root/usr/src/uts/common/io/zyd/zyd.h
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Copyright (c) 2008 by  Ben Taylor <bentaylor.solx86@gmail.com>
 * Copyright (c) 2007 by  Lukas Turek <turek@ksvi.mff.cuni.cz>
 * Copyright (c) 2007 by  Jiri Svoboda <jirik.svoboda@seznam.cz>
 * Copyright (c) 2007 by  Martin Krulis <martin.krulis@matfyz.cz>
 * Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr>
 * Copyright (c) 2006 by Florian Stoehr <ich@florian-stoehr.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef _ZYD_H
#define _ZYD_H

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/sysmacros.h>
#include <sys/net80211.h>

#define USBDRV_MAJOR_VER 2
#define USBDRV_MINOR_VER 0
#include <sys/usb/usba.h>
#include <sys/usb/usba/usba_types.h>

#define ZYD_DRV_NAME  "zyd"
#define ZYD_DRV_DESC  "Zydas ZD1211(B)"
#define ZYD_DRV_REV   "V1.1"

/* Return the number of fields of an array */
#define ZYD_ARRAY_LENGTH(arr) (sizeof (arr) / sizeof ((arr)[0]))

/*
 * Result type: all functions beginning with zyd_
 * should use this to indicate success or failure.
 * (except for public funcions, of course)
 *
 * Detecting error: always use (value != ZYD_SUCCESS)
 * Indicating error: return ZYD_FAILURE
 */
typedef enum {
        ZYD_SUCCESS,
        ZYD_FAILURE
} zyd_res;

/*
 * Chip revision ID
 */
typedef enum {
        ZYD_UNKNOWN,
        ZYD_ZD1211,
        ZYD_ZD1211B
} zyd_mac_rev_t;

/*
 * USB-safe mutual exclusion object.
 */
typedef struct {
        boolean_t initialized;  /* B_TRUE if properly initialized */
        boolean_t held;         /* B_TRUE if the object is held */
        kmutex_t lock;          /* serialize access */
        kcondvar_t wait;        /* for waiting on release */
} zyd_serial_t;

/*
 * Holds an ioread request status.
 */
struct zyd_ioread {
        volatile boolean_t pending;     /* ioread is in progress */
        volatile boolean_t done;        /* response has been received */
        volatile boolean_t exc;         /* an exception has occured */

        void *buffer;                   /* response buffer */
        int buf_len;                    /* buffer size (bytes) */
};

/*
 * USB state.
 */
struct zyd_usb {
        /* Copy of sc->dip */
        dev_info_t              *dip;

        /* Device configuration information */
        usb_client_dev_data_t   *cdata;

        boolean_t               connected;

        /* Communication pipe handles */
        usb_pipe_handle_t       pipe_data_in;
        usb_pipe_handle_t       pipe_data_out;
        usb_pipe_handle_t       pipe_cmd_in;
        usb_pipe_handle_t       pipe_cmd_out;

        /* Communication endpoint data (copied from descriptor tree) */
        usb_ep_data_t           ep_data_in;
        usb_ep_data_t           ep_data_out;
        usb_ep_data_t           ep_cmd_in;
        usb_ep_data_t           ep_cmd_out;

        /* Current ioread request (if any) */
        struct zyd_ioread       io_read;
};

struct zyd_softc;       /* forward declaration */

struct zyd_rf {
        /* RF methods */
        zyd_res         (*init)(struct zyd_rf *);
        zyd_res         (*switch_radio)(struct zyd_rf *, boolean_t);
        zyd_res         (*set_channel)(struct zyd_rf *, uint8_t);

        /* RF attributes */
        struct          zyd_softc *rf_sc;       /* back-pointer */
        int             width;
};

/*
 * per-instance soft-state structure
 */
struct zyd_softc {
        /* Serialize access to the soft_state/device */
        zyd_serial_t            serial;
        struct zyd_rf           sc_rf;

        dev_info_t              *dip;

        /* timeout for scanning */
        timeout_id_t            timeout_id;

        /* USB-specific data */
        struct zyd_usb          usb;

        /* Chip revision ZYD1211/ZYD1211B */
        zyd_mac_rev_t           mac_rev;

        /* MAC address */
        uint8_t                 macaddr[IEEE80211_ADDR_LEN];

        /* net80211 data */
        struct ieee80211com     ic;

        boolean_t               running;
        boolean_t               suspended;
        boolean_t               resched;
        uint8_t                 tx_queued;

        /* Data from EEPROM */
        uint16_t                fwbase;
        uint8_t                 regdomain;
        uint16_t                fw_rev;
        uint8_t                 rf_rev;
        uint8_t                 pa_rev;
        uint8_t                 fix_cr47;
        uint8_t                 fix_cr157;
        uint8_t                 pwr_cal[14];
        uint8_t                 pwr_int[14];
        uint8_t                 ofdm36_cal[14];
        uint8_t                 ofdm48_cal[14];
        uint8_t                 ofdm54_cal[14];

        /* kstats */
        uint32_t                tx_nobuf;
        uint32_t                rx_nobuf;
        uint32_t                tx_err;
        uint32_t                rx_err;

        /* net80211 original state change handler */
        int                     (*newstate)(ieee80211com_t *,
                                        enum ieee80211_state, int);
};

/* RF-config request */
struct zyd_rfwrite {
        uint16_t        code;
        uint16_t        width;
        uint16_t        bit[32];
};

/* 16-bit I/O register write request */
struct zyd_iowrite16 {
        uint16_t        reg;
        uint16_t        value;
};

#pragma pack(1)

/* Generic usb command to the ZD chip */
struct zyd_cmd {
        uint16_t        cmd_code;
        uint8_t         data[64];
};

/* ZD prepends this header to an incoming frame. */
struct zyd_plcphdr {
        uint8_t         signal;
        uint8_t         reserved[2];
        uint16_t        service;        /* unaligned! */
};

/* ZD appends this footer to an incoming frame. */
struct zyd_rx_stat {
        uint8_t rssi;
        uint8_t signal_cck;
        uint8_t signal_ofdm;
        uint8_t cipher;
        uint8_t flags;
};

/* this structure may be unaligned */
struct zyd_rx_desc {
#define ZYD_MAX_RXFRAMECNT 3
        uint16_t   len[ZYD_MAX_RXFRAMECNT];
        uint16_t   tag;
#define ZYD_TAG_MULTIFRAME 0x697e
};

/*
 * Prepended to the 802.11 frame when sending to data_out.
 */
struct zyd_tx_header {
        uint8_t rate_mod_flags;
        uint16_t frame_size;
        uint8_t type_flags;
        uint16_t packet_size;
        uint16_t frame_duration;
        uint8_t service;
        uint16_t next_frame_duration;
};

#pragma pack()

/*
 * Map USB id to 1211/1211B chip
 */
typedef struct zyd_usb_info {
        uint16_t        vendor_id;
        uint16_t        product_id;
        zyd_mac_rev_t   mac_rev;
} zyd_usb_info_t;

/*
 * Simple lock for callback-waiting. This lock should be used in situations when
 * one needs to wait for a callback function. It sipmply encapsulates one mutex
 * and one conditional variable.
 */
struct zyd_cb_lock {
        boolean_t done;
        kmutex_t mutex;
        kcondvar_t cv;
};

/* Bits for rate_mod_flags */
#define ZYD_TX_RMF_RATE(rmf)    ((rmf) & 0x0f)
#define ZYD_TX_RMF_OFDM         0x10
#define ZYD_TX_RMF_SH_PREAMBLE  0x20    /* CCK */
#define ZYD_TX_RMF_5GHZ         0x40    /* OFDM */

/* Bits for type_flags */
#define ZYD_TX_FLAG_BACKOFF     0x01
#define ZYD_TX_FLAG_MULTICAST   0x02
#define ZYD_TX_FLAG_TYPE(t)     (((t) & 0x3) << 2)
#define ZYD_TX_TYPE_DATA        0
#define ZYD_TX_TYPE_PS_POLL     1
#define ZYD_TX_TYPE_MGMT        2
#define ZYD_TX_TYPE_CTL         3

#define ZYD_TX_FLAG_WAKEUP      0x10
#define ZYD_TX_FLAG_RTS         0x20
#define ZYD_TX_FLAG_ENCRYPT     0x40
#define ZYD_TX_FLAG_CTS_TO_SELF 0x80

#define ZYD_TX_SERVICE_LENGTH_EXTENSION         0x80

#define ZYD_TX_LIST_COUNT       0x8
#define ZYD_RX_LIST_COUNT       0x8
#define ZYD_USB_REQ_COUNT       0x8

/*
 * Time in miliseconds to stay on one channel during scan.
 */
#define ZYD_DWELL_TIME 200000

#define ZYD_SER_SIG     B_TRUE
#define ZYD_NO_SIG      B_FALSE

/* Location in the endpoint descriptor tree used by the device */
#define ZYD_USB_CONFIG_NUMBER  1
#define ZYD_USB_IFACE_INDEX    0
#define ZYD_USB_ALT_IF_INDEX   0

#define ZYD_DBG_HW      (1<<0)
#define ZYD_DBG_FW      (1<<1)
#define ZYD_DBG_USB     (1<<2)
#define ZYD_DBG_TX      (1<<3)
#define ZYD_DBG_RX      (1<<4)
#define ZYD_DBG_SCAN    (1<<5)
#define ZYD_DBG_GLD     (1<<6)
#define ZYD_DBG_80211   (1<<7)
#define ZYD_DBG_RESUME  (1<<8)

#define ZYD_RX_BUF_SIZE (sizeof (struct zyd_rx_desc) + \
        ((IEEE80211_MAX_LEN + 3) & ~3) * ZYD_MAX_RXFRAMECNT)

/* quickly determine if a given rate is CCK or OFDM */
#define ZYD_RATE_IS_OFDM(rate)  ((rate) >= 12 && (rate) != 22)

/*
 * Calculate the byte offset of a struct member
 */
#define ZYD_IC_TO_SOFTC(ic)\
(\
        (struct zyd_softc *)(\
                (uintptr_t)(ic) - offsetof(struct zyd_softc, ic)\
)\
)

/*
 * The 'struct zyd_usb usb' is stored inside 'struct zyd_softc'.
 * Using the knowledge of the usb member position,
 * convert a pointer to 'usb' to a pointer to the zyd_softc.
 */
#define ZYD_USB_TO_SOFTC(usbp)\
(\
        (struct zyd_softc *)(\
                (uintptr_t)(usbp) - offsetof(struct zyd_softc, usb)\
)\
)

/* Debugging macros */
#ifdef DEBUG
#define ZYD_DEBUG(x)    zyd_dbg x
#else
#define ZYD_DEBUG(x)
#endif
#define ZYD_WARN        zyd_warn

extern void *zyd_ssp;

#ifdef DEBUG
extern uint32_t zyd_dbg_flags;
void    zyd_dbg(uint32_t dbg_mask, const char *fmt, ...);
#endif
void    zyd_warn(const char *fmt, ...);
/*
 * Functions needed for initializing radios and switching channels
 */
extern zyd_res  zyd_read32(struct zyd_softc *, uint16_t, uint32_t *);
extern zyd_res  zyd_write32(struct zyd_softc *, uint16_t, uint32_t);
extern zyd_res  zyd_read16(struct zyd_softc *, uint16_t, uint16_t *);
extern zyd_res  zyd_write16a(struct zyd_softc *, const struct zyd_iowrite16 *,
    int);
extern zyd_res  zyd_write16(struct zyd_softc *, uint16_t, uint16_t);
/*
 * Zydas's own USB-safe synchronization primitive. There are many USB API
 * functions which forbids that caller holds a mutex. So we're avoiding that
 * by using out own primitive (it consist of )
 */
void    zyd_serial_init(struct zyd_softc *sc);
zyd_res zyd_serial_enter(struct zyd_softc *sc, boolean_t wait_sig);
void    zyd_serial_exit(struct zyd_softc *sc);
void    zyd_serial_deinit(struct zyd_softc *sc);

void    zyd_cb_lock_init(struct zyd_cb_lock *lock);
void    zyd_cb_lock_destroy(struct zyd_cb_lock *lock);
zyd_res zyd_cb_lock_wait(struct zyd_cb_lock *lock, clock_t timeout);
void    zyd_cb_lock_signal(struct zyd_cb_lock *lock);

/* chipset specific routines */
void            zyd_hw_set_channel(struct zyd_softc *sc, uint8_t chan);
zyd_res         zyd_hw_init(struct zyd_softc *sc);
void            zyd_hw_deinit(struct zyd_softc *sc);
zyd_res         zyd_hw_start(struct zyd_softc *sc);
void            zyd_hw_stop(struct zyd_softc *sc);

/* USB specific routines */
zyd_res         zyd_usb_init(struct zyd_softc *sc);
void            zyd_usb_deinit(struct zyd_softc *sc);
zyd_res         zyd_usb_open_pipes(struct zyd_usb *uc);
void            zyd_usb_close_pipes(struct zyd_usb *uc);
zyd_res         zyd_usb_cmd_in_start_polling(struct zyd_usb *uc);
void            zyd_usb_cmd_in_stop_polling(struct zyd_usb *uc);
zyd_res         zyd_usb_data_in_enable(struct zyd_usb *uc);
void            zyd_usb_data_in_disable(struct zyd_usb *uc);
zyd_res         zyd_usb_cmd_send(struct zyd_usb *uc, uint16_t code,
                        const void *data, size_t len);
zyd_res         zyd_usb_ioread_req(struct zyd_usb *uc, const void *in_data,
                        size_t in_len, void *out_data, size_t out_len);
zyd_res         zyd_usb_send_packet(struct zyd_usb *uc, mblk_t *mp);
zyd_mac_rev_t   zyd_usb_mac_rev(uint16_t vendor, uint16_t product);
zyd_res         zyd_usb_loadfirmware(struct zyd_usb *uc, uint8_t *fw,
                        size_t size);

void    zyd_receive(struct zyd_softc *sc, const uint8_t *buf, uint16_t len);
int     zyd_resume(struct zyd_softc *sc);
int     zyd_suspend(struct zyd_softc *sc);

extern uint8_t  zd1211_firmware[];
extern size_t   zd1211_firmware_size;
extern uint8_t  zd1211b_firmware[];
extern size_t   zd1211b_firmware_size;

#ifdef __cplusplus
}
#endif

#endif /* _ZYD_H */