| /* |
| * 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 */ |