blob: f280aca161873653d28d33e8546d09ebb464105a [file] [log] [blame]
/*
* 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 */