| /* |
| Copyright 2004, 2005 Jean-Baptiste Note |
| |
| This file is part of prism54usb. |
| |
| prism54usb is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| prism54usb is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with prism54usb; if not, write to the Free Software Foundation, |
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
| */ |
| |
| #ifndef _HAVE_ISL_SM_H_ |
| #define _HAVE_ISL_SM_H_ |
| |
| #include <linux/netdevice.h> |
| #include <linux/wireless.h> |
| #include <linux/list.h> |
| #include <linux/firmware.h> |
| |
| #ifdef MADWIFI |
| #include <linux/version.h> |
| #include "net80211/if_media.h" |
| #include "net80211/ieee80211_var.h" |
| #else |
| #include <net/ieee80211softmac.h> |
| #define PCIUART 1 |
| #endif /* MADWIFI */ |
| |
| #include "islsm_protocol.h" |
| #include "islsm_alloc.h" |
| #include "islsm_uart.h" |
| #include "islsm_bra.h" |
| |
| enum islsm_state { |
| /* in this state we just received the plug event */ |
| ISLSM_PROBE = 0, |
| /* communication bridge is ok (usb, pci) */ |
| ISLSM_BRIDGE_OK, |
| /* rom is ok -- the uart protocol is ok */ |
| ISLSM_ROM_OK, |
| /* firmware is being uploaded */ |
| ISLSM_FW_UPLOAD, |
| /* freemac has been uploaded and is ok */ |
| ISLSM_FREEMAC, |
| /* softmac has been uploaded and is ok */ |
| ISLSM_SOFTMAC, |
| }; |
| |
| /* callback typedefs */ |
| typedef int (*islsm_tx_t) (struct sk_buff *); |
| |
| struct islsm { |
| |
| /* intersil-firmware specific state machine |
| * variables |
| */ |
| |
| /* islsm instances management */ |
| unsigned minor; |
| unsigned islsm_state; |
| |
| /* |
| * Parameters set by the BRA parsing |
| */ |
| /* LMAC type */ |
| enum islsm_fw_type fw_type; |
| /* LMAC memory mapping */ |
| /* Generic LMac framespace */ |
| uint32_t frame_mem_start; |
| uint32_t frame_mem_end; |
| /* specialized LMac framespace */ |
| /* reserved space for control frames */ |
| uint32_t txframe_mem_start; |
| uint32_t txframe_mem_end; |
| /* reserved space for rx frames */ |
| uint32_t rxframe_mem_start; |
| /* memory allocator proper */ |
| mem_descr_t memory; |
| |
| /* Rate index table */ |
| /* The frame format uses indexes in a table for specifying the |
| * sending rate of various frames. This rate table is present in |
| * the BRA. We mirror it here for use as a lookup table */ |
| char bra_rate_table[ISLSM_BRA_RATE_TABLE_SIZE]; |
| |
| /* |
| * Other parameters (sort this mess) |
| */ |
| |
| /* firmware name */ |
| #define ISLSM_FW_NAME_LEN 33 |
| char firmware_name[ISLSM_FW_NAME_LEN + 1]; |
| |
| /* LEDs state */ |
| unsigned led_mode; |
| unsigned led_setting; |
| |
| /* reserve this much space ahead of the skb for the needs of the |
| hardware tx queues */ |
| size_t device_tx_header_space; |
| /* sm_tx_header_space to be added */ |
| /* sm_rx_header_space to be added (for monitor mode) */ |
| |
| enum islsm_versions device_version; |
| /* signalled when particular states in the configuration have |
| been reached : init interrupt, then mgmt readback end */ |
| struct completion dev_init_comp; |
| int wait_flag; |
| |
| struct sm_p smpar; |
| short soft_rxfilter; |
| u8 filter_rateset[8]; |
| |
| /* |
| * Parameters and data set by parsing of the EEPROM contents |
| */ |
| |
| /* number of rates defined in the readback */ |
| uint8_t pa_points_per_curve; |
| |
| uint8_t *eeprom; |
| size_t eeprom_size; |
| size_t pda_offset; |
| size_t pda_length; |
| /* FIXME : these arrays are *huge* (255 elements) -- we should |
| * get rid of them */ |
| #ifdef MADWIFI |
| struct wlan_pda_output_limits_channel_rev0_s output_pwr_limits[IEEE80211_CHAN_MAX]; |
| struct fw_cal_data_sample finfo4[IEEE80211_CHAN_MAX][ISLSM_POINTS_PER_CURVE]; |
| struct wlan_pda_iq_autocal_s finfo6[IEEE80211_CHAN_MAX]; |
| #else /* MADWIFI */ |
| struct wlan_pda_output_limits_channel_rev0_s output_pwr_limits[ISLSM_NR_CHANNELS + 1]; |
| struct fw_cal_data_sample finfo4[ISLSM_NR_CHANNELS + 1][ISLSM_POINTS_PER_CURVE]; |
| struct wlan_pda_iq_autocal_s finfo6[ISLSM_NR_CHANNELS + 1]; |
| #endif |
| unsigned int last_chan; |
| |
| #ifdef MADWIFI |
| struct ieee80211com sc_ic; |
| struct ieee80211_beacon_offsets islsm_boff; |
| int (*ieee80211_newstate) (struct ieee80211com *, |
| enum ieee80211_state, |
| int); |
| struct timer_list scan_ch; /* AP scan timer */ |
| #endif /* MADWIFI */ |
| |
| /* struct timer_list stats_update; */ |
| struct net_device_stats statistics; |
| #ifdef CONFIG_WLAN_80211 |
| struct iw_statistics iwstatistics; |
| #endif /* CONFIG_WLAN_80211 */ |
| |
| /* device-specific state machine and callbacks |
| We handle three types of devices : |
| - usb first generation |
| - usb second generation |
| - pci devices |
| These hooks are in no mean set in stone; they are here for |
| experimentation and will give way to a cleaner approach once |
| we have a general picture of how things work. |
| */ |
| |
| /* boots the device */ |
| int (*isl_boot) (struct net_device *); |
| int (*isl_stop) (struct net_device *); |
| /* transmits the data in the skb to the lmac */ |
| islsm_tx_t isl_tx; |
| |
| /* device operations */ |
| int (*isl_romboot) (struct islsm *); |
| int (*isl_load_fw) (struct islsm *, |
| const struct firmware *); |
| |
| /* uart structure and callbacks */ |
| #ifdef PCIUART |
| uart_instance_t uart; |
| void (*uart_prot_init) (struct islsm *); |
| void (*uart_cts) (struct islsm *); |
| void (*uart_prot_exit) (struct islsm *); |
| #endif /* PCIUART */ |
| |
| /* low-level stuff */ |
| /* read and write from the pci side */ |
| uint32_t (*isl_read_pcireg) (struct islsm *, |
| uint32_t address); |
| void (*isl_write_pcireg) (struct islsm *, |
| uint32_t value, |
| uint32_t address); |
| uint32_t (*isl_read_devmem) (struct islsm *, |
| uint32_t address); |
| void (*isl_write_devmem) (struct islsm *, |
| uint32_t value, |
| uint32_t address); |
| |
| /* |
| * It should not be needed as we can fetch it with an offsetof |
| * macro. But this is safer in case allocations ever get out-of-line. |
| */ |
| struct net_device *netdev; |
| #ifndef MADWIFI |
| struct ieee80211_device *ieee; |
| struct ieee80211softmac_device *softmac; |
| #endif |
| |
| /* This is the structure below us, filled with p54u or islpci |
| * device reference */ |
| /* This must be the last item so that it points to the data |
| * allocated beyond this structure by alloc_islsm */ |
| u8 priv[]; |
| }; |
| |
| /* |
| * These functions are modelled after the netdev and ieee80211 ones. |
| * The train of structs for softmac: |
| * [netdev][ieee80211][ieee80211softmac][islsm][p54u] |
| */ |
| |
| #ifdef MADWIFI |
| #define NETDEV_OF_ISLSM(device) ((device)->netdev) |
| #define ISLSM_OF_NETDEV(device) ((struct islsm *) netdev_priv(device)) |
| #define SET_NETDEV(device,netdevice) ((device)->netdev = (netdevice)) |
| extern inline void *islsm_priv(struct net_device *dev) { |
| return ((struct islsm *)netdev_priv(dev))->priv; |
| } |
| |
| #else |
| #define NETDEV_OF_ISLSM(device) ((device)->netdev) |
| #define ISLSM_OF_NETDEV(device) ((struct islsm *) ieee80211softmac_priv(device)) |
| static inline void *islsm_priv(struct net_device *dev) { |
| return ((struct islsm *)ieee80211softmac_priv(dev))->priv; |
| } |
| |
| #endif /* MADWIFI */ |
| |
| /* |
| * Control block used by islsm |
| */ |
| struct islsm_cb { |
| struct islsm_alloc_cb alloc; |
| }; |
| |
| struct net_device *alloc_islsm(int sizeof_priv); |
| void free_islsm(struct net_device *dev); |
| int register_islsm(struct net_device *netdev); |
| void unregister_islsm(struct net_device *netdev); |
| |
| int islsm_mode_set_filter(struct net_device *netdev, int mode); |
| |
| extern int islsm_wait_timeout(struct islsm *islsm, |
| unsigned int delay); |
| |
| /* now the helper functions, for sending packets */ |
| int islsm_outofband_msg(struct islsm *islsm, |
| void *buf, size_t size); |
| |
| int islsm_stats_readback(struct islsm *islsm); |
| |
| void islsm_make_control_led(struct islsm *islsm, |
| char *buf, uint16_t mode, |
| uint16_t perm_setting, |
| uint16_t temp_setting, |
| uint16_t duration); |
| |
| void islsm_make_freequeue(struct islsm *islsm, |
| char *buf, uint8_t queue_id); |
| |
| int islsm_set_filter(struct islsm *islsm, |
| uint16_t filter_type, |
| const uint8_t *bssid, uint16_t magic2, |
| uint32_t magic3, uint16_t magic8, |
| uint16_t magic9); |
| |
| int islsm_freq_change(struct islsm *islsm, |
| uint16_t channel, uint16_t freq, |
| uint16_t magic1, uint16_t magic2); |
| |
| int islsm_data_tx(struct islsm *islsm, struct sm_tx_p *txp, |
| struct sk_buff *skb); |
| |
| int islsm_eeprom_readback(struct islsm *islsm); |
| |
| int islsm_led_perm(struct islsm *islsm, |
| uint16_t mode, uint16_t perm_setting); |
| int islsm_led_temp(struct islsm *islsm, |
| uint16_t temp_setting, unsigned ms); |
| |
| int islsm_ping_device(struct islsm *islsm, unsigned length); |
| |
| /* now the helper functions, for receiving packets */ |
| void islsm_data_input(struct sk_buff *skb); |
| void islsm_bootup_input(struct sk_buff *skb); |
| int islsm_parse_eeprom(struct islsm *islsm); |
| |
| int islsm_request_firmware(const struct firmware **fw, |
| struct islsm *device); |
| |
| /* protocol settings */ |
| void islsm_params_init(struct islsm *islsm); |
| |
| /* helper function to get rid of -- replace with a standard one from one |
| * of the stacks */ |
| static inline unsigned int |
| islsm_ref_to_chan(unsigned int ref) |
| { |
| /* FIXME : only works for the B/G band, we now need it for the A |
| band */ |
| #ifdef MADWIFI |
| return ieee80211_mhz2ieee(ref, IEEE80211_CHAN_2GHZ); |
| #else |
| /* kludgy as hell */ |
| unsigned int out; |
| #define ISLSM_REF_CHAN0 0x0967 |
| if (ref <= ISLSM_REF_CHAN0) { |
| printk(KERN_ERR |
| "%s: Problem requesting channel of ref %i : too small\n", |
| "islsm", ref); |
| return 0; |
| } |
| out = (ref - ISLSM_REF_CHAN0) / 5; |
| if (out > 14) { |
| if (ref == 2484) |
| return 14; |
| printk(KERN_ERR |
| "%s: Problem requesting channel of ref %i : " |
| "channel %i too big\n", "islsm", ref, out); |
| return 0; |
| } |
| return out; |
| #undef ISLSM_REF_CHAN0 |
| #endif /* MADWIFI */ |
| } |
| |
| int islsm_chan_to_freq(unsigned int chan); |
| unsigned int islsm_freq_to_chan(int freq); |
| |
| /* Helper function for the hardware stacks, to be used to free a |
| TX skb successfully transmitted to the umac */ |
| static inline void |
| islsm_txskb_free(struct sk_buff *skb) { |
| struct net_device *netdev = skb->dev; |
| struct islsm *islsm = ISLSM_OF_NETDEV(netdev); |
| uint32_t lmac_addr = LMAC_ADDR_OF_SKB(skb); |
| unsigned flags = LMAC_ALLOC_FLAGS(skb); |
| |
| if (flags & ISLSM_ALLOC_FREE_WHEN_SUBMITTED) |
| islsm_free(&islsm->memory, lmac_addr); |
| |
| dev_kfree_skb_irq(skb); |
| } |
| |
| #endif /* _HAVE_ISL_SM_H_ */ |