hostap: move under intersil vendor directory
Part of reorganising wireless drivers directory and Kconfig. Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
98
drivers/net/wireless/intersil/hostap/Kconfig
Normal file
98
drivers/net/wireless/intersil/hostap/Kconfig
Normal file
@@ -0,0 +1,98 @@
|
||||
config HOSTAP
|
||||
tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
|
||||
select WIRELESS_EXT
|
||||
select WEXT_SPY
|
||||
select WEXT_PRIV
|
||||
select CRYPTO
|
||||
select CRYPTO_ARC4
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_MICHAEL_MIC
|
||||
select CRYPTO_ECB
|
||||
select CRC32
|
||||
select LIB80211
|
||||
select LIB80211_CRYPT_WEP
|
||||
select LIB80211_CRYPT_TKIP
|
||||
select LIB80211_CRYPT_CCMP
|
||||
---help---
|
||||
Shared driver code for IEEE 802.11b wireless cards based on
|
||||
Intersil Prism2/2.5/3 chipset. This driver supports so called
|
||||
Host AP mode that allows the card to act as an IEEE 802.11
|
||||
access point.
|
||||
|
||||
See <http://hostap.epitest.fi/> for more information about the
|
||||
Host AP driver configuration and tools. This site includes
|
||||
information and tools (hostapd and wpa_supplicant) for WPA/WPA2
|
||||
support.
|
||||
|
||||
This option includes the base Host AP driver code that is shared by
|
||||
different hardware models. You will also need to enable support for
|
||||
PLX/PCI/CS version of the driver to actually use the driver.
|
||||
|
||||
The driver can be compiled as a module and it will be called
|
||||
hostap.
|
||||
|
||||
config HOSTAP_FIRMWARE
|
||||
bool "Support downloading firmware images with Host AP driver"
|
||||
depends on HOSTAP
|
||||
---help---
|
||||
Configure Host AP driver to include support for firmware image
|
||||
download. This option by itself only enables downloading to the
|
||||
volatile memory, i.e. the card RAM. This option is required to
|
||||
support cards that don't have firmware in flash, such as D-Link
|
||||
DWL-520 rev E and D-Link DWL-650 rev P.
|
||||
|
||||
Firmware image downloading needs a user space tool, prism2_srec.
|
||||
It is available from http://hostap.epitest.fi/.
|
||||
|
||||
config HOSTAP_FIRMWARE_NVRAM
|
||||
bool "Support for non-volatile firmware download"
|
||||
depends on HOSTAP_FIRMWARE
|
||||
---help---
|
||||
Allow Host AP driver to write firmware images to the non-volatile
|
||||
card memory, i.e. flash memory that survives power cycling.
|
||||
Enable this option if you want to be able to change card firmware
|
||||
permanently.
|
||||
|
||||
Firmware image downloading needs a user space tool, prism2_srec.
|
||||
It is available from http://hostap.epitest.fi/.
|
||||
|
||||
config HOSTAP_PLX
|
||||
tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors"
|
||||
depends on PCI && HOSTAP
|
||||
---help---
|
||||
Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based
|
||||
PCI adaptors.
|
||||
|
||||
"Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
|
||||
driver and its help text includes more information about the Host AP
|
||||
driver.
|
||||
|
||||
The driver can be compiled as a module and will be named
|
||||
hostap_plx.
|
||||
|
||||
config HOSTAP_PCI
|
||||
tristate "Host AP driver for Prism2.5 PCI adaptors"
|
||||
depends on PCI && HOSTAP
|
||||
---help---
|
||||
Host AP driver's version for Prism2.5 PCI adaptors.
|
||||
|
||||
"Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
|
||||
driver and its help text includes more information about the Host AP
|
||||
driver.
|
||||
|
||||
The driver can be compiled as a module and will be named
|
||||
hostap_pci.
|
||||
|
||||
config HOSTAP_CS
|
||||
tristate "Host AP driver for Prism2/2.5/3 PC Cards"
|
||||
depends on PCMCIA && HOSTAP
|
||||
---help---
|
||||
Host AP driver's version for Prism2/2.5/3 PC Cards.
|
||||
|
||||
"Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
|
||||
driver and its help text includes more information about the Host AP
|
||||
driver.
|
||||
|
||||
The driver can be compiled as a module and will be named
|
||||
hostap_cs.
|
7
drivers/net/wireless/intersil/hostap/Makefile
Normal file
7
drivers/net/wireless/intersil/hostap/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \
|
||||
hostap_ioctl.o hostap_main.o hostap_proc.o
|
||||
obj-$(CONFIG_HOSTAP) += hostap.o
|
||||
|
||||
obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
|
||||
obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o
|
||||
obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o
|
95
drivers/net/wireless/intersil/hostap/hostap.h
Normal file
95
drivers/net/wireless/intersil/hostap/hostap.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef HOSTAP_H
|
||||
#define HOSTAP_H
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "hostap_wlan.h"
|
||||
#include "hostap_ap.h"
|
||||
|
||||
static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
|
||||
2447, 2452, 2457, 2462, 2467, 2472, 2484 };
|
||||
#define FREQ_COUNT ARRAY_SIZE(freq_list)
|
||||
|
||||
/* hostap.c */
|
||||
|
||||
extern struct proc_dir_entry *hostap_proc;
|
||||
|
||||
u16 hostap_tx_callback_register(local_info_t *local,
|
||||
void (*func)(struct sk_buff *, int ok, void *),
|
||||
void *data);
|
||||
int hostap_tx_callback_unregister(local_info_t *local, u16 idx);
|
||||
int hostap_set_word(struct net_device *dev, int rid, u16 val);
|
||||
int hostap_set_string(struct net_device *dev, int rid, const char *val);
|
||||
u16 hostap_get_porttype(local_info_t *local);
|
||||
int hostap_set_encryption(local_info_t *local);
|
||||
int hostap_set_antsel(local_info_t *local);
|
||||
int hostap_set_roaming(local_info_t *local);
|
||||
int hostap_set_auth_algs(local_info_t *local);
|
||||
void hostap_dump_rx_header(const char *name,
|
||||
const struct hfa384x_rx_frame *rx);
|
||||
void hostap_dump_tx_header(const char *name,
|
||||
const struct hfa384x_tx_frame *tx);
|
||||
extern const struct header_ops hostap_80211_ops;
|
||||
int hostap_80211_get_hdrlen(__le16 fc);
|
||||
struct net_device_stats *hostap_get_stats(struct net_device *dev);
|
||||
void hostap_setup_dev(struct net_device *dev, local_info_t *local,
|
||||
int type);
|
||||
void hostap_set_multicast_list_queue(struct work_struct *work);
|
||||
int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
|
||||
int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
|
||||
void hostap_cleanup(local_info_t *local);
|
||||
void hostap_cleanup_handler(void *data);
|
||||
struct net_device * hostap_add_interface(struct local_info *local,
|
||||
int type, int rtnl_locked,
|
||||
const char *prefix, const char *name);
|
||||
void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
|
||||
int remove_from_list);
|
||||
int prism2_update_comms_qual(struct net_device *dev);
|
||||
int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
|
||||
u8 *body, size_t bodylen);
|
||||
int prism2_sta_deauth(local_info_t *local, u16 reason);
|
||||
int prism2_wds_add(local_info_t *local, u8 *remote_addr,
|
||||
int rtnl_locked);
|
||||
int prism2_wds_del(local_info_t *local, u8 *remote_addr,
|
||||
int rtnl_locked, int do_not_remove);
|
||||
|
||||
|
||||
/* hostap_ap.c */
|
||||
|
||||
int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac);
|
||||
int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac);
|
||||
void ap_control_flush_macs(struct mac_restrictions *mac_restrictions);
|
||||
int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac);
|
||||
void ap_control_kickall(struct ap_data *ap);
|
||||
void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
|
||||
struct lib80211_crypt_data ***crypt);
|
||||
int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
|
||||
struct iw_quality qual[], int buf_size,
|
||||
int aplist);
|
||||
int prism2_ap_translate_scan(struct net_device *dev,
|
||||
struct iw_request_info *info, char *buffer);
|
||||
int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);
|
||||
|
||||
|
||||
/* hostap_proc.c */
|
||||
|
||||
void hostap_init_proc(local_info_t *local);
|
||||
void hostap_remove_proc(local_info_t *local);
|
||||
|
||||
|
||||
/* hostap_info.c */
|
||||
|
||||
void hostap_info_init(local_info_t *local);
|
||||
void hostap_info_process(local_info_t *local, struct sk_buff *skb);
|
||||
|
||||
|
||||
/* hostap_ioctl.c */
|
||||
|
||||
extern const struct iw_handler_def hostap_iw_handler_def;
|
||||
extern const struct ethtool_ops prism2_ethtool_ops;
|
||||
|
||||
int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||
|
||||
|
||||
#endif /* HOSTAP_H */
|
96
drivers/net/wireless/intersil/hostap/hostap_80211.h
Normal file
96
drivers/net/wireless/intersil/hostap/hostap_80211.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef HOSTAP_80211_H
|
||||
#define HOSTAP_80211_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
struct hostap_ieee80211_mgmt {
|
||||
__le16 frame_control;
|
||||
__le16 duration;
|
||||
u8 da[6];
|
||||
u8 sa[6];
|
||||
u8 bssid[6];
|
||||
__le16 seq_ctrl;
|
||||
union {
|
||||
struct {
|
||||
__le16 auth_alg;
|
||||
__le16 auth_transaction;
|
||||
__le16 status_code;
|
||||
/* possibly followed by Challenge text */
|
||||
u8 variable[0];
|
||||
} __packed auth;
|
||||
struct {
|
||||
__le16 reason_code;
|
||||
} __packed deauth;
|
||||
struct {
|
||||
__le16 capab_info;
|
||||
__le16 listen_interval;
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} __packed assoc_req;
|
||||
struct {
|
||||
__le16 capab_info;
|
||||
__le16 status_code;
|
||||
__le16 aid;
|
||||
/* followed by Supported rates */
|
||||
u8 variable[0];
|
||||
} __packed assoc_resp, reassoc_resp;
|
||||
struct {
|
||||
__le16 capab_info;
|
||||
__le16 listen_interval;
|
||||
u8 current_ap[6];
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} __packed reassoc_req;
|
||||
struct {
|
||||
__le16 reason_code;
|
||||
} __packed disassoc;
|
||||
struct {
|
||||
} __packed probe_req;
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
__le16 beacon_int;
|
||||
__le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params, TIM */
|
||||
u8 variable[0];
|
||||
} __packed beacon, probe_resp;
|
||||
} u;
|
||||
} __packed;
|
||||
|
||||
|
||||
#define IEEE80211_MGMT_HDR_LEN 24
|
||||
#define IEEE80211_DATA_HDR3_LEN 24
|
||||
#define IEEE80211_DATA_HDR4_LEN 30
|
||||
|
||||
|
||||
struct hostap_80211_rx_status {
|
||||
u32 mac_time;
|
||||
u8 signal;
|
||||
u8 noise;
|
||||
u16 rate; /* in 100 kbps */
|
||||
};
|
||||
|
||||
/* prism2_rx_80211 'type' argument */
|
||||
enum {
|
||||
PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
|
||||
PRISM2_RX_NULLFUNC_ACK
|
||||
};
|
||||
|
||||
int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats, int type);
|
||||
void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
|
||||
void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
|
||||
netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
|
||||
#endif /* HOSTAP_80211_H */
|
1117
drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
Normal file
1117
drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
Normal file
File diff suppressed because it is too large
Load Diff
553
drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
Normal file
553
drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
Normal file
@@ -0,0 +1,553 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "hostap_80211.h"
|
||||
#include "hostap_common.h"
|
||||
#include "hostap_wlan.h"
|
||||
#include "hostap.h"
|
||||
#include "hostap_ap.h"
|
||||
|
||||
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||
static unsigned char rfc1042_header[] =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
|
||||
static unsigned char bridge_tunnel_header[] =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
||||
/* No encapsulation header if EtherType < 0x600 (=length) */
|
||||
|
||||
void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
u16 fc;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
|
||||
printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
|
||||
name, skb->len, jiffies);
|
||||
|
||||
if (skb->len < 2)
|
||||
return;
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
|
||||
fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
|
||||
(fc & IEEE80211_FCTL_STYPE) >> 4,
|
||||
fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
|
||||
fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
|
||||
|
||||
if (skb->len < IEEE80211_DATA_HDR3_LEN) {
|
||||
printk("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
|
||||
le16_to_cpu(hdr->seq_ctrl));
|
||||
|
||||
printk(KERN_DEBUG " A1=%pM", hdr->addr1);
|
||||
printk(" A2=%pM", hdr->addr2);
|
||||
printk(" A3=%pM", hdr->addr3);
|
||||
if (skb->len >= 30)
|
||||
printk(" A4=%pM", hdr->addr4);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
|
||||
/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
|
||||
* Convert Ethernet header into a suitable IEEE 802.11 header depending on
|
||||
* device configuration. */
|
||||
netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
int need_headroom, need_tailroom = 0;
|
||||
struct ieee80211_hdr hdr;
|
||||
u16 fc, ethertype = 0;
|
||||
enum {
|
||||
WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
|
||||
} use_wds = WDS_NO;
|
||||
u8 *encaps_data;
|
||||
int hdr_len, encaps_len, skip_header_bytes;
|
||||
int to_assoc_ap = 0;
|
||||
struct hostap_skb_tx_data *meta;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
if (skb->len < ETH_HLEN) {
|
||||
printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
|
||||
"(len=%d)\n", dev->name, skb->len);
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
if (local->ddev != dev) {
|
||||
use_wds = (local->iw_mode == IW_MODE_MASTER &&
|
||||
!(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ?
|
||||
WDS_OWN_FRAME : WDS_COMPLIANT_FRAME;
|
||||
if (dev == local->stadev) {
|
||||
to_assoc_ap = 1;
|
||||
use_wds = WDS_NO;
|
||||
} else if (dev == local->apdev) {
|
||||
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
|
||||
"AP device with Ethernet net dev\n", dev->name);
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
} else {
|
||||
if (local->iw_mode == IW_MODE_REPEAT) {
|
||||
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
|
||||
"non-WDS link in Repeater mode\n", dev->name);
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
} else if (local->iw_mode == IW_MODE_INFRA &&
|
||||
(local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
|
||||
!ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) {
|
||||
/* AP client mode: send frames with foreign src addr
|
||||
* using 4-addr WDS frames */
|
||||
use_wds = WDS_COMPLIANT_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
/* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload
|
||||
* ==>
|
||||
* Prism2 TX frame with 802.11 header:
|
||||
* txdesc (address order depending on used mode; includes dst_addr and
|
||||
* src_addr), possible encapsulation (RFC1042/Bridge-Tunnel;
|
||||
* proto[2], payload {, possible addr4[6]} */
|
||||
|
||||
ethertype = (skb->data[12] << 8) | skb->data[13];
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
|
||||
/* Length of data after IEEE 802.11 header */
|
||||
encaps_data = NULL;
|
||||
encaps_len = 0;
|
||||
skip_header_bytes = ETH_HLEN;
|
||||
if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
|
||||
encaps_data = bridge_tunnel_header;
|
||||
encaps_len = sizeof(bridge_tunnel_header);
|
||||
skip_header_bytes -= 2;
|
||||
} else if (ethertype >= 0x600) {
|
||||
encaps_data = rfc1042_header;
|
||||
encaps_len = sizeof(rfc1042_header);
|
||||
skip_header_bytes -= 2;
|
||||
}
|
||||
|
||||
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
|
||||
hdr_len = IEEE80211_DATA_HDR3_LEN;
|
||||
|
||||
if (use_wds != WDS_NO) {
|
||||
/* Note! Prism2 station firmware has problems with sending real
|
||||
* 802.11 frames with four addresses; until these problems can
|
||||
* be fixed or worked around, 4-addr frames needed for WDS are
|
||||
* using incompatible format: FromDS flag is not set and the
|
||||
* fourth address is added after the frame payload; it is
|
||||
* assumed, that the receiving station knows how to handle this
|
||||
* frame format */
|
||||
|
||||
if (use_wds == WDS_COMPLIANT_FRAME) {
|
||||
fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
|
||||
/* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
|
||||
* Addr4 = SA */
|
||||
skb_copy_from_linear_data_offset(skb, ETH_ALEN,
|
||||
&hdr.addr4, ETH_ALEN);
|
||||
hdr_len += ETH_ALEN;
|
||||
} else {
|
||||
/* bogus 4-addr format to workaround Prism2 station
|
||||
* f/w bug */
|
||||
fc |= IEEE80211_FCTL_TODS;
|
||||
/* From DS: Addr1 = DA (used as RA),
|
||||
* Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),
|
||||
*/
|
||||
|
||||
/* SA from skb->data + ETH_ALEN will be added after
|
||||
* frame payload; use hdr.addr4 as a temporary buffer
|
||||
*/
|
||||
skb_copy_from_linear_data_offset(skb, ETH_ALEN,
|
||||
&hdr.addr4, ETH_ALEN);
|
||||
need_tailroom += ETH_ALEN;
|
||||
}
|
||||
|
||||
/* send broadcast and multicast frames to broadcast RA, if
|
||||
* configured; otherwise, use unicast RA of the WDS link */
|
||||
if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) &&
|
||||
is_multicast_ether_addr(skb->data))
|
||||
eth_broadcast_addr(hdr.addr1);
|
||||
else if (iface->type == HOSTAP_INTERFACE_WDS)
|
||||
memcpy(&hdr.addr1, iface->u.wds.remote_addr,
|
||||
ETH_ALEN);
|
||||
else
|
||||
memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
|
||||
memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
|
||||
skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
|
||||
} else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
|
||||
fc |= IEEE80211_FCTL_FROMDS;
|
||||
/* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
|
||||
skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
|
||||
memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
|
||||
skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3,
|
||||
ETH_ALEN);
|
||||
} else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
|
||||
fc |= IEEE80211_FCTL_TODS;
|
||||
/* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
|
||||
memcpy(&hdr.addr1, to_assoc_ap ?
|
||||
local->assoc_ap_addr : local->bssid, ETH_ALEN);
|
||||
skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
|
||||
ETH_ALEN);
|
||||
skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
|
||||
} else if (local->iw_mode == IW_MODE_ADHOC) {
|
||||
/* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
|
||||
skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
|
||||
skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
|
||||
ETH_ALEN);
|
||||
memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
hdr.frame_control = cpu_to_le16(fc);
|
||||
|
||||
skb_pull(skb, skip_header_bytes);
|
||||
need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
|
||||
if (skb_tailroom(skb) < need_tailroom) {
|
||||
skb = skb_unshare(skb, GFP_ATOMIC);
|
||||
if (skb == NULL) {
|
||||
iface->stats.tx_dropped++;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
if (pskb_expand_head(skb, need_headroom, need_tailroom,
|
||||
GFP_ATOMIC)) {
|
||||
kfree_skb(skb);
|
||||
iface->stats.tx_dropped++;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
} else if (skb_headroom(skb) < need_headroom) {
|
||||
struct sk_buff *tmp = skb;
|
||||
skb = skb_realloc_headroom(skb, need_headroom);
|
||||
kfree_skb(tmp);
|
||||
if (skb == NULL) {
|
||||
iface->stats.tx_dropped++;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
} else {
|
||||
skb = skb_unshare(skb, GFP_ATOMIC);
|
||||
if (skb == NULL) {
|
||||
iface->stats.tx_dropped++;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (encaps_data)
|
||||
memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
|
||||
memcpy(skb_push(skb, hdr_len), &hdr, hdr_len);
|
||||
if (use_wds == WDS_OWN_FRAME) {
|
||||
memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN);
|
||||
}
|
||||
|
||||
iface->stats.tx_packets++;
|
||||
iface->stats.tx_bytes += skb->len;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
meta = (struct hostap_skb_tx_data *) skb->cb;
|
||||
memset(meta, 0, sizeof(*meta));
|
||||
meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
|
||||
if (use_wds)
|
||||
meta->flags |= HOSTAP_TX_FLAGS_WDS;
|
||||
meta->ethertype = ethertype;
|
||||
meta->iface = iface;
|
||||
|
||||
/* Send IEEE 802.11 encapsulated frame using the master radio device */
|
||||
skb->dev = local->dev;
|
||||
dev_queue_xmit(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* hard_start_xmit function for hostapd wlan#ap interfaces */
|
||||
netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
struct hostap_skb_tx_data *meta;
|
||||
struct ieee80211_hdr *hdr;
|
||||
u16 fc;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
if (skb->len < 10) {
|
||||
printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
|
||||
"(len=%d)\n", dev->name, skb->len);
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
iface->stats.tx_packets++;
|
||||
iface->stats.tx_bytes += skb->len;
|
||||
|
||||
meta = (struct hostap_skb_tx_data *) skb->cb;
|
||||
memset(meta, 0, sizeof(*meta));
|
||||
meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
|
||||
meta->iface = iface;
|
||||
|
||||
if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
(fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) {
|
||||
u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
|
||||
sizeof(rfc1042_header)];
|
||||
meta->ethertype = (pos[0] << 8) | pos[1];
|
||||
}
|
||||
}
|
||||
|
||||
/* Send IEEE 802.11 encapsulated frame using the master radio device */
|
||||
skb->dev = local->dev;
|
||||
dev_queue_xmit(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Called only from software IRQ */
|
||||
static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
|
||||
struct lib80211_crypt_data *crypt)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int prefix_len, postfix_len, hdr_len, res;
|
||||
|
||||
iface = netdev_priv(skb->dev);
|
||||
local = iface->local;
|
||||
|
||||
if (skb->len < IEEE80211_DATA_HDR3_LEN) {
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (local->tkip_countermeasures &&
|
||||
strcmp(crypt->ops->name, "TKIP") == 0) {
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
|
||||
"TX packet to %pM\n",
|
||||
local->dev->name, hdr->addr1);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
skb = skb_unshare(skb, GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
return NULL;
|
||||
|
||||
prefix_len = crypt->ops->extra_mpdu_prefix_len +
|
||||
crypt->ops->extra_msdu_prefix_len;
|
||||
postfix_len = crypt->ops->extra_mpdu_postfix_len +
|
||||
crypt->ops->extra_msdu_postfix_len;
|
||||
if ((skb_headroom(skb) < prefix_len ||
|
||||
skb_tailroom(skb) < postfix_len) &&
|
||||
pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) {
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdr_len = hostap_80211_get_hdrlen(hdr->frame_control);
|
||||
|
||||
/* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
|
||||
* call both MSDU and MPDU encryption functions from here. */
|
||||
atomic_inc(&crypt->refcnt);
|
||||
res = 0;
|
||||
if (crypt->ops->encrypt_msdu)
|
||||
res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv);
|
||||
if (res == 0 && crypt->ops->encrypt_mpdu)
|
||||
res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv);
|
||||
atomic_dec(&crypt->refcnt);
|
||||
if (res < 0) {
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
||||
/* hard_start_xmit function for master radio interface wifi#.
|
||||
* AP processing (TX rate control, power save buffering, etc.).
|
||||
* Use hardware TX function to send the frame. */
|
||||
netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
netdev_tx_t ret = NETDEV_TX_BUSY;
|
||||
u16 fc;
|
||||
struct hostap_tx_data tx;
|
||||
ap_tx_ret tx_ret;
|
||||
struct hostap_skb_tx_data *meta;
|
||||
int no_encrypt = 0;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
tx.skb = skb;
|
||||
tx.sta_ptr = NULL;
|
||||
|
||||
meta = (struct hostap_skb_tx_data *) skb->cb;
|
||||
if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
|
||||
printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
|
||||
"expected 0x%08x)\n",
|
||||
dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
|
||||
ret = NETDEV_TX_OK;
|
||||
iface->stats.tx_dropped++;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (local->host_encrypt) {
|
||||
/* Set crypt to default algorithm and key; will be replaced in
|
||||
* AP code if STA has own alg/key */
|
||||
tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx];
|
||||
tx.host_encrypt = 1;
|
||||
} else {
|
||||
tx.crypt = NULL;
|
||||
tx.host_encrypt = 0;
|
||||
}
|
||||
|
||||
if (skb->len < 24) {
|
||||
printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
|
||||
"(len=%d)\n", dev->name, skb->len);
|
||||
ret = NETDEV_TX_OK;
|
||||
iface->stats.tx_dropped++;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* FIX (?):
|
||||
* Wi-Fi 802.11b test plan suggests that AP should ignore power save
|
||||
* bit in authentication and (re)association frames and assume tha
|
||||
* STA remains awake for the response. */
|
||||
tx_ret = hostap_handle_sta_tx(local, &tx);
|
||||
skb = tx.skb;
|
||||
meta = (struct hostap_skb_tx_data *) skb->cb;
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
switch (tx_ret) {
|
||||
case AP_TX_CONTINUE:
|
||||
break;
|
||||
case AP_TX_CONTINUE_NOT_AUTHORIZED:
|
||||
if (local->ieee_802_1x &&
|
||||
ieee80211_is_data(hdr->frame_control) &&
|
||||
meta->ethertype != ETH_P_PAE &&
|
||||
!(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
|
||||
printk(KERN_DEBUG "%s: dropped frame to unauthorized "
|
||||
"port (IEEE 802.1X): ethertype=0x%04x\n",
|
||||
dev->name, meta->ethertype);
|
||||
hostap_dump_tx_80211(dev->name, skb);
|
||||
|
||||
ret = NETDEV_TX_OK; /* drop packet */
|
||||
iface->stats.tx_dropped++;
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case AP_TX_DROP:
|
||||
ret = NETDEV_TX_OK; /* drop packet */
|
||||
iface->stats.tx_dropped++;
|
||||
goto fail;
|
||||
case AP_TX_RETRY:
|
||||
goto fail;
|
||||
case AP_TX_BUFFERED:
|
||||
/* do not free skb here, it will be freed when the
|
||||
* buffered frame is sent/timed out */
|
||||
ret = NETDEV_TX_OK;
|
||||
goto tx_exit;
|
||||
}
|
||||
|
||||
/* Request TX callback if protocol version is 2 in 802.11 header;
|
||||
* this version 2 is a special case used between hostapd and kernel
|
||||
* driver */
|
||||
if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&
|
||||
local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {
|
||||
meta->tx_cb_idx = local->ap->tx_callback_idx;
|
||||
|
||||
/* remove special version from the frame header */
|
||||
fc &= ~IEEE80211_FCTL_VERS;
|
||||
hdr->frame_control = cpu_to_le16(fc);
|
||||
}
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control)) {
|
||||
no_encrypt = 1;
|
||||
tx.crypt = NULL;
|
||||
}
|
||||
|
||||
if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
|
||||
!(fc & IEEE80211_FCTL_PROTECTED)) {
|
||||
no_encrypt = 1;
|
||||
PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
|
||||
"unencrypted EAPOL frame\n", dev->name);
|
||||
tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */
|
||||
}
|
||||
|
||||
if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
|
||||
tx.crypt = NULL;
|
||||
else if ((tx.crypt ||
|
||||
local->crypt_info.crypt[local->crypt_info.tx_keyidx]) &&
|
||||
!no_encrypt) {
|
||||
/* Add ISWEP flag both for firmware and host based encryption
|
||||
*/
|
||||
fc |= IEEE80211_FCTL_PROTECTED;
|
||||
hdr->frame_control = cpu_to_le16(fc);
|
||||
} else if (local->drop_unencrypted &&
|
||||
ieee80211_is_data(hdr->frame_control) &&
|
||||
meta->ethertype != ETH_P_PAE) {
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "%s: dropped unencrypted TX data "
|
||||
"frame (drop_unencrypted=1)\n", dev->name);
|
||||
}
|
||||
iface->stats.tx_dropped++;
|
||||
ret = NETDEV_TX_OK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (tx.crypt) {
|
||||
skb = hostap_tx_encrypt(skb, tx.crypt);
|
||||
if (skb == NULL) {
|
||||
printk(KERN_DEBUG "%s: TX - encryption failed\n",
|
||||
dev->name);
|
||||
ret = NETDEV_TX_OK;
|
||||
goto fail;
|
||||
}
|
||||
meta = (struct hostap_skb_tx_data *) skb->cb;
|
||||
if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
|
||||
printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
|
||||
"expected 0x%08x) after hostap_tx_encrypt\n",
|
||||
dev->name, meta->magic,
|
||||
HOSTAP_SKB_TX_DATA_MAGIC);
|
||||
ret = NETDEV_TX_OK;
|
||||
iface->stats.tx_dropped++;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (local->func->tx == NULL || local->func->tx(skb, dev)) {
|
||||
ret = NETDEV_TX_OK;
|
||||
iface->stats.tx_dropped++;
|
||||
} else {
|
||||
ret = NETDEV_TX_OK;
|
||||
iface->stats.tx_packets++;
|
||||
iface->stats.tx_bytes += skb->len;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (ret == NETDEV_TX_OK && skb)
|
||||
dev_kfree_skb(skb);
|
||||
tx_exit:
|
||||
if (tx.sta_ptr)
|
||||
hostap_handle_sta_release(tx.sta_ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(hostap_master_start_xmit);
|
3339
drivers/net/wireless/intersil/hostap/hostap_ap.c
Normal file
3339
drivers/net/wireless/intersil/hostap/hostap_ap.c
Normal file
File diff suppressed because it is too large
Load Diff
263
drivers/net/wireless/intersil/hostap/hostap_ap.h
Normal file
263
drivers/net/wireless/intersil/hostap/hostap_ap.h
Normal file
@@ -0,0 +1,263 @@
|
||||
#ifndef HOSTAP_AP_H
|
||||
#define HOSTAP_AP_H
|
||||
|
||||
#include "hostap_80211.h"
|
||||
|
||||
/* AP data structures for STAs */
|
||||
|
||||
/* maximum number of frames to buffer per STA */
|
||||
#define STA_MAX_TX_BUFFER 32
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
#define WLAN_STA_ASSOC BIT(1)
|
||||
#define WLAN_STA_PS BIT(2)
|
||||
#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
|
||||
#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
|
||||
#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
|
||||
* controlling whether STA is authorized to
|
||||
* send and receive non-IEEE 802.1X frames
|
||||
*/
|
||||
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
|
||||
|
||||
#define WLAN_RATE_1M BIT(0)
|
||||
#define WLAN_RATE_2M BIT(1)
|
||||
#define WLAN_RATE_5M5 BIT(2)
|
||||
#define WLAN_RATE_11M BIT(3)
|
||||
#define WLAN_RATE_COUNT 4
|
||||
|
||||
/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
|
||||
* but some pre-standard IEEE 802.11g products use longer elements. */
|
||||
#define WLAN_SUPP_RATES_MAX 32
|
||||
|
||||
/* Try to increase TX rate after # successfully sent consecutive packets */
|
||||
#define WLAN_RATE_UPDATE_COUNT 50
|
||||
|
||||
/* Decrease TX rate after # consecutive dropped packets */
|
||||
#define WLAN_RATE_DECREASE_THRESHOLD 2
|
||||
|
||||
struct sta_info {
|
||||
struct list_head list;
|
||||
struct sta_info *hnext; /* next entry in hash table list */
|
||||
atomic_t users; /* number of users (do not remove if > 0) */
|
||||
struct proc_dir_entry *proc;
|
||||
|
||||
u8 addr[6];
|
||||
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
|
||||
u32 flags;
|
||||
u16 capability;
|
||||
u16 listen_interval; /* or beacon_int for APs */
|
||||
u8 supported_rates[WLAN_SUPP_RATES_MAX];
|
||||
|
||||
unsigned long last_auth;
|
||||
unsigned long last_assoc;
|
||||
unsigned long last_rx;
|
||||
unsigned long last_tx;
|
||||
unsigned long rx_packets, tx_packets;
|
||||
unsigned long rx_bytes, tx_bytes;
|
||||
struct sk_buff_head tx_buf;
|
||||
/* FIX: timeout buffers with an expiry time somehow derived from
|
||||
* listen_interval */
|
||||
|
||||
s8 last_rx_silence; /* Noise in dBm */
|
||||
s8 last_rx_signal; /* Signal strength in dBm */
|
||||
u8 last_rx_rate; /* TX rate in 0.1 Mbps */
|
||||
u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */
|
||||
|
||||
u8 tx_supp_rates; /* bit field of supported TX rates */
|
||||
u8 tx_rate; /* current TX rate (in 0.1 Mbps) */
|
||||
u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */
|
||||
u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */
|
||||
u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */
|
||||
u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate)
|
||||
*/
|
||||
u32 tx_since_last_failure;
|
||||
u32 tx_consecutive_exc;
|
||||
|
||||
struct lib80211_crypt_data *crypt;
|
||||
|
||||
int ap; /* whether this station is an AP */
|
||||
|
||||
local_info_t *local;
|
||||
|
||||
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
|
||||
union {
|
||||
struct {
|
||||
char *challenge; /* shared key authentication
|
||||
* challenge */
|
||||
} sta;
|
||||
struct {
|
||||
int ssid_len;
|
||||
unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */
|
||||
int channel;
|
||||
unsigned long last_beacon; /* last RX beacon time */
|
||||
} ap;
|
||||
} u;
|
||||
|
||||
struct timer_list timer;
|
||||
enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next;
|
||||
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
};
|
||||
|
||||
|
||||
#define MAX_STA_COUNT 1024
|
||||
|
||||
/* Maximum number of AIDs to use for STAs; must be 2007 or lower
|
||||
* (8802.11 limitation) */
|
||||
#define MAX_AID_TABLE_SIZE 128
|
||||
|
||||
#define STA_HASH_SIZE 256
|
||||
#define STA_HASH(sta) (sta[5])
|
||||
|
||||
|
||||
/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC
|
||||
* has passed since last received frame from the station, a nullfunc data
|
||||
* frame is sent to the station. If this frame is not acknowledged and no other
|
||||
* frames have been received, the station will be disassociated after
|
||||
* AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after
|
||||
* AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with
|
||||
* max inactivity timer. */
|
||||
#define AP_MAX_INACTIVITY_SEC (5 * 60)
|
||||
#define AP_DISASSOC_DELAY (HZ)
|
||||
#define AP_DEAUTH_DELAY (HZ)
|
||||
|
||||
/* ap_policy: whether to accept frames to/from other APs/IBSS */
|
||||
typedef enum {
|
||||
AP_OTHER_AP_SKIP_ALL = 0,
|
||||
AP_OTHER_AP_SAME_SSID = 1,
|
||||
AP_OTHER_AP_ALL = 2,
|
||||
AP_OTHER_AP_EVEN_IBSS = 3
|
||||
} ap_policy_enum;
|
||||
|
||||
#define PRISM2_AUTH_OPEN BIT(0)
|
||||
#define PRISM2_AUTH_SHARED_KEY BIT(1)
|
||||
|
||||
|
||||
/* MAC address-based restrictions */
|
||||
struct mac_entry {
|
||||
struct list_head list;
|
||||
u8 addr[6];
|
||||
};
|
||||
|
||||
struct mac_restrictions {
|
||||
enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy;
|
||||
unsigned int entries;
|
||||
struct list_head mac_list;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
||||
struct add_sta_proc_data {
|
||||
u8 addr[ETH_ALEN];
|
||||
struct add_sta_proc_data *next;
|
||||
};
|
||||
|
||||
|
||||
typedef enum { WDS_ADD, WDS_DEL } wds_oper_type;
|
||||
struct wds_oper_data {
|
||||
wds_oper_type type;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct wds_oper_data *next;
|
||||
};
|
||||
|
||||
|
||||
struct ap_data {
|
||||
int initialized; /* whether ap_data has been initialized */
|
||||
local_info_t *local;
|
||||
int bridge_packets; /* send packet to associated STAs directly to the
|
||||
* wireless media instead of higher layers in the
|
||||
* kernel */
|
||||
unsigned int bridged_unicast; /* number of unicast frames bridged on
|
||||
* wireless media */
|
||||
unsigned int bridged_multicast; /* number of non-unicast frames
|
||||
* bridged on wireless media */
|
||||
unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped
|
||||
* because they were to an address that
|
||||
* was not associated */
|
||||
int nullfunc_ack; /* use workaround for nullfunc frame ACKs */
|
||||
|
||||
spinlock_t sta_table_lock;
|
||||
int num_sta; /* number of entries in sta_list */
|
||||
struct list_head sta_list; /* STA info list head */
|
||||
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||
|
||||
struct proc_dir_entry *proc;
|
||||
|
||||
ap_policy_enum ap_policy;
|
||||
unsigned int max_inactivity;
|
||||
int autom_ap_wds;
|
||||
|
||||
struct mac_restrictions mac_restrictions; /* MAC-based auth */
|
||||
int last_tx_rate;
|
||||
|
||||
struct work_struct add_sta_proc_queue;
|
||||
struct add_sta_proc_data *add_sta_proc_entries;
|
||||
|
||||
struct work_struct wds_oper_queue;
|
||||
struct wds_oper_data *wds_oper_entries;
|
||||
|
||||
u16 tx_callback_idx;
|
||||
|
||||
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
|
||||
/* pointers to STA info; based on allocated AID or NULL if AID free
|
||||
* AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
|
||||
* and so on
|
||||
*/
|
||||
struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
|
||||
|
||||
u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll;
|
||||
|
||||
/* WEP operations for generating challenges to be used with shared key
|
||||
* authentication */
|
||||
struct lib80211_crypto_ops *crypt;
|
||||
void *crypt_priv;
|
||||
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
};
|
||||
|
||||
|
||||
void hostap_rx(struct net_device *dev, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
void hostap_init_data(local_info_t *local);
|
||||
void hostap_init_ap_proc(local_info_t *local);
|
||||
void hostap_free_data(struct ap_data *ap);
|
||||
void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver);
|
||||
|
||||
typedef enum {
|
||||
AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED,
|
||||
AP_TX_CONTINUE_NOT_AUTHORIZED
|
||||
} ap_tx_ret;
|
||||
struct hostap_tx_data {
|
||||
struct sk_buff *skb;
|
||||
int host_encrypt;
|
||||
struct lib80211_crypt_data *crypt;
|
||||
void *sta_ptr;
|
||||
};
|
||||
ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
|
||||
void hostap_handle_sta_release(void *ptr);
|
||||
void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
|
||||
int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr);
|
||||
typedef enum {
|
||||
AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
|
||||
} ap_rx_ret;
|
||||
ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats,
|
||||
int wds);
|
||||
int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr,
|
||||
struct lib80211_crypt_data **crypt,
|
||||
void **sta_ptr);
|
||||
int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
|
||||
int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
|
||||
int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
|
||||
int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
void hostap_update_rates(local_info_t *local);
|
||||
void hostap_add_wds_links(local_info_t *local);
|
||||
void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type);
|
||||
|
||||
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
|
||||
void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
|
||||
int resend);
|
||||
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
|
||||
#endif /* HOSTAP_AP_H */
|
419
drivers/net/wireless/intersil/hostap/hostap_common.h
Normal file
419
drivers/net/wireless/intersil/hostap/hostap_common.h
Normal file
@@ -0,0 +1,419 @@
|
||||
#ifndef HOSTAP_COMMON_H
|
||||
#define HOSTAP_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
/* IEEE 802.11 defines */
|
||||
|
||||
/* HFA384X Configuration RIDs */
|
||||
#define HFA384X_RID_CNFPORTTYPE 0xFC00
|
||||
#define HFA384X_RID_CNFOWNMACADDR 0xFC01
|
||||
#define HFA384X_RID_CNFDESIREDSSID 0xFC02
|
||||
#define HFA384X_RID_CNFOWNCHANNEL 0xFC03
|
||||
#define HFA384X_RID_CNFOWNSSID 0xFC04
|
||||
#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05
|
||||
#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06
|
||||
#define HFA384X_RID_CNFMAXDATALEN 0xFC07
|
||||
#define HFA384X_RID_CNFWDSADDRESS 0xFC08
|
||||
#define HFA384X_RID_CNFPMENABLED 0xFC09
|
||||
#define HFA384X_RID_CNFPMEPS 0xFC0A
|
||||
#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B
|
||||
#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C
|
||||
#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D
|
||||
#define HFA384X_RID_CNFOWNNAME 0xFC0E
|
||||
#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10
|
||||
#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */
|
||||
#define HFA384X_RID_UNKNOWN1 0xFC20
|
||||
#define HFA384X_RID_UNKNOWN2 0xFC21
|
||||
#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23
|
||||
#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24
|
||||
#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25
|
||||
#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26
|
||||
#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27
|
||||
#define HFA384X_RID_CNFWEPFLAGS 0xFC28
|
||||
#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
|
||||
#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A
|
||||
#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */
|
||||
#define HFA384X_RID_CNFTXCONTROL 0xFC2C
|
||||
#define HFA384X_RID_CNFROAMINGMODE 0xFC2D
|
||||
#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */
|
||||
#define HFA384X_RID_CNFRCVCRCERROR 0xFC30
|
||||
#define HFA384X_RID_CNFMMLIFE 0xFC31
|
||||
#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32
|
||||
#define HFA384X_RID_CNFBEACONINT 0xFC33
|
||||
#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFSTAPCFINFO 0xFC35
|
||||
#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37
|
||||
#define HFA384X_RID_CNFTIMCTRL 0xFC40
|
||||
#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */
|
||||
#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */
|
||||
#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */
|
||||
#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */
|
||||
#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0;
|
||||
* write only */
|
||||
#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */
|
||||
#define HFA384X_RID_GROUPADDRESSES 0xFC80
|
||||
#define HFA384X_RID_CREATEIBSS 0xFC81
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82
|
||||
#define HFA384X_RID_RTSTHRESHOLD 0xFC83
|
||||
#define HFA384X_RID_TXRATECONTROL 0xFC84
|
||||
#define HFA384X_RID_PROMISCUOUSMODE 0xFC85
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */
|
||||
#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */
|
||||
#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */
|
||||
#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */
|
||||
#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */
|
||||
#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */
|
||||
#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */
|
||||
#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */
|
||||
#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */
|
||||
#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */
|
||||
#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */
|
||||
#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */
|
||||
#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */
|
||||
#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */
|
||||
#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */
|
||||
#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */
|
||||
#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0
|
||||
#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
|
||||
#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
|
||||
#define HFA384X_RID_CNFBASICRATES 0xFCB3
|
||||
#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4
|
||||
#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */
|
||||
#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */
|
||||
#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */
|
||||
#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */
|
||||
#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */
|
||||
#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */
|
||||
#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */
|
||||
#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */
|
||||
#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */
|
||||
#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */
|
||||
#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */
|
||||
#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */
|
||||
#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */
|
||||
#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */
|
||||
#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */
|
||||
#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */
|
||||
#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */
|
||||
#define HFA384X_RID_TICKTIME 0xFCE0
|
||||
#define HFA384X_RID_SCANREQUEST 0xFCE1
|
||||
#define HFA384X_RID_JOINREQUEST 0xFCE2
|
||||
#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */
|
||||
#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */
|
||||
#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */
|
||||
|
||||
/* HFA384X Information RIDs */
|
||||
#define HFA384X_RID_MAXLOADTIME 0xFD00
|
||||
#define HFA384X_RID_DOWNLOADBUFFER 0xFD01
|
||||
#define HFA384X_RID_PRIID 0xFD02
|
||||
#define HFA384X_RID_PRISUPRANGE 0xFD03
|
||||
#define HFA384X_RID_CFIACTRANGES 0xFD04
|
||||
#define HFA384X_RID_NICSERNUM 0xFD0A
|
||||
#define HFA384X_RID_NICID 0xFD0B
|
||||
#define HFA384X_RID_MFISUPRANGE 0xFD0C
|
||||
#define HFA384X_RID_CFISUPRANGE 0xFD0D
|
||||
#define HFA384X_RID_CHANNELLIST 0xFD10
|
||||
#define HFA384X_RID_REGULATORYDOMAINS 0xFD11
|
||||
#define HFA384X_RID_TEMPTYPE 0xFD12
|
||||
#define HFA384X_RID_CIS 0xFD13
|
||||
#define HFA384X_RID_STAID 0xFD20
|
||||
#define HFA384X_RID_STASUPRANGE 0xFD21
|
||||
#define HFA384X_RID_MFIACTRANGES 0xFD22
|
||||
#define HFA384X_RID_CFIACTRANGES2 0xFD23
|
||||
#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1;
|
||||
* only Prism2.5(?) */
|
||||
#define HFA384X_RID_PORTSTATUS 0xFD40
|
||||
#define HFA384X_RID_CURRENTSSID 0xFD41
|
||||
#define HFA384X_RID_CURRENTBSSID 0xFD42
|
||||
#define HFA384X_RID_COMMSQUALITY 0xFD43
|
||||
#define HFA384X_RID_CURRENTTXRATE 0xFD44
|
||||
#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45
|
||||
#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46
|
||||
#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47
|
||||
#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48
|
||||
#define HFA384X_RID_LONGRETRYLIMIT 0xFD49
|
||||
#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A
|
||||
#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B
|
||||
#define HFA384X_RID_CFPOLLABLE 0xFD4C
|
||||
#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D
|
||||
#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
|
||||
#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */
|
||||
#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */
|
||||
#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */
|
||||
#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */
|
||||
#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */
|
||||
#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */
|
||||
#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */
|
||||
#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */
|
||||
#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */
|
||||
#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */
|
||||
#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */
|
||||
#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */
|
||||
#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */
|
||||
#define HFA384X_RID_PHYTYPE 0xFDC0
|
||||
#define HFA384X_RID_CURRENTCHANNEL 0xFDC1
|
||||
#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2
|
||||
#define HFA384X_RID_CCAMODE 0xFDC3
|
||||
#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6
|
||||
#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */
|
||||
#define HFA384X_RID_BUILDSEQ 0xFFFE
|
||||
#define HFA384X_RID_FWID 0xFFFF
|
||||
|
||||
|
||||
struct hfa384x_comp_ident
|
||||
{
|
||||
__le16 id;
|
||||
__le16 variant;
|
||||
__le16 major;
|
||||
__le16 minor;
|
||||
} __packed;
|
||||
|
||||
#define HFA384X_COMP_ID_PRI 0x15
|
||||
#define HFA384X_COMP_ID_STA 0x1f
|
||||
#define HFA384X_COMP_ID_FW_AP 0x14b
|
||||
|
||||
struct hfa384x_sup_range
|
||||
{
|
||||
__le16 role;
|
||||
__le16 id;
|
||||
__le16 variant;
|
||||
__le16 bottom;
|
||||
__le16 top;
|
||||
} __packed;
|
||||
|
||||
|
||||
struct hfa384x_build_id
|
||||
{
|
||||
__le16 pri_seq;
|
||||
__le16 sec_seq;
|
||||
} __packed;
|
||||
|
||||
/* FD01 - Download Buffer */
|
||||
struct hfa384x_rid_download_buffer
|
||||
{
|
||||
__le16 page;
|
||||
__le16 offset;
|
||||
__le16 length;
|
||||
} __packed;
|
||||
|
||||
/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
|
||||
struct hfa384x_comms_quality {
|
||||
__le16 comm_qual; /* 0 .. 92 */
|
||||
__le16 signal_level; /* 27 .. 154 */
|
||||
__le16 noise_level; /* 27 .. 154 */
|
||||
} __packed;
|
||||
|
||||
|
||||
/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
|
||||
|
||||
/* New wireless extensions API - SET/GET convention (even ioctl numbers are
|
||||
* root only)
|
||||
*/
|
||||
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
|
||||
#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
|
||||
#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
|
||||
#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
|
||||
#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
|
||||
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
|
||||
#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
|
||||
#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
|
||||
#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
|
||||
#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
|
||||
#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
|
||||
#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
|
||||
#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
|
||||
#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
|
||||
|
||||
/* following are not in SIOCGIWPRIV list; check permission in the driver code
|
||||
*/
|
||||
#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
|
||||
#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
|
||||
|
||||
|
||||
/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
|
||||
enum {
|
||||
/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
|
||||
PRISM2_PARAM_TXRATECTRL = 2,
|
||||
PRISM2_PARAM_BEACON_INT = 3,
|
||||
PRISM2_PARAM_PSEUDO_IBSS = 4,
|
||||
PRISM2_PARAM_ALC = 5,
|
||||
/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
|
||||
PRISM2_PARAM_DUMP = 7,
|
||||
PRISM2_PARAM_OTHER_AP_POLICY = 8,
|
||||
PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
|
||||
PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
|
||||
PRISM2_PARAM_DTIM_PERIOD = 11,
|
||||
PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
|
||||
PRISM2_PARAM_MAX_WDS = 13,
|
||||
PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
|
||||
PRISM2_PARAM_AP_AUTH_ALGS = 15,
|
||||
PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
|
||||
PRISM2_PARAM_HOST_ENCRYPT = 17,
|
||||
PRISM2_PARAM_HOST_DECRYPT = 18,
|
||||
/* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */
|
||||
/* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */
|
||||
PRISM2_PARAM_HOST_ROAMING = 21,
|
||||
PRISM2_PARAM_BCRX_STA_KEY = 22,
|
||||
PRISM2_PARAM_IEEE_802_1X = 23,
|
||||
PRISM2_PARAM_ANTSEL_TX = 24,
|
||||
PRISM2_PARAM_ANTSEL_RX = 25,
|
||||
PRISM2_PARAM_MONITOR_TYPE = 26,
|
||||
PRISM2_PARAM_WDS_TYPE = 27,
|
||||
PRISM2_PARAM_HOSTSCAN = 28,
|
||||
PRISM2_PARAM_AP_SCAN = 29,
|
||||
PRISM2_PARAM_ENH_SEC = 30,
|
||||
PRISM2_PARAM_IO_DEBUG = 31,
|
||||
PRISM2_PARAM_BASIC_RATES = 32,
|
||||
PRISM2_PARAM_OPER_RATES = 33,
|
||||
PRISM2_PARAM_HOSTAPD = 34,
|
||||
PRISM2_PARAM_HOSTAPD_STA = 35,
|
||||
PRISM2_PARAM_WPA = 36,
|
||||
PRISM2_PARAM_PRIVACY_INVOKED = 37,
|
||||
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
|
||||
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
|
||||
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
|
||||
};
|
||||
|
||||
enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
|
||||
HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
|
||||
|
||||
|
||||
/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
|
||||
enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
|
||||
AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
|
||||
AP_MAC_CMD_KICKALL = 4 };
|
||||
|
||||
|
||||
/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
|
||||
enum {
|
||||
PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
|
||||
/* Note! Old versions of prism2_srec have a fatal error in CRC-16
|
||||
* calculation, which will corrupt all non-volatile downloads.
|
||||
* PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
|
||||
* prevent use of old versions of prism2_srec for non-volatile
|
||||
* download. */
|
||||
PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
|
||||
PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
|
||||
/* Persistent versions of volatile download commands (keep firmware
|
||||
* data in memory and automatically re-download after hw_reset */
|
||||
PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
|
||||
PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
|
||||
};
|
||||
|
||||
struct prism2_download_param {
|
||||
u32 dl_cmd;
|
||||
u32 start_addr;
|
||||
u32 num_areas;
|
||||
struct prism2_download_area {
|
||||
u32 addr; /* wlan card address */
|
||||
u32 len;
|
||||
void __user *ptr; /* pointer to data in user space */
|
||||
} data[0];
|
||||
};
|
||||
|
||||
#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
|
||||
#define PRISM2_MAX_DOWNLOAD_LEN 262144
|
||||
|
||||
|
||||
/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
|
||||
enum {
|
||||
PRISM2_HOSTAPD_FLUSH = 1,
|
||||
PRISM2_HOSTAPD_ADD_STA = 2,
|
||||
PRISM2_HOSTAPD_REMOVE_STA = 3,
|
||||
PRISM2_HOSTAPD_GET_INFO_STA = 4,
|
||||
/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
|
||||
PRISM2_SET_ENCRYPTION = 6,
|
||||
PRISM2_GET_ENCRYPTION = 7,
|
||||
PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
|
||||
PRISM2_HOSTAPD_GET_RID = 9,
|
||||
PRISM2_HOSTAPD_SET_RID = 10,
|
||||
PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
|
||||
PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
|
||||
PRISM2_HOSTAPD_MLME = 13,
|
||||
PRISM2_HOSTAPD_SCAN_REQ = 14,
|
||||
PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
|
||||
};
|
||||
|
||||
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
|
||||
#define PRISM2_HOSTAPD_RID_HDR_LEN \
|
||||
offsetof(struct prism2_hostapd_param, u.rid.data)
|
||||
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
|
||||
offsetof(struct prism2_hostapd_param, u.generic_elem.data)
|
||||
|
||||
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
|
||||
*/
|
||||
#define HOSTAP_CRYPT_ALG_NAME_LEN 16
|
||||
|
||||
|
||||
struct prism2_hostapd_param {
|
||||
u32 cmd;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
union {
|
||||
struct {
|
||||
u16 aid;
|
||||
u16 capability;
|
||||
u8 tx_supp_rates;
|
||||
} add_sta;
|
||||
struct {
|
||||
u32 inactive_sec;
|
||||
} get_info_sta;
|
||||
struct {
|
||||
u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
|
||||
u32 flags;
|
||||
u32 err;
|
||||
u8 idx;
|
||||
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
|
||||
u16 key_len;
|
||||
u8 key[0];
|
||||
} crypt;
|
||||
struct {
|
||||
u32 flags_and;
|
||||
u32 flags_or;
|
||||
} set_flags_sta;
|
||||
struct {
|
||||
u16 rid;
|
||||
u16 len;
|
||||
u8 data[0];
|
||||
} rid;
|
||||
struct {
|
||||
u8 len;
|
||||
u8 data[0];
|
||||
} generic_elem;
|
||||
struct {
|
||||
#define MLME_STA_DEAUTH 0
|
||||
#define MLME_STA_DISASSOC 1
|
||||
u16 cmd;
|
||||
u16 reason_code;
|
||||
} mlme;
|
||||
struct {
|
||||
u8 ssid_len;
|
||||
u8 ssid[32];
|
||||
} scan_req;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
|
||||
#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
|
||||
|
||||
#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
|
||||
#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
|
||||
#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
|
||||
#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
|
||||
#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
|
||||
#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
|
||||
|
||||
|
||||
#endif /* HOSTAP_COMMON_H */
|
48
drivers/net/wireless/intersil/hostap/hostap_config.h
Normal file
48
drivers/net/wireless/intersil/hostap/hostap_config.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef HOSTAP_CONFIG_H
|
||||
#define HOSTAP_CONFIG_H
|
||||
|
||||
/* In the previous versions of Host AP driver, support for user space version
|
||||
* of IEEE 802.11 management (hostapd) used to be disabled in the default
|
||||
* configuration. From now on, support for hostapd is always included and it is
|
||||
* possible to disable kernel driver version of IEEE 802.11 management with a
|
||||
* separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */
|
||||
/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
|
||||
/* Maximum number of events handler per one interrupt */
|
||||
#define PRISM2_MAX_INTERRUPT_EVENTS 20
|
||||
|
||||
/* Include code for downloading firmware images into volatile RAM. */
|
||||
#define PRISM2_DOWNLOAD_SUPPORT
|
||||
|
||||
/* Allow kernel configuration to enable download support. */
|
||||
#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE)
|
||||
#define PRISM2_DOWNLOAD_SUPPORT
|
||||
#endif
|
||||
|
||||
/* Allow kernel configuration to enable non-volatile download support. */
|
||||
#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM
|
||||
#define PRISM2_NON_VOLATILE_DOWNLOAD
|
||||
#endif
|
||||
|
||||
/* Save low-level I/O for debugging. This should not be enabled in normal use.
|
||||
*/
|
||||
/* #define PRISM2_IO_DEBUG */
|
||||
|
||||
/* Following defines can be used to remove unneeded parts of the driver, e.g.,
|
||||
* to limit the size of the kernel module. Definitions can be added here in
|
||||
* hostap_config.h or they can be added to make command with ccflags-y,
|
||||
* e.g.,
|
||||
* 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
|
||||
*/
|
||||
|
||||
/* Do not include debug messages into the driver */
|
||||
/* #define PRISM2_NO_DEBUG */
|
||||
|
||||
/* Do not include /proc/net/prism2/wlan#/{registers,debug} */
|
||||
/* #define PRISM2_NO_PROCFS_DEBUG */
|
||||
|
||||
/* Do not include station functionality (i.e., allow only Master (Host AP) mode
|
||||
*/
|
||||
/* #define PRISM2_NO_STATION_MODES */
|
||||
|
||||
#endif /* HOSTAP_CONFIG_H */
|
708
drivers/net/wireless/intersil/hostap/hostap_cs.c
Normal file
708
drivers/net/wireless/intersil/hostap/hostap_cs.c
Normal file
@@ -0,0 +1,708 @@
|
||||
#define PRISM2_PCCARD
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "hostap_wlan.h"
|
||||
|
||||
|
||||
static char *dev_info = "hostap_cs";
|
||||
|
||||
MODULE_AUTHOR("Jouni Malinen");
|
||||
MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
|
||||
"cards (PC Card).");
|
||||
MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static int ignore_cis_vcc;
|
||||
module_param(ignore_cis_vcc, int, 0444);
|
||||
MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
|
||||
|
||||
|
||||
/* struct local_info::hw_priv */
|
||||
struct hostap_cs_priv {
|
||||
struct pcmcia_device *link;
|
||||
int sandisk_connectplus;
|
||||
};
|
||||
|
||||
|
||||
#ifdef PRISM2_IO_DEBUG
|
||||
|
||||
static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
|
||||
outb(v, dev->base_addr + a);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
u8 v;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
v = inb(dev->base_addr + a);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
|
||||
outw(v, dev->base_addr + a);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
u16 v;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
v = inw(dev->base_addr + a);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
|
||||
u8 *buf, int wc)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
|
||||
outsw(dev->base_addr + a, buf, wc);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline void hfa384x_insw_debug(struct net_device *dev, int a,
|
||||
u8 *buf, int wc)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
|
||||
insw(dev->base_addr + a, buf, wc);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
|
||||
#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
|
||||
#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
|
||||
#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
|
||||
#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
|
||||
#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
|
||||
|
||||
#else /* PRISM2_IO_DEBUG */
|
||||
|
||||
#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
|
||||
#define HFA384X_INB(a) inb(dev->base_addr + (a))
|
||||
#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
|
||||
#define HFA384X_INW(a) inw(dev->base_addr + (a))
|
||||
#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
|
||||
#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
|
||||
|
||||
#endif /* PRISM2_IO_DEBUG */
|
||||
|
||||
|
||||
static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
|
||||
int len)
|
||||
{
|
||||
u16 d_off;
|
||||
u16 *pos;
|
||||
|
||||
d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
|
||||
pos = (u16 *) buf;
|
||||
|
||||
if (len / 2)
|
||||
HFA384X_INSW(d_off, buf, len / 2);
|
||||
pos += len / 2;
|
||||
|
||||
if (len & 1)
|
||||
*((char *) pos) = HFA384X_INB(d_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
|
||||
{
|
||||
u16 d_off;
|
||||
u16 *pos;
|
||||
|
||||
d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
|
||||
pos = (u16 *) buf;
|
||||
|
||||
if (len / 2)
|
||||
HFA384X_OUTSW(d_off, buf, len / 2);
|
||||
pos += len / 2;
|
||||
|
||||
if (len & 1)
|
||||
HFA384X_OUTB(*((char *) pos), d_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FIX: This might change at some point.. */
|
||||
#include "hostap_hw.c"
|
||||
|
||||
|
||||
|
||||
static void prism2_detach(struct pcmcia_device *p_dev);
|
||||
static void prism2_release(u_long arg);
|
||||
static int prism2_config(struct pcmcia_device *link);
|
||||
|
||||
|
||||
static int prism2_pccard_card_present(local_info_t *local)
|
||||
{
|
||||
struct hostap_cs_priv *hw_priv = local->hw_priv;
|
||||
if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0
|
||||
* Document No. 20-10-00058, January 2004
|
||||
* http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
|
||||
*/
|
||||
#define SANDISK_WLAN_ACTIVATION_OFF 0x40
|
||||
#define SANDISK_HCR_OFF 0x42
|
||||
|
||||
|
||||
static void sandisk_set_iobase(local_info_t *local)
|
||||
{
|
||||
int res;
|
||||
struct hostap_cs_priv *hw_priv = local->hw_priv;
|
||||
|
||||
res = pcmcia_write_config_byte(hw_priv->link, 0x10,
|
||||
hw_priv->link->resource[0]->start & 0x00ff);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
|
||||
" res=%d\n", res);
|
||||
}
|
||||
udelay(10);
|
||||
|
||||
res = pcmcia_write_config_byte(hw_priv->link, 0x12,
|
||||
(hw_priv->link->resource[0]->start >> 8) & 0x00ff);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
|
||||
" res=%d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sandisk_write_hcr(local_info_t *local, int hcr)
|
||||
{
|
||||
struct net_device *dev = local->dev;
|
||||
int i;
|
||||
|
||||
HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF);
|
||||
udelay(50);
|
||||
for (i = 0; i < 10; i++) {
|
||||
HFA384X_OUTB(hcr, SANDISK_HCR_OFF);
|
||||
}
|
||||
udelay(55);
|
||||
HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF);
|
||||
}
|
||||
|
||||
|
||||
static int sandisk_enable_wireless(struct net_device *dev)
|
||||
{
|
||||
int res, ret = 0;
|
||||
struct hostap_interface *iface = netdev_priv(dev);
|
||||
local_info_t *local = iface->local;
|
||||
struct hostap_cs_priv *hw_priv = local->hw_priv;
|
||||
|
||||
if (resource_size(hw_priv->link->resource[0]) < 0x42) {
|
||||
/* Not enough ports to be SanDisk multi-function card */
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) {
|
||||
/* No SanDisk manfid found */
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (hw_priv->link->socket->functions < 2) {
|
||||
/* No multi-function links found */
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected"
|
||||
" - using vendor-specific initialization\n", dev->name);
|
||||
hw_priv->sandisk_connectplus = 1;
|
||||
|
||||
res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
|
||||
COR_SOFT_RESET);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
|
||||
dev->name, res);
|
||||
goto done;
|
||||
}
|
||||
mdelay(5);
|
||||
|
||||
/*
|
||||
* Do not enable interrupts here to avoid some bogus events. Interrupts
|
||||
* will be enabled during the first cor_sreset call.
|
||||
*/
|
||||
res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
|
||||
(COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE |
|
||||
COR_FUNC_ENA));
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
|
||||
dev->name, res);
|
||||
goto done;
|
||||
}
|
||||
mdelay(5);
|
||||
|
||||
sandisk_set_iobase(local);
|
||||
|
||||
HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF);
|
||||
udelay(10);
|
||||
HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF);
|
||||
udelay(10);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void prism2_pccard_cor_sreset(local_info_t *local)
|
||||
{
|
||||
int res;
|
||||
u8 val;
|
||||
struct hostap_cs_priv *hw_priv = local->hw_priv;
|
||||
|
||||
if (!prism2_pccard_card_present(local))
|
||||
return;
|
||||
|
||||
res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
|
||||
res);
|
||||
return;
|
||||
}
|
||||
printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
|
||||
val);
|
||||
|
||||
val |= COR_SOFT_RESET;
|
||||
res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
|
||||
res);
|
||||
return;
|
||||
}
|
||||
|
||||
mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
|
||||
|
||||
val &= ~COR_SOFT_RESET;
|
||||
if (hw_priv->sandisk_connectplus)
|
||||
val |= COR_IREQ_ENA;
|
||||
res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
|
||||
res);
|
||||
return;
|
||||
}
|
||||
|
||||
mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
|
||||
|
||||
if (hw_priv->sandisk_connectplus)
|
||||
sandisk_set_iobase(local);
|
||||
}
|
||||
|
||||
|
||||
static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
|
||||
{
|
||||
int res;
|
||||
u8 old_cor;
|
||||
struct hostap_cs_priv *hw_priv = local->hw_priv;
|
||||
|
||||
if (!prism2_pccard_card_present(local))
|
||||
return;
|
||||
|
||||
if (hw_priv->sandisk_connectplus) {
|
||||
sandisk_write_hcr(local, hcr);
|
||||
return;
|
||||
}
|
||||
|
||||
res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res);
|
||||
return;
|
||||
}
|
||||
printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor);
|
||||
|
||||
res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
|
||||
old_cor | COR_SOFT_RESET);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res);
|
||||
return;
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
|
||||
/* Setup Genesis mode */
|
||||
res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res);
|
||||
return;
|
||||
}
|
||||
mdelay(10);
|
||||
|
||||
res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
|
||||
old_cor & ~COR_SOFT_RESET);
|
||||
if (res != 0) {
|
||||
printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res);
|
||||
return;
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
|
||||
static struct prism2_helper_functions prism2_pccard_funcs =
|
||||
{
|
||||
.card_present = prism2_pccard_card_present,
|
||||
.cor_sreset = prism2_pccard_cor_sreset,
|
||||
.genesis_reset = prism2_pccard_genesis_reset,
|
||||
.hw_type = HOSTAP_HW_PCCARD,
|
||||
};
|
||||
|
||||
|
||||
/* allocate local data and register with CardServices
|
||||
* initialize dev_link structure, but do not configure the card yet */
|
||||
static int hostap_cs_probe(struct pcmcia_device *p_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
|
||||
|
||||
ret = prism2_config(p_dev);
|
||||
if (ret) {
|
||||
PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void prism2_detach(struct pcmcia_device *link)
|
||||
{
|
||||
PDEBUG(DEBUG_FLOW, "prism2_detach\n");
|
||||
|
||||
prism2_release((u_long)link);
|
||||
|
||||
/* release net devices */
|
||||
if (link->priv) {
|
||||
struct hostap_cs_priv *hw_priv;
|
||||
struct net_device *dev;
|
||||
struct hostap_interface *iface;
|
||||
dev = link->priv;
|
||||
iface = netdev_priv(dev);
|
||||
hw_priv = iface->local->hw_priv;
|
||||
prism2_free_local_data(dev);
|
||||
kfree(hw_priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data)
|
||||
{
|
||||
if (p_dev->config_index == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return pcmcia_request_io(p_dev);
|
||||
}
|
||||
|
||||
static int prism2_config(struct pcmcia_device *link)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
int ret = 1;
|
||||
struct hostap_cs_priv *hw_priv;
|
||||
unsigned long flags;
|
||||
|
||||
PDEBUG(DEBUG_FLOW, "prism2_config()\n");
|
||||
|
||||
hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
|
||||
if (hw_priv == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Look for an appropriate configuration table entry in the CIS */
|
||||
link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO |
|
||||
CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
|
||||
if (ignore_cis_vcc)
|
||||
link->config_flags &= ~CONF_AUTO_CHECK_VCC;
|
||||
ret = pcmcia_loop_config(link, prism2_config_check, NULL);
|
||||
if (ret) {
|
||||
if (!ignore_cis_vcc)
|
||||
printk(KERN_ERR "GetNextTuple(): No matching "
|
||||
"CIS configuration. Maybe you need the "
|
||||
"ignore_cis_vcc=1 parameter.\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Need to allocate net_device before requesting IRQ handler */
|
||||
dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
|
||||
&link->dev);
|
||||
if (dev == NULL)
|
||||
goto failed;
|
||||
link->priv = dev;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
local->hw_priv = hw_priv;
|
||||
hw_priv->link = link;
|
||||
|
||||
/*
|
||||
* We enable IRQ here, but IRQ handler will not proceed
|
||||
* until dev->base_addr is set below. This protect us from
|
||||
* receive interrupts when driver is not initialized.
|
||||
*/
|
||||
ret = pcmcia_request_irq(link, prism2_interrupt);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
ret = pcmcia_enable_device(link);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(&local->irq_init_lock, flags);
|
||||
dev->irq = link->irq;
|
||||
dev->base_addr = link->resource[0]->start;
|
||||
spin_unlock_irqrestore(&local->irq_init_lock, flags);
|
||||
|
||||
local->shutdown = 0;
|
||||
|
||||
sandisk_enable_wireless(dev);
|
||||
|
||||
ret = prism2_hw_config(dev, 1);
|
||||
if (!ret)
|
||||
ret = hostap_hw_ready(dev);
|
||||
|
||||
return ret;
|
||||
|
||||
failed:
|
||||
kfree(hw_priv);
|
||||
prism2_release((u_long)link);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void prism2_release(u_long arg)
|
||||
{
|
||||
struct pcmcia_device *link = (struct pcmcia_device *)arg;
|
||||
|
||||
PDEBUG(DEBUG_FLOW, "prism2_release\n");
|
||||
|
||||
if (link->priv) {
|
||||
struct net_device *dev = link->priv;
|
||||
struct hostap_interface *iface;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
prism2_hw_shutdown(dev, 0);
|
||||
iface->local->shutdown = 1;
|
||||
}
|
||||
|
||||
pcmcia_disable_device(link);
|
||||
PDEBUG(DEBUG_FLOW, "release - done\n");
|
||||
}
|
||||
|
||||
static int hostap_cs_suspend(struct pcmcia_device *link)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *) link->priv;
|
||||
int dev_open = 0;
|
||||
struct hostap_interface *iface = NULL;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
|
||||
PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
|
||||
if (iface && iface->local)
|
||||
dev_open = iface->local->num_dev_open > 0;
|
||||
if (dev_open) {
|
||||
netif_stop_queue(dev);
|
||||
netif_device_detach(dev);
|
||||
}
|
||||
prism2_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hostap_cs_resume(struct pcmcia_device *link)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *) link->priv;
|
||||
int dev_open = 0;
|
||||
struct hostap_interface *iface = NULL;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
|
||||
PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
|
||||
|
||||
if (iface && iface->local)
|
||||
dev_open = iface->local->num_dev_open > 0;
|
||||
|
||||
prism2_hw_shutdown(dev, 1);
|
||||
prism2_hw_config(dev, dev_open ? 0 : 1);
|
||||
if (dev_open) {
|
||||
netif_device_attach(dev);
|
||||
netif_start_queue(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pcmcia_device_id hostap_cs_ids[] = {
|
||||
PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
|
||||
/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */
|
||||
PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
|
||||
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
|
||||
0x2d858104),
|
||||
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
|
||||
0x74c5e40d),
|
||||
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
|
||||
0x4b801a17),
|
||||
PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02",
|
||||
0x4b74baa0),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
|
||||
0x7a954bd9, 0x74be00c6),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
|
||||
0xe6ec52ce, 0x08649af2, 0x4b74baa0),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"Canon", "Wireless LAN CF Card K30225", "Version 01.00",
|
||||
0x96ef6fe2, 0x263fcbab, 0xa57adb8c),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
|
||||
0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"Instant Wireless ", " Network PC CARD", "Version 01.02",
|
||||
0x11d901af, 0x6e9bd926, 0x4b74baa0),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"SMC", "SMC2632W", "Version 01.02",
|
||||
0xc4f8b18b, 0x474a1f2a, 0x4b74baa0),
|
||||
PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G",
|
||||
0x2decece3, 0x82067c18),
|
||||
PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card",
|
||||
0x54f7c49c, 0x15a75e5b),
|
||||
PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE",
|
||||
0x74c5e40d, 0xdb472a18),
|
||||
PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card",
|
||||
0x0733cc81, 0x0c52f395),
|
||||
PCMCIA_DEVICE_PROD_ID12(
|
||||
"ZoomAir 11Mbps High", "Rate wireless Networking",
|
||||
0x273fe3db, 0x32a1eaee),
|
||||
PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
|
||||
0xa37434e9, 0x9762e8f1),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"Pretec", "CompactWLAN Card 802.11b", "2.5",
|
||||
0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
|
||||
0xc7b8df9d, 0x1700d087, 0x4b74baa0),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
|
||||
"Ver. 1.00",
|
||||
0x5cd01705, 0x4271660f, 0x9d08ee12),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"Wireless LAN" , "11Mbps PC Card", "Version 01.02",
|
||||
0x4b8870ff, 0x70e946d1, 0x4b74baa0),
|
||||
PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
|
||||
PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
|
||||
PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
|
||||
PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
|
||||
PCMCIA_DEVICE_NULL
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
|
||||
|
||||
|
||||
static struct pcmcia_driver hostap_driver = {
|
||||
.name = "hostap_cs",
|
||||
.probe = hostap_cs_probe,
|
||||
.remove = prism2_detach,
|
||||
.owner = THIS_MODULE,
|
||||
.id_table = hostap_cs_ids,
|
||||
.suspend = hostap_cs_suspend,
|
||||
.resume = hostap_cs_resume,
|
||||
};
|
||||
module_pcmcia_driver(hostap_driver);
|
812
drivers/net/wireless/intersil/hostap/hostap_download.c
Normal file
812
drivers/net/wireless/intersil/hostap/hostap_download.c
Normal file
@@ -0,0 +1,812 @@
|
||||
static int prism2_enable_aux_port(struct net_device *dev, int enable)
|
||||
{
|
||||
u16 val, reg;
|
||||
int i, tries;
|
||||
unsigned long flags;
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
if (local->no_pri) {
|
||||
if (enable) {
|
||||
PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
|
||||
"port is already enabled\n", dev->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&local->cmdlock, flags);
|
||||
|
||||
/* wait until busy bit is clear */
|
||||
tries = HFA384X_CMD_BUSY_TIMEOUT;
|
||||
while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
|
||||
tries--;
|
||||
udelay(1);
|
||||
}
|
||||
if (tries == 0) {
|
||||
reg = HFA384X_INW(HFA384X_CMD_OFF);
|
||||
spin_unlock_irqrestore(&local->cmdlock, flags);
|
||||
printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
|
||||
dev->name, reg);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
val = HFA384X_INW(HFA384X_CONTROL_OFF);
|
||||
|
||||
if (enable) {
|
||||
HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
|
||||
HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
|
||||
HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
|
||||
|
||||
if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
|
||||
printk("prism2_enable_aux_port: was not disabled!?\n");
|
||||
val &= ~HFA384X_AUX_PORT_MASK;
|
||||
val |= HFA384X_AUX_PORT_ENABLE;
|
||||
} else {
|
||||
HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
|
||||
HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
|
||||
HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
|
||||
|
||||
if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
|
||||
printk("prism2_enable_aux_port: was not enabled!?\n");
|
||||
val &= ~HFA384X_AUX_PORT_MASK;
|
||||
val |= HFA384X_AUX_PORT_DISABLE;
|
||||
}
|
||||
HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
|
||||
|
||||
udelay(5);
|
||||
|
||||
i = 10000;
|
||||
while (i > 0) {
|
||||
val = HFA384X_INW(HFA384X_CONTROL_OFF);
|
||||
val &= HFA384X_AUX_PORT_MASK;
|
||||
|
||||
if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
|
||||
(!enable && val == HFA384X_AUX_PORT_DISABLED))
|
||||
break;
|
||||
|
||||
udelay(10);
|
||||
i--;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&local->cmdlock, flags);
|
||||
|
||||
if (i == 0) {
|
||||
printk("prism2_enable_aux_port(%d) timed out\n",
|
||||
enable);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
|
||||
void *buf)
|
||||
{
|
||||
u16 page, offset;
|
||||
if (addr & 1 || len & 1)
|
||||
return -1;
|
||||
|
||||
page = addr >> 7;
|
||||
offset = addr & 0x7f;
|
||||
|
||||
HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
|
||||
HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
|
||||
|
||||
udelay(5);
|
||||
|
||||
#ifdef PRISM2_PCI
|
||||
{
|
||||
__le16 *pos = (__le16 *) buf;
|
||||
while (len > 0) {
|
||||
*pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
#else /* PRISM2_PCI */
|
||||
HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
|
||||
#endif /* PRISM2_PCI */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
|
||||
void *buf)
|
||||
{
|
||||
u16 page, offset;
|
||||
if (addr & 1 || len & 1)
|
||||
return -1;
|
||||
|
||||
page = addr >> 7;
|
||||
offset = addr & 0x7f;
|
||||
|
||||
HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
|
||||
HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
|
||||
|
||||
udelay(5);
|
||||
|
||||
#ifdef PRISM2_PCI
|
||||
{
|
||||
__le16 *pos = (__le16 *) buf;
|
||||
while (len > 0) {
|
||||
HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
#else /* PRISM2_PCI */
|
||||
HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
|
||||
#endif /* PRISM2_PCI */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int prism2_pda_ok(u8 *buf)
|
||||
{
|
||||
__le16 *pda = (__le16 *) buf;
|
||||
int pos;
|
||||
u16 len, pdr;
|
||||
|
||||
if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
|
||||
buf[3] == 0x00)
|
||||
return 0;
|
||||
|
||||
pos = 0;
|
||||
while (pos + 1 < PRISM2_PDA_SIZE / 2) {
|
||||
len = le16_to_cpu(pda[pos]);
|
||||
pdr = le16_to_cpu(pda[pos + 1]);
|
||||
if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
|
||||
return 0;
|
||||
|
||||
if (pdr == 0x0000 && len == 2) {
|
||||
/* PDA end found */
|
||||
return 1;
|
||||
}
|
||||
|
||||
pos += len + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define prism2_download_aux_dump_npages 65536
|
||||
|
||||
struct prism2_download_aux_dump {
|
||||
local_info_t *local;
|
||||
u16 page[0x80];
|
||||
};
|
||||
|
||||
static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct prism2_download_aux_dump *ctx = m->private;
|
||||
|
||||
hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page);
|
||||
seq_write(m, ctx->page, 0x80);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos)
|
||||
{
|
||||
struct prism2_download_aux_dump *ctx = m->private;
|
||||
prism2_enable_aux_port(ctx->local->dev, 1);
|
||||
if (*_pos >= prism2_download_aux_dump_npages)
|
||||
return NULL;
|
||||
return (void *)((unsigned long)*_pos + 1);
|
||||
}
|
||||
|
||||
static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos)
|
||||
{
|
||||
++*_pos;
|
||||
if (*_pos >= prism2_download_aux_dump_npages)
|
||||
return NULL;
|
||||
return (void *)((unsigned long)*_pos + 1);
|
||||
}
|
||||
|
||||
static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
struct prism2_download_aux_dump *ctx = m->private;
|
||||
prism2_enable_aux_port(ctx->local->dev, 0);
|
||||
}
|
||||
|
||||
static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
|
||||
.start = prism2_download_aux_dump_proc_start,
|
||||
.next = prism2_download_aux_dump_proc_next,
|
||||
.stop = prism2_download_aux_dump_proc_stop,
|
||||
.show = prism2_download_aux_dump_proc_show,
|
||||
};
|
||||
|
||||
static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops,
|
||||
sizeof(struct prism2_download_aux_dump));
|
||||
if (ret == 0) {
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = PDE_DATA(inode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_download_aux_dump_proc_fops = {
|
||||
.open = prism2_download_aux_dump_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
|
||||
|
||||
static u8 * prism2_read_pda(struct net_device *dev)
|
||||
{
|
||||
u8 *buf;
|
||||
int res, i, found = 0;
|
||||
#define NUM_PDA_ADDRS 4
|
||||
unsigned int pda_addr[NUM_PDA_ADDRS] = {
|
||||
0x7f0000 /* others than HFA3841 */,
|
||||
0x3f0000 /* HFA3841 */,
|
||||
0x390000 /* apparently used in older cards */,
|
||||
0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
|
||||
};
|
||||
|
||||
buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Note: wlan card should be in initial state (just after init cmd)
|
||||
* and no other operations should be performed concurrently. */
|
||||
|
||||
prism2_enable_aux_port(dev, 1);
|
||||
|
||||
for (i = 0; i < NUM_PDA_ADDRS; i++) {
|
||||
PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
|
||||
dev->name, pda_addr[i]);
|
||||
res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
|
||||
if (res)
|
||||
continue;
|
||||
if (res == 0 && prism2_pda_ok(buf)) {
|
||||
PDEBUG2(DEBUG_EXTRA2, ": OK\n");
|
||||
found = 1;
|
||||
break;
|
||||
} else {
|
||||
PDEBUG2(DEBUG_EXTRA2, ": failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
prism2_enable_aux_port(dev, 0);
|
||||
|
||||
if (!found) {
|
||||
printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
|
||||
kfree(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static int prism2_download_volatile(local_info_t *local,
|
||||
struct prism2_download_data *param)
|
||||
{
|
||||
struct net_device *dev = local->dev;
|
||||
int ret = 0, i;
|
||||
u16 param0, param1;
|
||||
|
||||
if (local->hw_downloading) {
|
||||
printk(KERN_WARNING "%s: Already downloading - aborting new "
|
||||
"request\n", dev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
local->hw_downloading = 1;
|
||||
if (local->pri_only) {
|
||||
hfa384x_disable_interrupts(dev);
|
||||
} else {
|
||||
prism2_hw_shutdown(dev, 0);
|
||||
|
||||
if (prism2_hw_init(dev, 0)) {
|
||||
printk(KERN_WARNING "%s: Could not initialize card for"
|
||||
" download\n", dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (prism2_enable_aux_port(dev, 1)) {
|
||||
printk(KERN_WARNING "%s: Could not enable AUX port\n",
|
||||
dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
param0 = param->start_addr & 0xffff;
|
||||
param1 = param->start_addr >> 16;
|
||||
|
||||
HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
|
||||
HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
|
||||
if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
|
||||
(HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
|
||||
param0)) {
|
||||
printk(KERN_WARNING "%s: Download command execution failed\n",
|
||||
dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < param->num_areas; i++) {
|
||||
PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
|
||||
dev->name, param->data[i].len, param->data[i].addr);
|
||||
if (hfa384x_to_aux(dev, param->data[i].addr,
|
||||
param->data[i].len, param->data[i].data)) {
|
||||
printk(KERN_WARNING "%s: RAM download at 0x%08x "
|
||||
"(len=%d) failed\n", dev->name,
|
||||
param->data[i].addr, param->data[i].len);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
|
||||
HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
|
||||
if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
|
||||
(HFA384X_PROGMODE_DISABLE << 8), param0)) {
|
||||
printk(KERN_WARNING "%s: Download command execution failed\n",
|
||||
dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
/* ProgMode disable causes the hardware to restart itself from the
|
||||
* given starting address. Give hw some time and ACK command just in
|
||||
* case restart did not happen. */
|
||||
mdelay(5);
|
||||
HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
|
||||
|
||||
if (prism2_enable_aux_port(dev, 0)) {
|
||||
printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
|
||||
dev->name);
|
||||
/* continue anyway.. restart should have taken care of this */
|
||||
}
|
||||
|
||||
mdelay(5);
|
||||
local->hw_downloading = 0;
|
||||
if (prism2_hw_config(dev, 2)) {
|
||||
printk(KERN_WARNING "%s: Card configuration after RAM "
|
||||
"download failed\n", dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
local->hw_downloading = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int prism2_enable_genesis(local_info_t *local, int hcr)
|
||||
{
|
||||
struct net_device *dev = local->dev;
|
||||
u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
|
||||
u8 readbuf[4];
|
||||
|
||||
printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
|
||||
dev->name, hcr);
|
||||
local->func->cor_sreset(local);
|
||||
hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
|
||||
local->func->genesis_reset(local, hcr);
|
||||
|
||||
/* Readback test */
|
||||
hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
|
||||
hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
|
||||
hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
|
||||
|
||||
if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
|
||||
printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
|
||||
hcr);
|
||||
return 0;
|
||||
} else {
|
||||
printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
|
||||
"write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
|
||||
hcr, initseq[0], initseq[1], initseq[2], initseq[3],
|
||||
readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int prism2_get_ram_size(local_info_t *local)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
|
||||
if (prism2_enable_genesis(local, 0x1f) == 0)
|
||||
ret = 8;
|
||||
else if (prism2_enable_genesis(local, 0x0f) == 0)
|
||||
ret = 16;
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
/* Disable genesis mode */
|
||||
local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int prism2_download_genesis(local_info_t *local,
|
||||
struct prism2_download_data *param)
|
||||
{
|
||||
struct net_device *dev = local->dev;
|
||||
int ram16 = 0, i;
|
||||
int ret = 0;
|
||||
|
||||
if (local->hw_downloading) {
|
||||
printk(KERN_WARNING "%s: Already downloading - aborting new "
|
||||
"request\n", dev->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!local->func->genesis_reset || !local->func->cor_sreset) {
|
||||
printk(KERN_INFO "%s: Genesis mode downloading not supported "
|
||||
"with this hwmodel\n", dev->name);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
local->hw_downloading = 1;
|
||||
|
||||
if (prism2_enable_aux_port(dev, 1)) {
|
||||
printk(KERN_DEBUG "%s: failed to enable AUX port\n",
|
||||
dev->name);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (local->sram_type == -1) {
|
||||
/* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
|
||||
if (prism2_enable_genesis(local, 0x1f) == 0) {
|
||||
ram16 = 0;
|
||||
PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
|
||||
"SRAM\n", dev->name);
|
||||
} else if (prism2_enable_genesis(local, 0x0f) == 0) {
|
||||
ram16 = 1;
|
||||
PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
|
||||
"SRAM\n", dev->name);
|
||||
} else {
|
||||
printk(KERN_DEBUG "%s: Could not initiate genesis "
|
||||
"mode\n", dev->name);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (prism2_enable_genesis(local, local->sram_type == 8 ?
|
||||
0x1f : 0x0f)) {
|
||||
printk(KERN_DEBUG "%s: Failed to set Genesis "
|
||||
"mode (sram_type=%d)\n", dev->name,
|
||||
local->sram_type);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
ram16 = local->sram_type != 8;
|
||||
}
|
||||
|
||||
for (i = 0; i < param->num_areas; i++) {
|
||||
PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
|
||||
dev->name, param->data[i].len, param->data[i].addr);
|
||||
if (hfa384x_to_aux(dev, param->data[i].addr,
|
||||
param->data[i].len, param->data[i].data)) {
|
||||
printk(KERN_WARNING "%s: RAM download at 0x%08x "
|
||||
"(len=%d) failed\n", dev->name,
|
||||
param->data[i].addr, param->data[i].len);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
|
||||
local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
|
||||
if (prism2_enable_aux_port(dev, 0)) {
|
||||
printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
|
||||
dev->name);
|
||||
}
|
||||
|
||||
mdelay(5);
|
||||
local->hw_downloading = 0;
|
||||
|
||||
PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
|
||||
/*
|
||||
* Make sure the INIT command does not generate a command completion
|
||||
* event by disabling interrupts.
|
||||
*/
|
||||
hfa384x_disable_interrupts(dev);
|
||||
if (prism2_hw_init(dev, 1)) {
|
||||
printk(KERN_DEBUG "%s: Initialization after genesis mode "
|
||||
"download failed\n", dev->name);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
|
||||
if (prism2_hw_init2(dev, 1)) {
|
||||
printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
|
||||
"download failed\n", dev->name);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
local->hw_downloading = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
|
||||
/* Note! Non-volatile downloading functionality has not yet been tested
|
||||
* thoroughly and it may corrupt flash image and effectively kill the card that
|
||||
* is being updated. You have been warned. */
|
||||
|
||||
static inline int prism2_download_block(struct net_device *dev,
|
||||
u32 addr, u8 *data,
|
||||
u32 bufaddr, int rest_len)
|
||||
{
|
||||
u16 param0, param1;
|
||||
int block_len;
|
||||
|
||||
block_len = rest_len < 4096 ? rest_len : 4096;
|
||||
|
||||
param0 = addr & 0xffff;
|
||||
param1 = addr >> 16;
|
||||
|
||||
HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
|
||||
HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
|
||||
|
||||
if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
|
||||
(HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
|
||||
param0)) {
|
||||
printk(KERN_WARNING "%s: Flash download command execution "
|
||||
"failed\n", dev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
|
||||
printk(KERN_WARNING "%s: flash download at 0x%08x "
|
||||
"(len=%d) failed\n", dev->name, addr, block_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
|
||||
HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
|
||||
if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
|
||||
(HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
|
||||
0)) {
|
||||
printk(KERN_WARNING "%s: Flash write command execution "
|
||||
"failed\n", dev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return block_len;
|
||||
}
|
||||
|
||||
|
||||
static int prism2_download_nonvolatile(local_info_t *local,
|
||||
struct prism2_download_data *dl)
|
||||
{
|
||||
struct net_device *dev = local->dev;
|
||||
int ret = 0, i;
|
||||
struct {
|
||||
__le16 page;
|
||||
__le16 offset;
|
||||
__le16 len;
|
||||
} dlbuffer;
|
||||
u32 bufaddr;
|
||||
|
||||
if (local->hw_downloading) {
|
||||
printk(KERN_WARNING "%s: Already downloading - aborting new "
|
||||
"request\n", dev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
|
||||
&dlbuffer, 6, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
printk(KERN_WARNING "%s: Could not read download buffer "
|
||||
"parameters\n", dev->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
|
||||
le16_to_cpu(dlbuffer.len),
|
||||
le16_to_cpu(dlbuffer.page),
|
||||
le16_to_cpu(dlbuffer.offset));
|
||||
|
||||
bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
|
||||
|
||||
local->hw_downloading = 1;
|
||||
|
||||
if (!local->pri_only) {
|
||||
prism2_hw_shutdown(dev, 0);
|
||||
|
||||
if (prism2_hw_init(dev, 0)) {
|
||||
printk(KERN_WARNING "%s: Could not initialize card for"
|
||||
" download\n", dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
hfa384x_disable_interrupts(dev);
|
||||
|
||||
if (prism2_enable_aux_port(dev, 1)) {
|
||||
printk(KERN_WARNING "%s: Could not enable AUX port\n",
|
||||
dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
|
||||
for (i = 0; i < dl->num_areas; i++) {
|
||||
int rest_len = dl->data[i].len;
|
||||
int data_off = 0;
|
||||
|
||||
while (rest_len > 0) {
|
||||
int block_len;
|
||||
|
||||
block_len = prism2_download_block(
|
||||
dev, dl->data[i].addr + data_off,
|
||||
dl->data[i].data + data_off, bufaddr,
|
||||
rest_len);
|
||||
|
||||
if (block_len < 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rest_len -= block_len;
|
||||
data_off += block_len;
|
||||
}
|
||||
}
|
||||
|
||||
HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
|
||||
HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
|
||||
if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
|
||||
(HFA384X_PROGMODE_DISABLE << 8), 0)) {
|
||||
printk(KERN_WARNING "%s: Download command execution failed\n",
|
||||
dev->name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prism2_enable_aux_port(dev, 0)) {
|
||||
printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
|
||||
dev->name);
|
||||
/* continue anyway.. restart should have taken care of this */
|
||||
}
|
||||
|
||||
mdelay(5);
|
||||
|
||||
local->func->hw_reset(dev);
|
||||
local->hw_downloading = 0;
|
||||
if (prism2_hw_config(dev, 2)) {
|
||||
printk(KERN_WARNING "%s: Card configuration after flash "
|
||||
"download failed\n", dev->name);
|
||||
ret = -1;
|
||||
} else {
|
||||
printk(KERN_INFO "%s: Card initialized successfully after "
|
||||
"flash download\n", dev->name);
|
||||
}
|
||||
|
||||
out:
|
||||
local->hw_downloading = 0;
|
||||
return ret;
|
||||
}
|
||||
#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
|
||||
|
||||
|
||||
static void prism2_download_free_data(struct prism2_download_data *dl)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dl == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < dl->num_areas; i++)
|
||||
kfree(dl->data[i].data);
|
||||
kfree(dl);
|
||||
}
|
||||
|
||||
|
||||
static int prism2_download(local_info_t *local,
|
||||
struct prism2_download_param *param)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
u32 total_len = 0;
|
||||
struct prism2_download_data *dl = NULL;
|
||||
|
||||
printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
|
||||
"num_areas=%d\n",
|
||||
param->dl_cmd, param->start_addr, param->num_areas);
|
||||
|
||||
if (param->num_areas > 100) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dl = kzalloc(sizeof(*dl) + param->num_areas *
|
||||
sizeof(struct prism2_download_data_area), GFP_KERNEL);
|
||||
if (dl == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
dl->dl_cmd = param->dl_cmd;
|
||||
dl->start_addr = param->start_addr;
|
||||
dl->num_areas = param->num_areas;
|
||||
for (i = 0; i < param->num_areas; i++) {
|
||||
PDEBUG(DEBUG_EXTRA2,
|
||||
" area %d: addr=0x%08x len=%d ptr=0x%p\n",
|
||||
i, param->data[i].addr, param->data[i].len,
|
||||
param->data[i].ptr);
|
||||
|
||||
dl->data[i].addr = param->data[i].addr;
|
||||
dl->data[i].len = param->data[i].len;
|
||||
|
||||
total_len += param->data[i].len;
|
||||
if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
|
||||
total_len > PRISM2_MAX_DOWNLOAD_LEN) {
|
||||
ret = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
|
||||
if (dl->data[i].data == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (copy_from_user(dl->data[i].data, param->data[i].ptr,
|
||||
param->data[i].len)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
switch (param->dl_cmd) {
|
||||
case PRISM2_DOWNLOAD_VOLATILE:
|
||||
case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
|
||||
ret = prism2_download_volatile(local, dl);
|
||||
break;
|
||||
case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
|
||||
case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
|
||||
ret = prism2_download_genesis(local, dl);
|
||||
break;
|
||||
case PRISM2_DOWNLOAD_NON_VOLATILE:
|
||||
#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
|
||||
ret = prism2_download_nonvolatile(local, dl);
|
||||
#else /* PRISM2_NON_VOLATILE_DOWNLOAD */
|
||||
printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
|
||||
local->dev->name);
|
||||
ret = -EOPNOTSUPP;
|
||||
#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
|
||||
break;
|
||||
default:
|
||||
printk(KERN_DEBUG "%s: unsupported download command %d\n",
|
||||
local->dev->name, param->dl_cmd);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret == 0 && dl &&
|
||||
param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
|
||||
prism2_download_free_data(local->dl_pri);
|
||||
local->dl_pri = dl;
|
||||
} else if (ret == 0 && dl &&
|
||||
param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
|
||||
prism2_download_free_data(local->dl_sec);
|
||||
local->dl_sec = dl;
|
||||
} else
|
||||
prism2_download_free_data(dl);
|
||||
|
||||
return ret;
|
||||
}
|
3424
drivers/net/wireless/intersil/hostap/hostap_hw.c
Normal file
3424
drivers/net/wireless/intersil/hostap/hostap_hw.c
Normal file
File diff suppressed because it is too large
Load Diff
507
drivers/net/wireless/intersil/hostap/hostap_info.c
Normal file
507
drivers/net/wireless/intersil/hostap/hostap_info.c
Normal file
@@ -0,0 +1,507 @@
|
||||
/* Host AP driver Info Frame processing (part of hostap.o module) */
|
||||
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include "hostap_wlan.h"
|
||||
#include "hostap.h"
|
||||
#include "hostap_ap.h"
|
||||
|
||||
/* Called only as a tasklet (software IRQ) */
|
||||
static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
|
||||
int left)
|
||||
{
|
||||
struct hfa384x_comm_tallies *tallies;
|
||||
|
||||
if (left < sizeof(struct hfa384x_comm_tallies)) {
|
||||
printk(KERN_DEBUG "%s: too short (len=%d) commtallies "
|
||||
"info frame\n", local->dev->name, left);
|
||||
return;
|
||||
}
|
||||
|
||||
tallies = (struct hfa384x_comm_tallies *) buf;
|
||||
#define ADD_COMM_TALLIES(name) \
|
||||
local->comm_tallies.name += le16_to_cpu(tallies->name)
|
||||
ADD_COMM_TALLIES(tx_unicast_frames);
|
||||
ADD_COMM_TALLIES(tx_multicast_frames);
|
||||
ADD_COMM_TALLIES(tx_fragments);
|
||||
ADD_COMM_TALLIES(tx_unicast_octets);
|
||||
ADD_COMM_TALLIES(tx_multicast_octets);
|
||||
ADD_COMM_TALLIES(tx_deferred_transmissions);
|
||||
ADD_COMM_TALLIES(tx_single_retry_frames);
|
||||
ADD_COMM_TALLIES(tx_multiple_retry_frames);
|
||||
ADD_COMM_TALLIES(tx_retry_limit_exceeded);
|
||||
ADD_COMM_TALLIES(tx_discards);
|
||||
ADD_COMM_TALLIES(rx_unicast_frames);
|
||||
ADD_COMM_TALLIES(rx_multicast_frames);
|
||||
ADD_COMM_TALLIES(rx_fragments);
|
||||
ADD_COMM_TALLIES(rx_unicast_octets);
|
||||
ADD_COMM_TALLIES(rx_multicast_octets);
|
||||
ADD_COMM_TALLIES(rx_fcs_errors);
|
||||
ADD_COMM_TALLIES(rx_discards_no_buffer);
|
||||
ADD_COMM_TALLIES(tx_discards_wrong_sa);
|
||||
ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
|
||||
ADD_COMM_TALLIES(rx_message_in_msg_fragments);
|
||||
ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
|
||||
#undef ADD_COMM_TALLIES
|
||||
}
|
||||
|
||||
|
||||
/* Called only as a tasklet (software IRQ) */
|
||||
static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf,
|
||||
int left)
|
||||
{
|
||||
struct hfa384x_comm_tallies32 *tallies;
|
||||
|
||||
if (left < sizeof(struct hfa384x_comm_tallies32)) {
|
||||
printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 "
|
||||
"info frame\n", local->dev->name, left);
|
||||
return;
|
||||
}
|
||||
|
||||
tallies = (struct hfa384x_comm_tallies32 *) buf;
|
||||
#define ADD_COMM_TALLIES(name) \
|
||||
local->comm_tallies.name += le32_to_cpu(tallies->name)
|
||||
ADD_COMM_TALLIES(tx_unicast_frames);
|
||||
ADD_COMM_TALLIES(tx_multicast_frames);
|
||||
ADD_COMM_TALLIES(tx_fragments);
|
||||
ADD_COMM_TALLIES(tx_unicast_octets);
|
||||
ADD_COMM_TALLIES(tx_multicast_octets);
|
||||
ADD_COMM_TALLIES(tx_deferred_transmissions);
|
||||
ADD_COMM_TALLIES(tx_single_retry_frames);
|
||||
ADD_COMM_TALLIES(tx_multiple_retry_frames);
|
||||
ADD_COMM_TALLIES(tx_retry_limit_exceeded);
|
||||
ADD_COMM_TALLIES(tx_discards);
|
||||
ADD_COMM_TALLIES(rx_unicast_frames);
|
||||
ADD_COMM_TALLIES(rx_multicast_frames);
|
||||
ADD_COMM_TALLIES(rx_fragments);
|
||||
ADD_COMM_TALLIES(rx_unicast_octets);
|
||||
ADD_COMM_TALLIES(rx_multicast_octets);
|
||||
ADD_COMM_TALLIES(rx_fcs_errors);
|
||||
ADD_COMM_TALLIES(rx_discards_no_buffer);
|
||||
ADD_COMM_TALLIES(tx_discards_wrong_sa);
|
||||
ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
|
||||
ADD_COMM_TALLIES(rx_message_in_msg_fragments);
|
||||
ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
|
||||
#undef ADD_COMM_TALLIES
|
||||
}
|
||||
|
||||
|
||||
/* Called only as a tasklet (software IRQ) */
|
||||
static void prism2_info_commtallies(local_info_t *local, unsigned char *buf,
|
||||
int left)
|
||||
{
|
||||
if (local->tallies32)
|
||||
prism2_info_commtallies32(local, buf, left);
|
||||
else
|
||||
prism2_info_commtallies16(local, buf, left);
|
||||
}
|
||||
|
||||
|
||||
#ifndef PRISM2_NO_STATION_MODES
|
||||
#ifndef PRISM2_NO_DEBUG
|
||||
static const char* hfa384x_linkstatus_str(u16 linkstatus)
|
||||
{
|
||||
switch (linkstatus) {
|
||||
case HFA384X_LINKSTATUS_CONNECTED:
|
||||
return "Connected";
|
||||
case HFA384X_LINKSTATUS_DISCONNECTED:
|
||||
return "Disconnected";
|
||||
case HFA384X_LINKSTATUS_AP_CHANGE:
|
||||
return "Access point change";
|
||||
case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE:
|
||||
return "Access point out of range";
|
||||
case HFA384X_LINKSTATUS_AP_IN_RANGE:
|
||||
return "Access point in range";
|
||||
case HFA384X_LINKSTATUS_ASSOC_FAILED:
|
||||
return "Association failed";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
#endif /* PRISM2_NO_DEBUG */
|
||||
|
||||
|
||||
/* Called only as a tasklet (software IRQ) */
|
||||
static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf,
|
||||
int left)
|
||||
{
|
||||
u16 val;
|
||||
int non_sta_mode;
|
||||
|
||||
/* Alloc new JoinRequests to occur since LinkStatus for the previous
|
||||
* has been received */
|
||||
local->last_join_time = 0;
|
||||
|
||||
if (left != 2) {
|
||||
printk(KERN_DEBUG "%s: invalid linkstatus info frame "
|
||||
"length %d\n", local->dev->name, left);
|
||||
return;
|
||||
}
|
||||
|
||||
non_sta_mode = local->iw_mode == IW_MODE_MASTER ||
|
||||
local->iw_mode == IW_MODE_REPEAT ||
|
||||
local->iw_mode == IW_MODE_MONITOR;
|
||||
|
||||
val = buf[0] | (buf[1] << 8);
|
||||
if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) {
|
||||
PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n",
|
||||
local->dev->name, val, hfa384x_linkstatus_str(val));
|
||||
}
|
||||
|
||||
if (non_sta_mode) {
|
||||
netif_carrier_on(local->dev);
|
||||
netif_carrier_on(local->ddev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get current BSSID later in scheduled task */
|
||||
set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info);
|
||||
local->prev_link_status = val;
|
||||
schedule_work(&local->info_queue);
|
||||
}
|
||||
|
||||
|
||||
static void prism2_host_roaming(local_info_t *local)
|
||||
{
|
||||
struct hfa384x_join_request req;
|
||||
struct net_device *dev = local->dev;
|
||||
struct hfa384x_hostscan_result *selected, *entry;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
if (local->last_join_time &&
|
||||
time_before(jiffies, local->last_join_time + 10 * HZ)) {
|
||||
PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been "
|
||||
"completed - waiting for it before issuing new one\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ScanResults are sorted: first ESS results in decreasing signal
|
||||
* quality then IBSS results in similar order.
|
||||
* Trivial roaming policy: just select the first entry.
|
||||
* This could probably be improved by adding hysteresis to limit
|
||||
* number of handoffs, etc.
|
||||
*
|
||||
* Could do periodic RID_SCANREQUEST or Inquire F101 to get new
|
||||
* ScanResults */
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
if (local->last_scan_results == NULL ||
|
||||
local->last_scan_results_count == 0) {
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
selected = &local->last_scan_results[0];
|
||||
|
||||
if (local->preferred_ap[0] || local->preferred_ap[1] ||
|
||||
local->preferred_ap[2] || local->preferred_ap[3] ||
|
||||
local->preferred_ap[4] || local->preferred_ap[5]) {
|
||||
/* Try to find preferred AP */
|
||||
PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n",
|
||||
dev->name, local->preferred_ap);
|
||||
for (i = 0; i < local->last_scan_results_count; i++) {
|
||||
entry = &local->last_scan_results[i];
|
||||
if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
|
||||
{
|
||||
PDEBUG(DEBUG_EXTRA, "%s: using preferred AP "
|
||||
"selection\n", dev->name);
|
||||
selected = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(req.bssid, selected->bssid, ETH_ALEN);
|
||||
req.channel = selected->chid;
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
|
||||
PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM"
|
||||
" channel=%d\n",
|
||||
dev->name, req.bssid, le16_to_cpu(req.channel));
|
||||
if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
|
||||
sizeof(req))) {
|
||||
printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
|
||||
}
|
||||
local->last_join_time = jiffies;
|
||||
}
|
||||
|
||||
|
||||
static void hostap_report_scan_complete(local_info_t *local)
|
||||
{
|
||||
union iwreq_data wrqu;
|
||||
|
||||
/* Inform user space about new scan results (just empty event,
|
||||
* SIOCGIWSCAN can be used to fetch data */
|
||||
wrqu.data.length = 0;
|
||||
wrqu.data.flags = 0;
|
||||
wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL);
|
||||
|
||||
/* Allow SIOCGIWSCAN handling to occur since we have received
|
||||
* scanning result */
|
||||
local->scan_timestamp = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Called only as a tasklet (software IRQ) */
|
||||
static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
|
||||
int left)
|
||||
{
|
||||
u16 *pos;
|
||||
int new_count, i;
|
||||
unsigned long flags;
|
||||
struct hfa384x_scan_result *res;
|
||||
struct hfa384x_hostscan_result *results, *prev;
|
||||
|
||||
if (left < 4) {
|
||||
printk(KERN_DEBUG "%s: invalid scanresult info frame "
|
||||
"length %d\n", local->dev->name, left);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = (u16 *) buf;
|
||||
pos++;
|
||||
pos++;
|
||||
left -= 4;
|
||||
|
||||
new_count = left / sizeof(struct hfa384x_scan_result);
|
||||
results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
|
||||
GFP_ATOMIC);
|
||||
if (results == NULL)
|
||||
return;
|
||||
|
||||
/* Convert to hostscan result format. */
|
||||
res = (struct hfa384x_scan_result *) pos;
|
||||
for (i = 0; i < new_count; i++) {
|
||||
memcpy(&results[i], &res[i],
|
||||
sizeof(struct hfa384x_scan_result));
|
||||
results[i].atim = 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
local->last_scan_type = PRISM2_SCAN;
|
||||
prev = local->last_scan_results;
|
||||
local->last_scan_results = results;
|
||||
local->last_scan_results_count = new_count;
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
kfree(prev);
|
||||
|
||||
hostap_report_scan_complete(local);
|
||||
|
||||
/* Perform rest of ScanResults handling later in scheduled task */
|
||||
set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info);
|
||||
schedule_work(&local->info_queue);
|
||||
}
|
||||
|
||||
|
||||
/* Called only as a tasklet (software IRQ) */
|
||||
static void prism2_info_hostscanresults(local_info_t *local,
|
||||
unsigned char *buf, int left)
|
||||
{
|
||||
int i, result_size, copy_len, new_count;
|
||||
struct hfa384x_hostscan_result *results, *prev;
|
||||
unsigned long flags;
|
||||
__le16 *pos;
|
||||
u8 *ptr;
|
||||
|
||||
wake_up_interruptible(&local->hostscan_wq);
|
||||
|
||||
if (left < 4) {
|
||||
printk(KERN_DEBUG "%s: invalid hostscanresult info frame "
|
||||
"length %d\n", local->dev->name, left);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = (__le16 *) buf;
|
||||
copy_len = result_size = le16_to_cpu(*pos);
|
||||
if (result_size == 0) {
|
||||
printk(KERN_DEBUG "%s: invalid result_size (0) in "
|
||||
"hostscanresults\n", local->dev->name);
|
||||
return;
|
||||
}
|
||||
if (copy_len > sizeof(struct hfa384x_hostscan_result))
|
||||
copy_len = sizeof(struct hfa384x_hostscan_result);
|
||||
|
||||
pos++;
|
||||
pos++;
|
||||
left -= 4;
|
||||
ptr = (u8 *) pos;
|
||||
|
||||
new_count = left / result_size;
|
||||
results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result),
|
||||
GFP_ATOMIC);
|
||||
if (results == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < new_count; i++) {
|
||||
memcpy(&results[i], ptr, copy_len);
|
||||
ptr += result_size;
|
||||
left -= result_size;
|
||||
}
|
||||
|
||||
if (left) {
|
||||
printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n",
|
||||
local->dev->name, left, result_size);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
local->last_scan_type = PRISM2_HOSTSCAN;
|
||||
prev = local->last_scan_results;
|
||||
local->last_scan_results = results;
|
||||
local->last_scan_results_count = new_count;
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
kfree(prev);
|
||||
|
||||
hostap_report_scan_complete(local);
|
||||
}
|
||||
#endif /* PRISM2_NO_STATION_MODES */
|
||||
|
||||
|
||||
/* Called only as a tasklet (software IRQ) */
|
||||
void hostap_info_process(local_info_t *local, struct sk_buff *skb)
|
||||
{
|
||||
struct hfa384x_info_frame *info;
|
||||
unsigned char *buf;
|
||||
int left;
|
||||
#ifndef PRISM2_NO_DEBUG
|
||||
int i;
|
||||
#endif /* PRISM2_NO_DEBUG */
|
||||
|
||||
info = (struct hfa384x_info_frame *) skb->data;
|
||||
buf = skb->data + sizeof(*info);
|
||||
left = skb->len - sizeof(*info);
|
||||
|
||||
switch (le16_to_cpu(info->type)) {
|
||||
case HFA384X_INFO_COMMTALLIES:
|
||||
prism2_info_commtallies(local, buf, left);
|
||||
break;
|
||||
|
||||
#ifndef PRISM2_NO_STATION_MODES
|
||||
case HFA384X_INFO_LINKSTATUS:
|
||||
prism2_info_linkstatus(local, buf, left);
|
||||
break;
|
||||
|
||||
case HFA384X_INFO_SCANRESULTS:
|
||||
prism2_info_scanresults(local, buf, left);
|
||||
break;
|
||||
|
||||
case HFA384X_INFO_HOSTSCANRESULTS:
|
||||
prism2_info_hostscanresults(local, buf, left);
|
||||
break;
|
||||
#endif /* PRISM2_NO_STATION_MODES */
|
||||
|
||||
#ifndef PRISM2_NO_DEBUG
|
||||
default:
|
||||
PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
|
||||
local->dev->name, le16_to_cpu(info->len),
|
||||
le16_to_cpu(info->type));
|
||||
PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
|
||||
for (i = 0; i < (left < 100 ? left : 100); i++)
|
||||
PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
|
||||
PDEBUG2(DEBUG_EXTRA, "\n");
|
||||
break;
|
||||
#endif /* PRISM2_NO_DEBUG */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef PRISM2_NO_STATION_MODES
|
||||
static void handle_info_queue_linkstatus(local_info_t *local)
|
||||
{
|
||||
int val = local->prev_link_status;
|
||||
int connected;
|
||||
union iwreq_data wrqu;
|
||||
|
||||
connected =
|
||||
val == HFA384X_LINKSTATUS_CONNECTED ||
|
||||
val == HFA384X_LINKSTATUS_AP_CHANGE ||
|
||||
val == HFA384X_LINKSTATUS_AP_IN_RANGE;
|
||||
|
||||
if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID,
|
||||
local->bssid, ETH_ALEN, 1) < 0) {
|
||||
printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
|
||||
"LinkStatus event\n", local->dev->name);
|
||||
} else {
|
||||
PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n",
|
||||
local->dev->name,
|
||||
(unsigned char *) local->bssid);
|
||||
if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
|
||||
hostap_add_sta(local->ap, local->bssid);
|
||||
}
|
||||
|
||||
/* Get BSSID if we have a valid AP address */
|
||||
if (connected) {
|
||||
netif_carrier_on(local->dev);
|
||||
netif_carrier_on(local->ddev);
|
||||
memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN);
|
||||
} else {
|
||||
netif_carrier_off(local->dev);
|
||||
netif_carrier_off(local->ddev);
|
||||
eth_zero_addr(wrqu.ap_addr.sa_data);
|
||||
}
|
||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
|
||||
/*
|
||||
* Filter out sequential disconnect events in order not to cause a
|
||||
* flood of SIOCGIWAP events that have a race condition with EAPOL
|
||||
* frames and can confuse wpa_supplicant about the current association
|
||||
* status.
|
||||
*/
|
||||
if (connected || local->prev_linkstatus_connected)
|
||||
wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
|
||||
local->prev_linkstatus_connected = connected;
|
||||
}
|
||||
|
||||
|
||||
static void handle_info_queue_scanresults(local_info_t *local)
|
||||
{
|
||||
if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
|
||||
prism2_host_roaming(local);
|
||||
|
||||
if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
|
||||
!is_zero_ether_addr(local->preferred_ap)) {
|
||||
/*
|
||||
* Firmware seems to be getting into odd state in host_roaming
|
||||
* mode 2 when hostscan is used without join command, so try
|
||||
* to fix this by re-joining the current AP. This does not
|
||||
* actually trigger a new association if the current AP is
|
||||
* still in the scan results.
|
||||
*/
|
||||
prism2_host_roaming(local);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Called only as scheduled task after receiving info frames (used to avoid
|
||||
* pending too much time in HW IRQ handler). */
|
||||
static void handle_info_queue(struct work_struct *work)
|
||||
{
|
||||
local_info_t *local = container_of(work, local_info_t, info_queue);
|
||||
|
||||
if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
|
||||
&local->pending_info))
|
||||
handle_info_queue_linkstatus(local);
|
||||
|
||||
if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS,
|
||||
&local->pending_info))
|
||||
handle_info_queue_scanresults(local);
|
||||
}
|
||||
#endif /* PRISM2_NO_STATION_MODES */
|
||||
|
||||
|
||||
void hostap_info_init(local_info_t *local)
|
||||
{
|
||||
skb_queue_head_init(&local->info_list);
|
||||
#ifndef PRISM2_NO_STATION_MODES
|
||||
INIT_WORK(&local->info_queue, handle_info_queue);
|
||||
#endif /* PRISM2_NO_STATION_MODES */
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(hostap_info_init);
|
||||
EXPORT_SYMBOL(hostap_info_process);
|
4054
drivers/net/wireless/intersil/hostap/hostap_ioctl.c
Normal file
4054
drivers/net/wireless/intersil/hostap/hostap_ioctl.c
Normal file
File diff suppressed because it is too large
Load Diff
1140
drivers/net/wireless/intersil/hostap/hostap_main.c
Normal file
1140
drivers/net/wireless/intersil/hostap/hostap_main.c
Normal file
File diff suppressed because it is too large
Load Diff
459
drivers/net/wireless/intersil/hostap/hostap_pci.c
Normal file
459
drivers/net/wireless/intersil/hostap/hostap_pci.c
Normal file
@@ -0,0 +1,459 @@
|
||||
#define PRISM2_PCI
|
||||
|
||||
/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
|
||||
* driver patches from Reyk Floeter <reyk@vantronix.net> and
|
||||
* Andy Warner <andyw@pobox.com> */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "hostap_wlan.h"
|
||||
|
||||
|
||||
static char *dev_info = "hostap_pci";
|
||||
|
||||
|
||||
MODULE_AUTHOR("Jouni Malinen");
|
||||
MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
|
||||
"PCI cards.");
|
||||
MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
/* struct local_info::hw_priv */
|
||||
struct hostap_pci_priv {
|
||||
void __iomem *mem_start;
|
||||
};
|
||||
|
||||
|
||||
/* FIX: do we need mb/wmb/rmb with memory operations? */
|
||||
|
||||
|
||||
static const struct pci_device_id prism2_pci_id_table[] = {
|
||||
/* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
|
||||
{ 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
|
||||
/* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
|
||||
{ 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
|
||||
/* Samsung MagicLAN SWL-2210P */
|
||||
{ 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
#ifdef PRISM2_IO_DEBUG
|
||||
|
||||
static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
hw_priv = local->hw_priv;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
|
||||
writeb(v, hw_priv->mem_start + a);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
u8 v;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
hw_priv = local->hw_priv;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
v = readb(hw_priv->mem_start + a);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
hw_priv = local->hw_priv;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
|
||||
writew(v, hw_priv->mem_start + a);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
u16 v;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
hw_priv = local->hw_priv;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
v = readw(hw_priv->mem_start + a);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
return v;
|
||||
}
|
||||
|
||||
#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
|
||||
#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
|
||||
#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
|
||||
#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
|
||||
#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v)))
|
||||
#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a)))
|
||||
|
||||
#else /* PRISM2_IO_DEBUG */
|
||||
|
||||
static inline void hfa384x_outb(struct net_device *dev, int a, u8 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
iface = netdev_priv(dev);
|
||||
hw_priv = iface->local->hw_priv;
|
||||
writeb(v, hw_priv->mem_start + a);
|
||||
}
|
||||
|
||||
static inline u8 hfa384x_inb(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
iface = netdev_priv(dev);
|
||||
hw_priv = iface->local->hw_priv;
|
||||
return readb(hw_priv->mem_start + a);
|
||||
}
|
||||
|
||||
static inline void hfa384x_outw(struct net_device *dev, int a, u16 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
iface = netdev_priv(dev);
|
||||
hw_priv = iface->local->hw_priv;
|
||||
writew(v, hw_priv->mem_start + a);
|
||||
}
|
||||
|
||||
static inline u16 hfa384x_inw(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
iface = netdev_priv(dev);
|
||||
hw_priv = iface->local->hw_priv;
|
||||
return readw(hw_priv->mem_start + a);
|
||||
}
|
||||
|
||||
#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v))
|
||||
#define HFA384X_INB(a) hfa384x_inb(dev, (a))
|
||||
#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
|
||||
#define HFA384X_INW(a) hfa384x_inw(dev, (a))
|
||||
#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v)))
|
||||
#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a)))
|
||||
|
||||
#endif /* PRISM2_IO_DEBUG */
|
||||
|
||||
|
||||
static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
|
||||
int len)
|
||||
{
|
||||
u16 d_off;
|
||||
__le16 *pos;
|
||||
|
||||
d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
|
||||
pos = (__le16 *) buf;
|
||||
|
||||
for ( ; len > 1; len -= 2)
|
||||
*pos++ = HFA384X_INW_DATA(d_off);
|
||||
|
||||
if (len & 1)
|
||||
*((char *) pos) = HFA384X_INB(d_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
|
||||
{
|
||||
u16 d_off;
|
||||
__le16 *pos;
|
||||
|
||||
d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
|
||||
pos = (__le16 *) buf;
|
||||
|
||||
for ( ; len > 1; len -= 2)
|
||||
HFA384X_OUTW_DATA(*pos++, d_off);
|
||||
|
||||
if (len & 1)
|
||||
HFA384X_OUTB(*((char *) pos), d_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FIX: This might change at some point.. */
|
||||
#include "hostap_hw.c"
|
||||
|
||||
static void prism2_pci_cor_sreset(local_info_t *local)
|
||||
{
|
||||
struct net_device *dev = local->dev;
|
||||
u16 reg;
|
||||
|
||||
reg = HFA384X_INB(HFA384X_PCICOR_OFF);
|
||||
printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg);
|
||||
|
||||
/* linux-wlan-ng uses extremely long hold and settle times for
|
||||
* COR sreset. A comment in the driver code mentions that the long
|
||||
* delays appear to be necessary. However, at least IBM 22P6901 seems
|
||||
* to work fine with shorter delays.
|
||||
*
|
||||
* Longer delays can be configured by uncommenting following line: */
|
||||
/* #define PRISM2_PCI_USE_LONG_DELAYS */
|
||||
|
||||
#ifdef PRISM2_PCI_USE_LONG_DELAYS
|
||||
int i;
|
||||
|
||||
HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
|
||||
mdelay(250);
|
||||
|
||||
HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
|
||||
mdelay(500);
|
||||
|
||||
/* Wait for f/w to complete initialization (CMD:BUSY == 0) */
|
||||
i = 2000000 / 10;
|
||||
while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
|
||||
udelay(10);
|
||||
|
||||
#else /* PRISM2_PCI_USE_LONG_DELAYS */
|
||||
|
||||
HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
|
||||
mdelay(2);
|
||||
HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
|
||||
mdelay(2);
|
||||
|
||||
#endif /* PRISM2_PCI_USE_LONG_DELAYS */
|
||||
|
||||
if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
|
||||
printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
|
||||
{
|
||||
struct net_device *dev = local->dev;
|
||||
|
||||
HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
|
||||
mdelay(10);
|
||||
HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
|
||||
mdelay(10);
|
||||
HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
|
||||
static struct prism2_helper_functions prism2_pci_funcs =
|
||||
{
|
||||
.card_present = NULL,
|
||||
.cor_sreset = prism2_pci_cor_sreset,
|
||||
.genesis_reset = prism2_pci_genesis_reset,
|
||||
.hw_type = HOSTAP_HW_PCI,
|
||||
};
|
||||
|
||||
|
||||
static int prism2_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned long phymem;
|
||||
void __iomem *mem = NULL;
|
||||
local_info_t *local = NULL;
|
||||
struct net_device *dev = NULL;
|
||||
static int cards_found /* = 0 */;
|
||||
int irq_registered = 0;
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
|
||||
hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
|
||||
if (hw_priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
goto err_out_free;
|
||||
|
||||
phymem = pci_resource_start(pdev, 0);
|
||||
|
||||
if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
|
||||
printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
|
||||
goto err_out_disable;
|
||||
}
|
||||
|
||||
mem = pci_ioremap_bar(pdev, 0);
|
||||
if (mem == NULL) {
|
||||
printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev = prism2_init_local_data(&prism2_pci_funcs, cards_found,
|
||||
&pdev->dev);
|
||||
if (dev == NULL)
|
||||
goto fail;
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
local->hw_priv = hw_priv;
|
||||
cards_found++;
|
||||
|
||||
dev->irq = pdev->irq;
|
||||
hw_priv->mem_start = mem;
|
||||
dev->base_addr = (unsigned long) mem;
|
||||
|
||||
prism2_pci_cor_sreset(local);
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
|
||||
dev)) {
|
||||
printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
|
||||
goto fail;
|
||||
} else
|
||||
irq_registered = 1;
|
||||
|
||||
if (!local->pri_only && prism2_hw_config(dev, 1)) {
|
||||
printk(KERN_DEBUG "%s: hardware initialization failed\n",
|
||||
dev_info);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
|
||||
"mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
|
||||
|
||||
return hostap_hw_ready(dev);
|
||||
|
||||
fail:
|
||||
if (irq_registered && dev)
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
if (mem)
|
||||
iounmap(mem);
|
||||
|
||||
release_mem_region(phymem, pci_resource_len(pdev, 0));
|
||||
|
||||
err_out_disable:
|
||||
pci_disable_device(pdev);
|
||||
prism2_free_local_data(dev);
|
||||
|
||||
err_out_free:
|
||||
kfree(hw_priv);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
static void prism2_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct hostap_interface *iface;
|
||||
void __iomem *mem_start;
|
||||
struct hostap_pci_priv *hw_priv;
|
||||
|
||||
dev = pci_get_drvdata(pdev);
|
||||
iface = netdev_priv(dev);
|
||||
hw_priv = iface->local->hw_priv;
|
||||
|
||||
/* Reset the hardware, and ensure interrupts are disabled. */
|
||||
prism2_pci_cor_sreset(iface->local);
|
||||
hfa384x_disable_interrupts(dev);
|
||||
|
||||
if (dev->irq)
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
mem_start = hw_priv->mem_start;
|
||||
prism2_free_local_data(dev);
|
||||
kfree(hw_priv);
|
||||
|
||||
iounmap(mem_start);
|
||||
|
||||
release_mem_region(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
|
||||
if (netif_running(dev)) {
|
||||
netif_stop_queue(dev);
|
||||
netif_device_detach(dev);
|
||||
}
|
||||
prism2_suspend(dev);
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prism2_pci_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
int err;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
|
||||
dev->name);
|
||||
return err;
|
||||
}
|
||||
pci_restore_state(pdev);
|
||||
prism2_hw_config(dev, 0);
|
||||
if (netif_running(dev)) {
|
||||
netif_device_attach(dev);
|
||||
netif_start_queue(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
|
||||
|
||||
static struct pci_driver prism2_pci_driver = {
|
||||
.name = "hostap_pci",
|
||||
.id_table = prism2_pci_id_table,
|
||||
.probe = prism2_pci_probe,
|
||||
.remove = prism2_pci_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = prism2_pci_suspend,
|
||||
.resume = prism2_pci_resume,
|
||||
#endif /* CONFIG_PM */
|
||||
};
|
||||
|
||||
module_pci_driver(prism2_pci_driver);
|
618
drivers/net/wireless/intersil/hostap/hostap_plx.c
Normal file
618
drivers/net/wireless/intersil/hostap/hostap_plx.c
Normal file
@@ -0,0 +1,618 @@
|
||||
#define PRISM2_PLX
|
||||
|
||||
/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
|
||||
* based on:
|
||||
* - Host AP driver patch from james@madingley.org
|
||||
* - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "hostap_wlan.h"
|
||||
|
||||
|
||||
static char *dev_info = "hostap_plx";
|
||||
|
||||
|
||||
MODULE_AUTHOR("Jouni Malinen");
|
||||
MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
|
||||
"cards (PLX).");
|
||||
MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static int ignore_cis;
|
||||
module_param(ignore_cis, int, 0444);
|
||||
MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
|
||||
|
||||
|
||||
/* struct local_info::hw_priv */
|
||||
struct hostap_plx_priv {
|
||||
void __iomem *attr_mem;
|
||||
unsigned int cor_offset;
|
||||
};
|
||||
|
||||
|
||||
#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
|
||||
#define COR_SRESET 0x80
|
||||
#define COR_LEVLREQ 0x40
|
||||
#define COR_ENABLE_FUNC 0x01
|
||||
/* PCI Configuration Registers */
|
||||
#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */
|
||||
/* Local Configuration Registers */
|
||||
#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */
|
||||
#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
|
||||
#define PLX_CNTRL 0x50
|
||||
#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
|
||||
|
||||
|
||||
#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
|
||||
|
||||
static const struct pci_device_id prism2_plx_id_table[] = {
|
||||
PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
|
||||
PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
|
||||
PLXDEV(0x126c, 0x8030, "Nortel emobility"),
|
||||
PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
|
||||
PLXDEV(0x1385, 0x4100, "Netgear MA301"),
|
||||
PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
|
||||
PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
|
||||
PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
|
||||
PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
|
||||
PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
|
||||
PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
|
||||
PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
|
||||
PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
|
||||
PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
|
||||
* is not listed here, you will need to add it here to get the driver
|
||||
* initialized. */
|
||||
static struct prism2_plx_manfid {
|
||||
u16 manfid1, manfid2;
|
||||
} prism2_plx_known_manfids[] = {
|
||||
{ 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
|
||||
{ 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
|
||||
{ 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
|
||||
{ 0x0126, 0x8000 } /* Proxim RangeLAN */,
|
||||
{ 0x0138, 0x0002 } /* Compaq WL100 */,
|
||||
{ 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
|
||||
{ 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
|
||||
{ 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
|
||||
{ 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
|
||||
{ 0x028a, 0x0002 } /* D-Link DRC-650 */,
|
||||
{ 0x0250, 0x0002 } /* Samsung SWL2000-N */,
|
||||
{ 0xc250, 0x0002 } /* EMTAC A2424i */,
|
||||
{ 0xd601, 0x0002 } /* Z-Com XI300 */,
|
||||
{ 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
|
||||
{ 0, 0}
|
||||
};
|
||||
|
||||
|
||||
#ifdef PRISM2_IO_DEBUG
|
||||
|
||||
static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
|
||||
outb(v, dev->base_addr + a);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
u8 v;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
v = inb(dev->base_addr + a);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
|
||||
outw(v, dev->base_addr + a);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
u16 v;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
v = inw(dev->base_addr + a);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
|
||||
u8 *buf, int wc)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
|
||||
outsw(dev->base_addr + a, buf, wc);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
static inline void hfa384x_insw_debug(struct net_device *dev, int a,
|
||||
u8 *buf, int wc)
|
||||
{
|
||||
struct hostap_interface *iface;
|
||||
local_info_t *local;
|
||||
unsigned long flags;
|
||||
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
|
||||
spin_lock_irqsave(&local->lock, flags);
|
||||
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
|
||||
insw(dev->base_addr + a, buf, wc);
|
||||
spin_unlock_irqrestore(&local->lock, flags);
|
||||
}
|
||||
|
||||
#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
|
||||
#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
|
||||
#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
|
||||
#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
|
||||
#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
|
||||
#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
|
||||
|
||||
#else /* PRISM2_IO_DEBUG */
|
||||
|
||||
#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
|
||||
#define HFA384X_INB(a) inb(dev->base_addr + (a))
|
||||
#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
|
||||
#define HFA384X_INW(a) inw(dev->base_addr + (a))
|
||||
#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
|
||||
#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
|
||||
|
||||
#endif /* PRISM2_IO_DEBUG */
|
||||
|
||||
|
||||
static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
|
||||
int len)
|
||||
{
|
||||
u16 d_off;
|
||||
u16 *pos;
|
||||
|
||||
d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
|
||||
pos = (u16 *) buf;
|
||||
|
||||
if (len / 2)
|
||||
HFA384X_INSW(d_off, buf, len / 2);
|
||||
pos += len / 2;
|
||||
|
||||
if (len & 1)
|
||||
*((char *) pos) = HFA384X_INB(d_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
|
||||
{
|
||||
u16 d_off;
|
||||
u16 *pos;
|
||||
|
||||
d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
|
||||
pos = (u16 *) buf;
|
||||
|
||||
if (len / 2)
|
||||
HFA384X_OUTSW(d_off, buf, len / 2);
|
||||
pos += len / 2;
|
||||
|
||||
if (len & 1)
|
||||
HFA384X_OUTB(*((char *) pos), d_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FIX: This might change at some point.. */
|
||||
#include "hostap_hw.c"
|
||||
|
||||
|
||||
static void prism2_plx_cor_sreset(local_info_t *local)
|
||||
{
|
||||
unsigned char corsave;
|
||||
struct hostap_plx_priv *hw_priv = local->hw_priv;
|
||||
|
||||
printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
|
||||
dev_info);
|
||||
|
||||
/* Set sreset bit of COR and clear it after hold time */
|
||||
|
||||
if (hw_priv->attr_mem == NULL) {
|
||||
/* TMD7160 - COR at card's first I/O addr */
|
||||
corsave = inb(hw_priv->cor_offset);
|
||||
outb(corsave | COR_SRESET, hw_priv->cor_offset);
|
||||
mdelay(2);
|
||||
outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
|
||||
mdelay(2);
|
||||
} else {
|
||||
/* PLX9052 */
|
||||
corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
|
||||
writeb(corsave | COR_SRESET,
|
||||
hw_priv->attr_mem + hw_priv->cor_offset);
|
||||
mdelay(2);
|
||||
writeb(corsave & ~COR_SRESET,
|
||||
hw_priv->attr_mem + hw_priv->cor_offset);
|
||||
mdelay(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
|
||||
{
|
||||
unsigned char corsave;
|
||||
struct hostap_plx_priv *hw_priv = local->hw_priv;
|
||||
|
||||
if (hw_priv->attr_mem == NULL) {
|
||||
/* TMD7160 - COR at card's first I/O addr */
|
||||
corsave = inb(hw_priv->cor_offset);
|
||||
outb(corsave | COR_SRESET, hw_priv->cor_offset);
|
||||
mdelay(10);
|
||||
outb(hcr, hw_priv->cor_offset + 2);
|
||||
mdelay(10);
|
||||
outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
|
||||
mdelay(10);
|
||||
} else {
|
||||
/* PLX9052 */
|
||||
corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
|
||||
writeb(corsave | COR_SRESET,
|
||||
hw_priv->attr_mem + hw_priv->cor_offset);
|
||||
mdelay(10);
|
||||
writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
|
||||
mdelay(10);
|
||||
writeb(corsave & ~COR_SRESET,
|
||||
hw_priv->attr_mem + hw_priv->cor_offset);
|
||||
mdelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct prism2_helper_functions prism2_plx_funcs =
|
||||
{
|
||||
.card_present = NULL,
|
||||
.cor_sreset = prism2_plx_cor_sreset,
|
||||
.genesis_reset = prism2_plx_genesis_reset,
|
||||
.hw_type = HOSTAP_HW_PLX,
|
||||
};
|
||||
|
||||
|
||||
static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
|
||||
unsigned int *cor_offset,
|
||||
unsigned int *cor_index)
|
||||
{
|
||||
#define CISTPL_CONFIG 0x1A
|
||||
#define CISTPL_MANFID 0x20
|
||||
#define CISTPL_END 0xFF
|
||||
#define CIS_MAX_LEN 256
|
||||
u8 *cis;
|
||||
int i, pos;
|
||||
unsigned int rmsz, rasz, manfid1, manfid2;
|
||||
struct prism2_plx_manfid *manfid;
|
||||
|
||||
cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
|
||||
if (cis == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* read CIS; it is in even offsets in the beginning of attr_mem */
|
||||
for (i = 0; i < CIS_MAX_LEN; i++)
|
||||
cis[i] = readb(attr_mem + 2 * i);
|
||||
printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n",
|
||||
dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]);
|
||||
|
||||
/* set reasonable defaults for Prism2 cards just in case CIS parsing
|
||||
* fails */
|
||||
*cor_offset = 0x3e0;
|
||||
*cor_index = 0x01;
|
||||
manfid1 = manfid2 = 0;
|
||||
|
||||
pos = 0;
|
||||
while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
|
||||
if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
|
||||
goto cis_error;
|
||||
|
||||
switch (cis[pos]) {
|
||||
case CISTPL_CONFIG:
|
||||
if (cis[pos + 1] < 2)
|
||||
goto cis_error;
|
||||
rmsz = (cis[pos + 2] & 0x3c) >> 2;
|
||||
rasz = cis[pos + 2] & 0x03;
|
||||
if (4 + rasz + rmsz > cis[pos + 1])
|
||||
goto cis_error;
|
||||
*cor_index = cis[pos + 3] & 0x3F;
|
||||
*cor_offset = 0;
|
||||
for (i = 0; i <= rasz; i++)
|
||||
*cor_offset += cis[pos + 4 + i] << (8 * i);
|
||||
printk(KERN_DEBUG "%s: cor_index=0x%x "
|
||||
"cor_offset=0x%x\n", dev_info,
|
||||
*cor_index, *cor_offset);
|
||||
if (*cor_offset > attr_len) {
|
||||
printk(KERN_ERR "%s: COR offset not within "
|
||||
"attr_mem\n", dev_info);
|
||||
kfree(cis);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case CISTPL_MANFID:
|
||||
if (cis[pos + 1] < 4)
|
||||
goto cis_error;
|
||||
manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
|
||||
manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
|
||||
printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
|
||||
dev_info, manfid1, manfid2);
|
||||
break;
|
||||
}
|
||||
|
||||
pos += cis[pos + 1] + 2;
|
||||
}
|
||||
|
||||
if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
|
||||
goto cis_error;
|
||||
|
||||
for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
|
||||
if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
|
||||
kfree(cis);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
|
||||
" not supported card\n", dev_info, manfid1, manfid2);
|
||||
goto fail;
|
||||
|
||||
cis_error:
|
||||
printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
|
||||
|
||||
fail:
|
||||
kfree(cis);
|
||||
if (ignore_cis) {
|
||||
printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
|
||||
"errors during CIS verification\n", dev_info);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int prism2_plx_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned int pccard_ioaddr, plx_ioaddr;
|
||||
unsigned long pccard_attr_mem;
|
||||
unsigned int pccard_attr_len;
|
||||
void __iomem *attr_mem = NULL;
|
||||
unsigned int cor_offset = 0, cor_index = 0;
|
||||
u32 reg;
|
||||
local_info_t *local = NULL;
|
||||
struct net_device *dev = NULL;
|
||||
struct hostap_interface *iface;
|
||||
static int cards_found /* = 0 */;
|
||||
int irq_registered = 0;
|
||||
int tmd7160;
|
||||
struct hostap_plx_priv *hw_priv;
|
||||
|
||||
hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
|
||||
if (hw_priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
goto err_out_free;
|
||||
|
||||
/* National Datacomm NCP130 based on TMD7160, not PLX9052. */
|
||||
tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
|
||||
|
||||
plx_ioaddr = pci_resource_start(pdev, 1);
|
||||
pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
|
||||
|
||||
if (tmd7160) {
|
||||
/* TMD7160 */
|
||||
attr_mem = NULL; /* no access to PC Card attribute memory */
|
||||
|
||||
printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
|
||||
"irq=%d, pccard_io=0x%x\n",
|
||||
plx_ioaddr, pdev->irq, pccard_ioaddr);
|
||||
|
||||
cor_offset = plx_ioaddr;
|
||||
cor_index = 0x04;
|
||||
|
||||
outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
|
||||
mdelay(1);
|
||||
reg = inb(plx_ioaddr);
|
||||
if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
|
||||
printk(KERN_ERR "%s: Error setting COR (expected="
|
||||
"0x%02x, was=0x%02x)\n", dev_info,
|
||||
cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
/* PLX9052 */
|
||||
pccard_attr_mem = pci_resource_start(pdev, 2);
|
||||
pccard_attr_len = pci_resource_len(pdev, 2);
|
||||
if (pccard_attr_len < PLX_MIN_ATTR_LEN)
|
||||
goto fail;
|
||||
|
||||
|
||||
attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
|
||||
if (attr_mem == NULL) {
|
||||
printk(KERN_ERR "%s: cannot remap attr_mem\n",
|
||||
dev_info);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
|
||||
"mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
|
||||
pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
|
||||
|
||||
if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
|
||||
&cor_offset, &cor_index)) {
|
||||
printk(KERN_INFO "Unknown PC Card CIS - not a "
|
||||
"Prism2/2.5 card?\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
|
||||
"adapter\n");
|
||||
|
||||
/* Write COR to enable PC Card */
|
||||
writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
|
||||
attr_mem + cor_offset);
|
||||
|
||||
/* Enable PCI interrupts if they are not already enabled */
|
||||
reg = inl(plx_ioaddr + PLX_INTCSR);
|
||||
printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
|
||||
if (!(reg & PLX_INTCSR_PCI_INTEN)) {
|
||||
outl(reg | PLX_INTCSR_PCI_INTEN,
|
||||
plx_ioaddr + PLX_INTCSR);
|
||||
if (!(inl(plx_ioaddr + PLX_INTCSR) &
|
||||
PLX_INTCSR_PCI_INTEN)) {
|
||||
printk(KERN_WARNING "%s: Could not enable "
|
||||
"Local Interrupts\n", dev_info);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
reg = inl(plx_ioaddr + PLX_CNTRL);
|
||||
printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
|
||||
"present=%d)\n",
|
||||
reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
|
||||
/* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
|
||||
* not present; but are there really such cards in use(?) */
|
||||
}
|
||||
|
||||
dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
|
||||
&pdev->dev);
|
||||
if (dev == NULL)
|
||||
goto fail;
|
||||
iface = netdev_priv(dev);
|
||||
local = iface->local;
|
||||
local->hw_priv = hw_priv;
|
||||
cards_found++;
|
||||
|
||||
dev->irq = pdev->irq;
|
||||
dev->base_addr = pccard_ioaddr;
|
||||
hw_priv->attr_mem = attr_mem;
|
||||
hw_priv->cor_offset = cor_offset;
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
|
||||
dev)) {
|
||||
printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
|
||||
goto fail;
|
||||
} else
|
||||
irq_registered = 1;
|
||||
|
||||
if (prism2_hw_config(dev, 1)) {
|
||||
printk(KERN_DEBUG "%s: hardware initialization failed\n",
|
||||
dev_info);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return hostap_hw_ready(dev);
|
||||
|
||||
fail:
|
||||
if (irq_registered && dev)
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
if (attr_mem)
|
||||
iounmap(attr_mem);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
prism2_free_local_data(dev);
|
||||
|
||||
err_out_free:
|
||||
kfree(hw_priv);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
static void prism2_plx_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct hostap_interface *iface;
|
||||
struct hostap_plx_priv *hw_priv;
|
||||
|
||||
dev = pci_get_drvdata(pdev);
|
||||
iface = netdev_priv(dev);
|
||||
hw_priv = iface->local->hw_priv;
|
||||
|
||||
/* Reset the hardware, and ensure interrupts are disabled. */
|
||||
prism2_plx_cor_sreset(iface->local);
|
||||
hfa384x_disable_interrupts(dev);
|
||||
|
||||
if (hw_priv->attr_mem)
|
||||
iounmap(hw_priv->attr_mem);
|
||||
if (dev->irq)
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
prism2_free_local_data(dev);
|
||||
kfree(hw_priv);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
|
||||
|
||||
static struct pci_driver prism2_plx_driver = {
|
||||
.name = "hostap_plx",
|
||||
.id_table = prism2_plx_id_table,
|
||||
.probe = prism2_plx_probe,
|
||||
.remove = prism2_plx_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(prism2_plx_driver);
|
499
drivers/net/wireless/intersil/hostap/hostap_proc.c
Normal file
499
drivers/net/wireless/intersil/hostap/hostap_proc.c
Normal file
@@ -0,0 +1,499 @@
|
||||
/* /proc routines for Host AP driver */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/export.h>
|
||||
#include <net/lib80211.h>
|
||||
|
||||
#include "hostap_wlan.h"
|
||||
#include "hostap.h"
|
||||
|
||||
#define PROC_LIMIT (PAGE_SIZE - 80)
|
||||
|
||||
|
||||
#ifndef PRISM2_NO_PROCFS_DEBUG
|
||||
static int prism2_debug_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
int i;
|
||||
|
||||
seq_printf(m, "next_txfid=%d next_alloc=%d\n",
|
||||
local->next_txfid, local->next_alloc);
|
||||
for (i = 0; i < PRISM2_TXFID_COUNT; i++)
|
||||
seq_printf(m, "FID: tx=%04X intransmit=%04X\n",
|
||||
local->txfid[i], local->intransmitfid[i]);
|
||||
seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control);
|
||||
seq_printf(m, "beacon_int=%d\n", local->beacon_int);
|
||||
seq_printf(m, "dtim_period=%d\n", local->dtim_period);
|
||||
seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections);
|
||||
seq_printf(m, "dev_enabled=%d\n", local->dev_enabled);
|
||||
seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
|
||||
for (i = 0; i < WEP_KEYS; i++) {
|
||||
if (local->crypt_info.crypt[i] &&
|
||||
local->crypt_info.crypt[i]->ops) {
|
||||
seq_printf(m, "crypt[%d]=%s\n", i,
|
||||
local->crypt_info.crypt[i]->ops->name);
|
||||
}
|
||||
}
|
||||
seq_printf(m, "pri_only=%d\n", local->pri_only);
|
||||
seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
|
||||
seq_printf(m, "sram_type=%d\n", local->sram_type);
|
||||
seq_printf(m, "no_pri=%d\n", local->no_pri);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prism2_debug_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, prism2_debug_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_debug_proc_fops = {
|
||||
.open = prism2_debug_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif /* PRISM2_NO_PROCFS_DEBUG */
|
||||
|
||||
|
||||
static int prism2_stats_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
struct comm_tallies_sums *sums = &local->comm_tallies;
|
||||
|
||||
seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
|
||||
seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
|
||||
seq_printf(m, "TxFragments=%u\n", sums->tx_fragments);
|
||||
seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
|
||||
seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
|
||||
seq_printf(m, "TxDeferredTransmissions=%u\n",
|
||||
sums->tx_deferred_transmissions);
|
||||
seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames);
|
||||
seq_printf(m, "TxMultipleRetryFrames=%u\n",
|
||||
sums->tx_multiple_retry_frames);
|
||||
seq_printf(m, "TxRetryLimitExceeded=%u\n",
|
||||
sums->tx_retry_limit_exceeded);
|
||||
seq_printf(m, "TxDiscards=%u\n", sums->tx_discards);
|
||||
seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
|
||||
seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
|
||||
seq_printf(m, "RxFragments=%u\n", sums->rx_fragments);
|
||||
seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
|
||||
seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
|
||||
seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
|
||||
seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer);
|
||||
seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
|
||||
seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n",
|
||||
sums->rx_discards_wep_undecryptable);
|
||||
seq_printf(m, "RxMessageInMsgFragments=%u\n",
|
||||
sums->rx_message_in_msg_fragments);
|
||||
seq_printf(m, "RxMessageInBadMsgFragments=%u\n",
|
||||
sums->rx_message_in_bad_msg_fragments);
|
||||
/* FIX: this may grow too long for one page(?) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prism2_stats_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, prism2_stats_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_stats_proc_fops = {
|
||||
.open = prism2_stats_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
|
||||
static int prism2_wds_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct list_head *ptr = v;
|
||||
struct hostap_interface *iface;
|
||||
|
||||
iface = list_entry(ptr, struct hostap_interface, list);
|
||||
if (iface->type == HOSTAP_INTERFACE_WDS)
|
||||
seq_printf(m, "%s\t%pM\n",
|
||||
iface->dev->name, iface->u.wds.remote_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
read_lock_bh(&local->iface_lock);
|
||||
return seq_list_start(&local->hostap_interfaces, *_pos);
|
||||
}
|
||||
|
||||
static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
return seq_list_next(v, &local->hostap_interfaces, _pos);
|
||||
}
|
||||
|
||||
static void prism2_wds_proc_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
read_unlock_bh(&local->iface_lock);
|
||||
}
|
||||
|
||||
static const struct seq_operations prism2_wds_proc_seqops = {
|
||||
.start = prism2_wds_proc_start,
|
||||
.next = prism2_wds_proc_next,
|
||||
.stop = prism2_wds_proc_stop,
|
||||
.show = prism2_wds_proc_show,
|
||||
};
|
||||
|
||||
static int prism2_wds_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret = seq_open(file, &prism2_wds_proc_seqops);
|
||||
if (ret == 0) {
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = PDE_DATA(inode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_wds_proc_fops = {
|
||||
.open = prism2_wds_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
|
||||
static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
struct list_head *ptr = v;
|
||||
struct hostap_bss_info *bss;
|
||||
|
||||
if (ptr == &local->bss_list) {
|
||||
seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
|
||||
"SSID(hex)\tWPA IE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bss = list_entry(ptr, struct hostap_bss_info, list);
|
||||
seq_printf(m, "%pM\t%lu\t%u\t0x%x\t",
|
||||
bss->bssid, bss->last_update,
|
||||
bss->count, bss->capab_info);
|
||||
|
||||
seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid);
|
||||
|
||||
seq_putc(m, '\t');
|
||||
seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
|
||||
seq_putc(m, '\t');
|
||||
seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie);
|
||||
seq_putc(m, '\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
spin_lock_bh(&local->lock);
|
||||
return seq_list_start_head(&local->bss_list, *_pos);
|
||||
}
|
||||
|
||||
static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
return seq_list_next(v, &local->bss_list, _pos);
|
||||
}
|
||||
|
||||
static void prism2_bss_list_proc_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
spin_unlock_bh(&local->lock);
|
||||
}
|
||||
|
||||
static const struct seq_operations prism2_bss_list_proc_seqops = {
|
||||
.start = prism2_bss_list_proc_start,
|
||||
.next = prism2_bss_list_proc_next,
|
||||
.stop = prism2_bss_list_proc_stop,
|
||||
.show = prism2_bss_list_proc_show,
|
||||
};
|
||||
|
||||
static int prism2_bss_list_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret = seq_open(file, &prism2_bss_list_proc_seqops);
|
||||
if (ret == 0) {
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = PDE_DATA(inode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_bss_list_proc_fops = {
|
||||
.open = prism2_bss_list_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
|
||||
static int prism2_crypt_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
int i;
|
||||
|
||||
seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
|
||||
for (i = 0; i < WEP_KEYS; i++) {
|
||||
if (local->crypt_info.crypt[i] &&
|
||||
local->crypt_info.crypt[i]->ops &&
|
||||
local->crypt_info.crypt[i]->ops->print_stats) {
|
||||
local->crypt_info.crypt[i]->ops->print_stats(
|
||||
m, local->crypt_info.crypt[i]->priv);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prism2_crypt_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, prism2_crypt_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_crypt_proc_fops = {
|
||||
.open = prism2_crypt_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
|
||||
static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *_pos)
|
||||
{
|
||||
local_info_t *local = PDE_DATA(file_inode(file));
|
||||
size_t off;
|
||||
|
||||
if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE)
|
||||
return 0;
|
||||
|
||||
off = *_pos;
|
||||
if (count > PRISM2_PDA_SIZE - off)
|
||||
count = PRISM2_PDA_SIZE - off;
|
||||
if (copy_to_user(buf, local->pda + off, count) != 0)
|
||||
return -EFAULT;
|
||||
*_pos += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_pda_proc_fops = {
|
||||
.read = prism2_pda_proc_read,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
|
||||
static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf,
|
||||
size_t bufsize, loff_t *_pos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_aux_dump_proc_fops = {
|
||||
.read = prism2_aux_dump_proc_no_read,
|
||||
};
|
||||
|
||||
|
||||
#ifdef PRISM2_IO_DEBUG
|
||||
static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
local_info_t *local = (local_info_t *) data;
|
||||
int head = local->io_debug_head;
|
||||
int start_bytes, left, copy, copied;
|
||||
|
||||
if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
|
||||
*eof = 1;
|
||||
if (off >= PRISM2_IO_DEBUG_SIZE * 4)
|
||||
return 0;
|
||||
count = PRISM2_IO_DEBUG_SIZE * 4 - off;
|
||||
}
|
||||
|
||||
copied = 0;
|
||||
start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
|
||||
left = count;
|
||||
|
||||
if (off < start_bytes) {
|
||||
copy = start_bytes - off;
|
||||
if (copy > count)
|
||||
copy = count;
|
||||
memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
|
||||
left -= copy;
|
||||
if (left > 0)
|
||||
memcpy(&page[copy], local->io_debug, left);
|
||||
} else {
|
||||
memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
|
||||
left);
|
||||
}
|
||||
|
||||
*start = page;
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif /* PRISM2_IO_DEBUG */
|
||||
|
||||
|
||||
#ifndef PRISM2_NO_STATION_MODES
|
||||
static int prism2_scan_results_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
unsigned long entry;
|
||||
int i, len;
|
||||
struct hfa384x_hostscan_result *scanres;
|
||||
u8 *p;
|
||||
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
seq_printf(m,
|
||||
"CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry = (unsigned long)v - 2;
|
||||
scanres = &local->last_scan_results[entry];
|
||||
|
||||
seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ",
|
||||
le16_to_cpu(scanres->chid),
|
||||
(s16) le16_to_cpu(scanres->anl),
|
||||
(s16) le16_to_cpu(scanres->sl),
|
||||
le16_to_cpu(scanres->beacon_interval),
|
||||
le16_to_cpu(scanres->capability),
|
||||
le16_to_cpu(scanres->rate),
|
||||
scanres->bssid,
|
||||
le16_to_cpu(scanres->atim));
|
||||
|
||||
p = scanres->sup_rates;
|
||||
for (i = 0; i < sizeof(scanres->sup_rates); i++) {
|
||||
if (p[i] == 0)
|
||||
break;
|
||||
seq_printf(m, "<%02x>", p[i]);
|
||||
}
|
||||
seq_putc(m, ' ');
|
||||
|
||||
p = scanres->ssid;
|
||||
len = le16_to_cpu(scanres->ssid_len);
|
||||
if (len > 32)
|
||||
len = 32;
|
||||
for (i = 0; i < len; i++) {
|
||||
unsigned char c = p[i];
|
||||
if (c >= 32 && c < 127)
|
||||
seq_putc(m, c);
|
||||
else
|
||||
seq_printf(m, "<%02x>", c);
|
||||
}
|
||||
seq_putc(m, '\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
spin_lock_bh(&local->lock);
|
||||
|
||||
/* We have a header (pos 0) + N results to show (pos 1...N) */
|
||||
if (*_pos > local->last_scan_results_count)
|
||||
return NULL;
|
||||
return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
|
||||
}
|
||||
|
||||
static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
|
||||
++*_pos;
|
||||
if (*_pos > local->last_scan_results_count)
|
||||
return NULL;
|
||||
return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
|
||||
}
|
||||
|
||||
static void prism2_scan_results_proc_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
local_info_t *local = m->private;
|
||||
spin_unlock_bh(&local->lock);
|
||||
}
|
||||
|
||||
static const struct seq_operations prism2_scan_results_proc_seqops = {
|
||||
.start = prism2_scan_results_proc_start,
|
||||
.next = prism2_scan_results_proc_next,
|
||||
.stop = prism2_scan_results_proc_stop,
|
||||
.show = prism2_scan_results_proc_show,
|
||||
};
|
||||
|
||||
static int prism2_scan_results_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret = seq_open(file, &prism2_scan_results_proc_seqops);
|
||||
if (ret == 0) {
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = PDE_DATA(inode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations prism2_scan_results_proc_fops = {
|
||||
.open = prism2_scan_results_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
|
||||
#endif /* PRISM2_NO_STATION_MODES */
|
||||
|
||||
|
||||
void hostap_init_proc(local_info_t *local)
|
||||
{
|
||||
local->proc = NULL;
|
||||
|
||||
if (hostap_proc == NULL) {
|
||||
printk(KERN_WARNING "%s: hostap proc directory not created\n",
|
||||
local->dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
local->proc = proc_mkdir(local->ddev->name, hostap_proc);
|
||||
if (local->proc == NULL) {
|
||||
printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
|
||||
local->ddev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef PRISM2_NO_PROCFS_DEBUG
|
||||
proc_create_data("debug", 0, local->proc,
|
||||
&prism2_debug_proc_fops, local);
|
||||
#endif /* PRISM2_NO_PROCFS_DEBUG */
|
||||
proc_create_data("stats", 0, local->proc,
|
||||
&prism2_stats_proc_fops, local);
|
||||
proc_create_data("wds", 0, local->proc,
|
||||
&prism2_wds_proc_fops, local);
|
||||
proc_create_data("pda", 0, local->proc,
|
||||
&prism2_pda_proc_fops, local);
|
||||
proc_create_data("aux_dump", 0, local->proc,
|
||||
local->func->read_aux_fops ?: &prism2_aux_dump_proc_fops,
|
||||
local);
|
||||
proc_create_data("bss_list", 0, local->proc,
|
||||
&prism2_bss_list_proc_fops, local);
|
||||
proc_create_data("crypt", 0, local->proc,
|
||||
&prism2_crypt_proc_fops, local);
|
||||
#ifdef PRISM2_IO_DEBUG
|
||||
proc_create_data("io_debug", 0, local->proc,
|
||||
&prism2_io_debug_proc_fops, local);
|
||||
#endif /* PRISM2_IO_DEBUG */
|
||||
#ifndef PRISM2_NO_STATION_MODES
|
||||
proc_create_data("scan_results", 0, local->proc,
|
||||
&prism2_scan_results_proc_fops, local);
|
||||
#endif /* PRISM2_NO_STATION_MODES */
|
||||
}
|
||||
|
||||
|
||||
void hostap_remove_proc(local_info_t *local)
|
||||
{
|
||||
proc_remove(local->proc);
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(hostap_init_proc);
|
||||
EXPORT_SYMBOL(hostap_remove_proc);
|
1047
drivers/net/wireless/intersil/hostap/hostap_wlan.h
Normal file
1047
drivers/net/wireless/intersil/hostap/hostap_wlan.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user