dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6 into upstream

This commit is contained in:
Jeff Garzik 2006-04-26 06:18:15 -04:00
commit 00355cd938
29 changed files with 1669 additions and 1057 deletions

View File

@ -14,8 +14,8 @@ Copyright (C) 2004-2006, Intel Corporation
README.ipw2200 README.ipw2200
Version: 1.0.8 Version: 1.1.2
Date : October 20, 2005 Date : March 30, 2006
Index Index
@ -103,7 +103,7 @@ file.
1.1. Overview of Features 1.1. Overview of Features
----------------------------------------------- -----------------------------------------------
The current release (1.0.8) supports the following features: The current release (1.1.2) supports the following features:
+ BSS mode (Infrastructure, Managed) + BSS mode (Infrastructure, Managed)
+ IBSS mode (Ad-Hoc) + IBSS mode (Ad-Hoc)
@ -247,8 +247,8 @@ and can set the contents via echo. For example:
% cat /sys/bus/pci/drivers/ipw2200/debug_level % cat /sys/bus/pci/drivers/ipw2200/debug_level
Will report the current debug level of the driver's logging subsystem Will report the current debug level of the driver's logging subsystem
(only available if CONFIG_IPW_DEBUG was configured when the driver was (only available if CONFIG_IPW2200_DEBUG was configured when the driver
built). was built).
You can set the debug level via: You can set the debug level via:

View File

@ -235,7 +235,35 @@ config IPW2200_MONITOR
promiscuous mode via the Wireless Tool's Monitor mode. While in this promiscuous mode via the Wireless Tool's Monitor mode. While in this
mode, no packets can be sent. mode, no packets can be sent.
config IPW_QOS config IPW2200_RADIOTAP
bool "Enable radiotap format 802.11 raw packet support"
depends on IPW2200_MONITOR
config IPW2200_PROMISCUOUS
bool "Enable creation of a RF radiotap promiscuous interface"
depends on IPW2200_MONITOR
select IPW2200_RADIOTAP
---help---
Enables the creation of a second interface prefixed 'rtap'.
This second interface will provide every received in radiotap
format.
This is useful for performing wireless network analysis while
maintaining an active association.
Example usage:
% modprobe ipw2200 rtap_iface=1
% ifconfig rtap0 up
% tethereal -i rtap0
If you do not specify 'rtap_iface=1' as a module parameter then
the rtap interface will not be created and you will need to turn
it on via sysfs:
% echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
config IPW2200_QOS
bool "Enable QoS support" bool "Enable QoS support"
depends on IPW2200 && EXPERIMENTAL depends on IPW2200 && EXPERIMENTAL

View File

@ -47,6 +47,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/ieee80211.h>
#include "airo.h" #include "airo.h"
@ -467,6 +468,8 @@ static int do8bitIO = 0;
#define RID_ECHOTEST_RESULTS 0xFF71 #define RID_ECHOTEST_RESULTS 0xFF71
#define RID_BSSLISTFIRST 0xFF72 #define RID_BSSLISTFIRST 0xFF72
#define RID_BSSLISTNEXT 0xFF73 #define RID_BSSLISTNEXT 0xFF73
#define RID_WPA_BSSLISTFIRST 0xFF74
#define RID_WPA_BSSLISTNEXT 0xFF75
typedef struct { typedef struct {
u16 cmd; u16 cmd;
@ -739,6 +742,14 @@ typedef struct {
u16 extSoftCap; u16 extSoftCap;
} CapabilityRid; } CapabilityRid;
/* Only present on firmware >= 5.30.17 */
typedef struct {
u16 unknown[4];
u8 fixed[12]; /* WLAN management frame */
u8 iep[624];
} BSSListRidExtra;
typedef struct { typedef struct {
u16 len; u16 len;
u16 index; /* First is 0 and 0xffff means end of list */ u16 index; /* First is 0 and 0xffff means end of list */
@ -767,6 +778,9 @@ typedef struct {
} fh; } fh;
u16 dsChannel; u16 dsChannel;
u16 atimWindow; u16 atimWindow;
/* Only present on firmware >= 5.30.17 */
BSSListRidExtra extra;
} BSSListRid; } BSSListRid;
typedef struct { typedef struct {
@ -1140,8 +1154,6 @@ struct airo_info {
char defindex; // Used with auto wep char defindex; // Used with auto wep
struct proc_dir_entry *proc_entry; struct proc_dir_entry *proc_entry;
spinlock_t aux_lock; spinlock_t aux_lock;
unsigned long flags;
#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
#define FLAG_RADIO_OFF 0 /* User disabling of MAC */ #define FLAG_RADIO_OFF 0 /* User disabling of MAC */
#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */ #define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
#define FLAG_RADIO_MASK 0x03 #define FLAG_RADIO_MASK 0x03
@ -1151,6 +1163,7 @@ struct airo_info {
#define FLAG_UPDATE_MULTI 5 #define FLAG_UPDATE_MULTI 5
#define FLAG_UPDATE_UNI 6 #define FLAG_UPDATE_UNI 6
#define FLAG_802_11 7 #define FLAG_802_11 7
#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
#define FLAG_PENDING_XMIT 9 #define FLAG_PENDING_XMIT 9
#define FLAG_PENDING_XMIT11 10 #define FLAG_PENDING_XMIT11 10
#define FLAG_MPI 11 #define FLAG_MPI 11
@ -1158,17 +1171,19 @@ struct airo_info {
#define FLAG_COMMIT 13 #define FLAG_COMMIT 13
#define FLAG_RESET 14 #define FLAG_RESET 14
#define FLAG_FLASHING 15 #define FLAG_FLASHING 15
#define JOB_MASK 0x2ff0000 #define FLAG_WPA_CAPABLE 16
#define JOB_DIE 16 unsigned long flags;
#define JOB_XMIT 17 #define JOB_DIE 0
#define JOB_XMIT11 18 #define JOB_XMIT 1
#define JOB_STATS 19 #define JOB_XMIT11 2
#define JOB_PROMISC 20 #define JOB_STATS 3
#define JOB_MIC 21 #define JOB_PROMISC 4
#define JOB_EVENT 22 #define JOB_MIC 5
#define JOB_AUTOWEP 23 #define JOB_EVENT 6
#define JOB_WSTATS 24 #define JOB_AUTOWEP 7
#define JOB_SCAN_RESULTS 25 #define JOB_WSTATS 8
#define JOB_SCAN_RESULTS 9
unsigned long jobs;
int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap); int whichbap);
unsigned short *flash; unsigned short *flash;
@ -1208,6 +1223,11 @@ struct airo_info {
#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE #define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
char proc_name[IFNAMSIZ]; char proc_name[IFNAMSIZ];
/* WPA-related stuff */
unsigned int bssListFirst;
unsigned int bssListNext;
unsigned int bssListRidLen;
struct list_head network_list; struct list_head network_list;
struct list_head network_free_list; struct list_head network_free_list;
BSSListElement *networks; BSSListElement *networks;
@ -1264,7 +1284,7 @@ static void micinit(struct airo_info *ai)
{ {
MICRid mic_rid; MICRid mic_rid;
clear_bit(JOB_MIC, &ai->flags); clear_bit(JOB_MIC, &ai->jobs);
PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
up(&ai->sem); up(&ai->sem);
@ -1705,24 +1725,24 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
static int readBSSListRid(struct airo_info *ai, int first, static int readBSSListRid(struct airo_info *ai, int first,
BSSListRid *list) { BSSListRid *list) {
int rc; int rc;
Cmd cmd; Cmd cmd;
Resp rsp; Resp rsp;
if (first == 1) { if (first == 1) {
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS; cmd.cmd=CMD_LISTBSS;
if (down_interruptible(&ai->sem)) if (down_interruptible(&ai->sem))
return -ERESTARTSYS; return -ERESTARTSYS;
issuecommand(ai, &cmd, &rsp); issuecommand(ai, &cmd, &rsp);
up(&ai->sem); up(&ai->sem);
/* Let the command take effect */ /* Let the command take effect */
ai->task = current; ai->task = current;
ssleep(3); ssleep(3);
ai->task = NULL; ai->task = NULL;
} }
rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT, rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
list, sizeof(*list), 1); list, ai->bssListRidLen, 1);
list->len = le16_to_cpu(list->len); list->len = le16_to_cpu(list->len);
list->index = le16_to_cpu(list->index); list->index = le16_to_cpu(list->index);
@ -2112,7 +2132,7 @@ static void airo_end_xmit(struct net_device *dev) {
int fid = priv->xmit.fid; int fid = priv->xmit.fid;
u32 *fids = priv->fids; u32 *fids = priv->fids;
clear_bit(JOB_XMIT, &priv->flags); clear_bit(JOB_XMIT, &priv->jobs);
clear_bit(FLAG_PENDING_XMIT, &priv->flags); clear_bit(FLAG_PENDING_XMIT, &priv->flags);
status = transmit_802_3_packet (priv, fids[fid], skb->data); status = transmit_802_3_packet (priv, fids[fid], skb->data);
up(&priv->sem); up(&priv->sem);
@ -2162,7 +2182,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if (down_trylock(&priv->sem) != 0) { if (down_trylock(&priv->sem) != 0) {
set_bit(FLAG_PENDING_XMIT, &priv->flags); set_bit(FLAG_PENDING_XMIT, &priv->flags);
netif_stop_queue(dev); netif_stop_queue(dev);
set_bit(JOB_XMIT, &priv->flags); set_bit(JOB_XMIT, &priv->jobs);
wake_up_interruptible(&priv->thr_wait); wake_up_interruptible(&priv->thr_wait);
} else } else
airo_end_xmit(dev); airo_end_xmit(dev);
@ -2177,7 +2197,7 @@ static void airo_end_xmit11(struct net_device *dev) {
int fid = priv->xmit11.fid; int fid = priv->xmit11.fid;
u32 *fids = priv->fids; u32 *fids = priv->fids;
clear_bit(JOB_XMIT11, &priv->flags); clear_bit(JOB_XMIT11, &priv->jobs);
clear_bit(FLAG_PENDING_XMIT11, &priv->flags); clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
status = transmit_802_11_packet (priv, fids[fid], skb->data); status = transmit_802_11_packet (priv, fids[fid], skb->data);
up(&priv->sem); up(&priv->sem);
@ -2233,7 +2253,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
if (down_trylock(&priv->sem) != 0) { if (down_trylock(&priv->sem) != 0) {
set_bit(FLAG_PENDING_XMIT11, &priv->flags); set_bit(FLAG_PENDING_XMIT11, &priv->flags);
netif_stop_queue(dev); netif_stop_queue(dev);
set_bit(JOB_XMIT11, &priv->flags); set_bit(JOB_XMIT11, &priv->jobs);
wake_up_interruptible(&priv->thr_wait); wake_up_interruptible(&priv->thr_wait);
} else } else
airo_end_xmit11(dev); airo_end_xmit11(dev);
@ -2244,7 +2264,7 @@ static void airo_read_stats(struct airo_info *ai) {
StatsRid stats_rid; StatsRid stats_rid;
u32 *vals = stats_rid.vals; u32 *vals = stats_rid.vals;
clear_bit(JOB_STATS, &ai->flags); clear_bit(JOB_STATS, &ai->jobs);
if (ai->power.event) { if (ai->power.event) {
up(&ai->sem); up(&ai->sem);
return; return;
@ -2272,10 +2292,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev)
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
if (!test_bit(JOB_STATS, &local->flags)) { if (!test_bit(JOB_STATS, &local->jobs)) {
/* Get stats out of the card if available */ /* Get stats out of the card if available */
if (down_trylock(&local->sem) != 0) { if (down_trylock(&local->sem) != 0) {
set_bit(JOB_STATS, &local->flags); set_bit(JOB_STATS, &local->jobs);
wake_up_interruptible(&local->thr_wait); wake_up_interruptible(&local->thr_wait);
} else } else
airo_read_stats(local); airo_read_stats(local);
@ -2290,7 +2310,7 @@ static void airo_set_promisc(struct airo_info *ai) {
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_SETMODE; cmd.cmd=CMD_SETMODE;
clear_bit(JOB_PROMISC, &ai->flags); clear_bit(JOB_PROMISC, &ai->jobs);
cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
issuecommand(ai, &cmd, &rsp); issuecommand(ai, &cmd, &rsp);
up(&ai->sem); up(&ai->sem);
@ -2302,7 +2322,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
if ((dev->flags ^ ai->flags) & IFF_PROMISC) { if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
change_bit(FLAG_PROMISC, &ai->flags); change_bit(FLAG_PROMISC, &ai->flags);
if (down_trylock(&ai->sem) != 0) { if (down_trylock(&ai->sem) != 0) {
set_bit(JOB_PROMISC, &ai->flags); set_bit(JOB_PROMISC, &ai->jobs);
wake_up_interruptible(&ai->thr_wait); wake_up_interruptible(&ai->thr_wait);
} else } else
airo_set_promisc(ai); airo_set_promisc(ai);
@ -2380,7 +2400,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
} }
clear_bit(FLAG_REGISTERED, &ai->flags); clear_bit(FLAG_REGISTERED, &ai->flags);
} }
set_bit(JOB_DIE, &ai->flags); set_bit(JOB_DIE, &ai->jobs);
kill_proc(ai->thr_pid, SIGTERM, 1); kill_proc(ai->thr_pid, SIGTERM, 1);
wait_for_completion(&ai->thr_exited); wait_for_completion(&ai->thr_exited);
@ -2701,14 +2721,14 @@ static int reset_card( struct net_device *dev , int lock) {
return 0; return 0;
} }
#define MAX_NETWORK_COUNT 64 #define AIRO_MAX_NETWORK_COUNT 64
static int airo_networks_allocate(struct airo_info *ai) static int airo_networks_allocate(struct airo_info *ai)
{ {
if (ai->networks) if (ai->networks)
return 0; return 0;
ai->networks = ai->networks =
kzalloc(MAX_NETWORK_COUNT * sizeof(BSSListElement), kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
GFP_KERNEL); GFP_KERNEL);
if (!ai->networks) { if (!ai->networks) {
airo_print_warn(ai->dev->name, "Out of memory allocating beacons"); airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
@ -2732,11 +2752,33 @@ static void airo_networks_initialize(struct airo_info *ai)
INIT_LIST_HEAD(&ai->network_free_list); INIT_LIST_HEAD(&ai->network_free_list);
INIT_LIST_HEAD(&ai->network_list); INIT_LIST_HEAD(&ai->network_list);
for (i = 0; i < MAX_NETWORK_COUNT; i++) for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
list_add_tail(&ai->networks[i].list, list_add_tail(&ai->networks[i].list,
&ai->network_free_list); &ai->network_free_list);
} }
static int airo_test_wpa_capable(struct airo_info *ai)
{
int status;
CapabilityRid cap_rid;
const char *name = ai->dev->name;
status = readCapabilityRid(ai, &cap_rid, 1);
if (status != SUCCESS) return 0;
/* Only firmware versions 5.30.17 or better can do WPA */
if ((cap_rid.softVer > 0x530)
|| ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 0x17))) {
airo_print_info(name, "WPA is supported.");
return 1;
}
/* No WPA support */
airo_print_info(name, "WPA unsupported (only firmware versions 5.30.17"
" and greater support WPA. Detected %s)", cap_rid.prodVer);
return 0;
}
static struct net_device *_init_airo_card( unsigned short irq, int port, static struct net_device *_init_airo_card( unsigned short irq, int port,
int is_pcmcia, struct pci_dev *pci, int is_pcmcia, struct pci_dev *pci,
struct device *dmdev ) struct device *dmdev )
@ -2759,6 +2801,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai = dev->priv; ai = dev->priv;
ai->wifidev = NULL; ai->wifidev = NULL;
ai->flags = 0; ai->flags = 0;
ai->jobs = 0;
ai->dev = dev; ai->dev = dev;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
airo_print_dbg(dev->name, "Found an MPI350 card"); airo_print_dbg(dev->name, "Found an MPI350 card");
@ -2838,6 +2881,18 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
set_bit(FLAG_FLASHING, &ai->flags); set_bit(FLAG_FLASHING, &ai->flags);
} }
/* Test for WPA support */
if (airo_test_wpa_capable(ai)) {
set_bit(FLAG_WPA_CAPABLE, &ai->flags);
ai->bssListFirst = RID_WPA_BSSLISTFIRST;
ai->bssListNext = RID_WPA_BSSLISTNEXT;
ai->bssListRidLen = sizeof(BSSListRid);
} else {
ai->bssListFirst = RID_BSSLISTFIRST;
ai->bssListNext = RID_BSSLISTNEXT;
ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
}
rc = register_netdev(dev); rc = register_netdev(dev);
if (rc) { if (rc) {
airo_print_err(dev->name, "Couldn't register_netdev"); airo_print_err(dev->name, "Couldn't register_netdev");
@ -2875,7 +2930,7 @@ err_out_irq:
err_out_unlink: err_out_unlink:
del_airo_dev(dev); del_airo_dev(dev);
err_out_thr: err_out_thr:
set_bit(JOB_DIE, &ai->flags); set_bit(JOB_DIE, &ai->jobs);
kill_proc(ai->thr_pid, SIGTERM, 1); kill_proc(ai->thr_pid, SIGTERM, 1);
wait_for_completion(&ai->thr_exited); wait_for_completion(&ai->thr_exited);
err_out_free: err_out_free:
@ -2933,7 +2988,7 @@ static void airo_send_event(struct net_device *dev) {
union iwreq_data wrqu; union iwreq_data wrqu;
StatusRid status_rid; StatusRid status_rid;
clear_bit(JOB_EVENT, &ai->flags); clear_bit(JOB_EVENT, &ai->jobs);
PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
up(&ai->sem); up(&ai->sem);
wrqu.data.length = 0; wrqu.data.length = 0;
@ -2947,7 +3002,7 @@ static void airo_send_event(struct net_device *dev) {
static void airo_process_scan_results (struct airo_info *ai) { static void airo_process_scan_results (struct airo_info *ai) {
union iwreq_data wrqu; union iwreq_data wrqu;
BSSListRid BSSList; BSSListRid bss;
int rc; int rc;
BSSListElement * loop_net; BSSListElement * loop_net;
BSSListElement * tmp_net; BSSListElement * tmp_net;
@ -2960,15 +3015,15 @@ static void airo_process_scan_results (struct airo_info *ai) {
} }
/* Try to read the first entry of the scan result */ /* Try to read the first entry of the scan result */
rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0); rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
if((rc) || (BSSList.index == 0xffff)) { if((rc) || (bss.index == 0xffff)) {
/* No scan results */ /* No scan results */
goto out; goto out;
} }
/* Read and parse all entries */ /* Read and parse all entries */
tmp_net = NULL; tmp_net = NULL;
while((!rc) && (BSSList.index != 0xffff)) { while((!rc) && (bss.index != 0xffff)) {
/* Grab a network off the free list */ /* Grab a network off the free list */
if (!list_empty(&ai->network_free_list)) { if (!list_empty(&ai->network_free_list)) {
tmp_net = list_entry(ai->network_free_list.next, tmp_net = list_entry(ai->network_free_list.next,
@ -2977,19 +3032,19 @@ static void airo_process_scan_results (struct airo_info *ai) {
} }
if (tmp_net != NULL) { if (tmp_net != NULL) {
memcpy(tmp_net, &BSSList, sizeof(tmp_net->bss)); memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
list_add_tail(&tmp_net->list, &ai->network_list); list_add_tail(&tmp_net->list, &ai->network_list);
tmp_net = NULL; tmp_net = NULL;
} }
/* Read next entry */ /* Read next entry */
rc = PC4500_readrid(ai, RID_BSSLISTNEXT, rc = PC4500_readrid(ai, ai->bssListNext,
&BSSList, sizeof(BSSList), 0); &bss, ai->bssListRidLen, 0);
} }
out: out:
ai->scan_timeout = 0; ai->scan_timeout = 0;
clear_bit(JOB_SCAN_RESULTS, &ai->flags); clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
up(&ai->sem); up(&ai->sem);
/* Send an empty event to user space. /* Send an empty event to user space.
@ -3019,10 +3074,10 @@ static int airo_thread(void *data) {
/* make swsusp happy with our thread */ /* make swsusp happy with our thread */
try_to_freeze(); try_to_freeze();
if (test_bit(JOB_DIE, &ai->flags)) if (test_bit(JOB_DIE, &ai->jobs))
break; break;
if (ai->flags & JOB_MASK) { if (ai->jobs) {
locked = down_interruptible(&ai->sem); locked = down_interruptible(&ai->sem);
} else { } else {
wait_queue_t wait; wait_queue_t wait;
@ -3031,16 +3086,16 @@ static int airo_thread(void *data) {
add_wait_queue(&ai->thr_wait, &wait); add_wait_queue(&ai->thr_wait, &wait);
for (;;) { for (;;) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (ai->flags & JOB_MASK) if (ai->jobs)
break; break;
if (ai->expires || ai->scan_timeout) { if (ai->expires || ai->scan_timeout) {
if (ai->scan_timeout && if (ai->scan_timeout &&
time_after_eq(jiffies,ai->scan_timeout)){ time_after_eq(jiffies,ai->scan_timeout)){
set_bit(JOB_SCAN_RESULTS,&ai->flags); set_bit(JOB_SCAN_RESULTS, &ai->jobs);
break; break;
} else if (ai->expires && } else if (ai->expires &&
time_after_eq(jiffies,ai->expires)){ time_after_eq(jiffies,ai->expires)){
set_bit(JOB_AUTOWEP,&ai->flags); set_bit(JOB_AUTOWEP, &ai->jobs);
break; break;
} }
if (!signal_pending(current)) { if (!signal_pending(current)) {
@ -3069,7 +3124,7 @@ static int airo_thread(void *data) {
if (locked) if (locked)
continue; continue;
if (test_bit(JOB_DIE, &ai->flags)) { if (test_bit(JOB_DIE, &ai->jobs)) {
up(&ai->sem); up(&ai->sem);
break; break;
} }
@ -3079,23 +3134,23 @@ static int airo_thread(void *data) {
continue; continue;
} }
if (test_bit(JOB_XMIT, &ai->flags)) if (test_bit(JOB_XMIT, &ai->jobs))
airo_end_xmit(dev); airo_end_xmit(dev);
else if (test_bit(JOB_XMIT11, &ai->flags)) else if (test_bit(JOB_XMIT11, &ai->jobs))
airo_end_xmit11(dev); airo_end_xmit11(dev);
else if (test_bit(JOB_STATS, &ai->flags)) else if (test_bit(JOB_STATS, &ai->jobs))
airo_read_stats(ai); airo_read_stats(ai);
else if (test_bit(JOB_WSTATS, &ai->flags)) else if (test_bit(JOB_WSTATS, &ai->jobs))
airo_read_wireless_stats(ai); airo_read_wireless_stats(ai);
else if (test_bit(JOB_PROMISC, &ai->flags)) else if (test_bit(JOB_PROMISC, &ai->jobs))
airo_set_promisc(ai); airo_set_promisc(ai);
else if (test_bit(JOB_MIC, &ai->flags)) else if (test_bit(JOB_MIC, &ai->jobs))
micinit(ai); micinit(ai);
else if (test_bit(JOB_EVENT, &ai->flags)) else if (test_bit(JOB_EVENT, &ai->jobs))
airo_send_event(dev); airo_send_event(dev);
else if (test_bit(JOB_AUTOWEP, &ai->flags)) else if (test_bit(JOB_AUTOWEP, &ai->jobs))
timer_func(dev); timer_func(dev);
else if (test_bit(JOB_SCAN_RESULTS, &ai->flags)) else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
airo_process_scan_results(ai); airo_process_scan_results(ai);
else /* Shouldn't get here, but we make sure to unlock */ else /* Shouldn't get here, but we make sure to unlock */
up(&ai->sem); up(&ai->sem);
@ -3133,7 +3188,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
if ( status & EV_MIC ) { if ( status & EV_MIC ) {
OUT4500( apriv, EVACK, EV_MIC ); OUT4500( apriv, EVACK, EV_MIC );
if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) { if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
set_bit(JOB_MIC, &apriv->flags); set_bit(JOB_MIC, &apriv->jobs);
wake_up_interruptible(&apriv->thr_wait); wake_up_interruptible(&apriv->thr_wait);
} }
} }
@ -3187,7 +3242,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
set_bit(FLAG_UPDATE_MULTI, &apriv->flags); set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
if (down_trylock(&apriv->sem) != 0) { if (down_trylock(&apriv->sem) != 0) {
set_bit(JOB_EVENT, &apriv->flags); set_bit(JOB_EVENT, &apriv->jobs);
wake_up_interruptible(&apriv->thr_wait); wake_up_interruptible(&apriv->thr_wait);
} else } else
airo_send_event(dev); airo_send_event(dev);
@ -5485,7 +5540,7 @@ static void timer_func( struct net_device *dev ) {
up(&apriv->sem); up(&apriv->sem);
/* Schedule check to see if the change worked */ /* Schedule check to see if the change worked */
clear_bit(JOB_AUTOWEP, &apriv->flags); clear_bit(JOB_AUTOWEP, &apriv->jobs);
apriv->expires = RUN_AT(HZ*3); apriv->expires = RUN_AT(HZ*3);
} }
@ -6876,7 +6931,7 @@ static int airo_get_range(struct net_device *dev,
} }
range->num_txpower = i; range->num_txpower = i;
range->txpower_capa = IW_TXPOW_MWATT; range->txpower_capa = IW_TXPOW_MWATT;
range->we_version_source = 12; range->we_version_source = 19;
range->we_version_compiled = WIRELESS_EXT; range->we_version_compiled = WIRELESS_EXT;
range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
range->retry_flags = IW_RETRY_LIMIT; range->retry_flags = IW_RETRY_LIMIT;
@ -7152,6 +7207,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
u16 capabilities; u16 capabilities;
char * current_val; /* For rates */ char * current_val; /* For rates */
int i; int i;
char * buf;
/* First entry *MUST* be the AP MAC address */ /* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP; iwe.cmd = SIOCGIWAP;
@ -7238,8 +7294,69 @@ static inline char *airo_translate_scan(struct net_device *dev,
if((current_val - current_ev) > IW_EV_LCP_LEN) if((current_val - current_ev) > IW_EV_LCP_LEN)
current_ev = current_val; current_ev = current_val;
/* The other data in the scan result are not really /* Beacon interval */
* interesting, so for now drop it - Jean II */ buf = kmalloc(30, GFP_KERNEL);
if (buf) {
iwe.cmd = IWEVCUSTOM;
sprintf(buf, "bcn_int=%d", bss->beaconInterval);
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
kfree(buf);
}
/* Put WPA/RSN Information Elements into the event stream */
if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
unsigned int num_null_ies = 0;
u16 length = sizeof (bss->extra.iep);
struct ieee80211_info_element *info_element =
(struct ieee80211_info_element *) &bss->extra.iep;
while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
if (sizeof(*info_element) + info_element->len > length) {
/* Invalid element, don't continue parsing IE */
break;
}
switch (info_element->id) {
case MFIE_TYPE_SSID:
/* Two zero-length SSID elements
* mean we're done parsing elements */
if (!info_element->len)
num_null_ies++;
break;
case MFIE_TYPE_GENERIC:
if (info_element->len >= 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x50 &&
info_element->data[2] == 0xf2 &&
info_element->data[3] == 0x01) {
iwe.cmd = IWEVGENIE;
iwe.u.data.length = min(info_element->len + 2,
MAX_WPA_IE_LEN);
current_ev = iwe_stream_add_point(current_ev, end_buf,
&iwe, (char *) info_element);
}
break;
case MFIE_TYPE_RSN:
iwe.cmd = IWEVGENIE;
iwe.u.data.length = min(info_element->len + 2,
MAX_WPA_IE_LEN);
current_ev = iwe_stream_add_point(current_ev, end_buf,
&iwe, (char *) info_element);
break;
default:
break;
}
length -= sizeof(*info_element) + info_element->len;
info_element =
(struct ieee80211_info_element *)&info_element->
data[info_element->len];
}
}
return current_ev; return current_ev;
} }
@ -7521,7 +7638,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
u32 *vals = stats_rid.vals; u32 *vals = stats_rid.vals;
/* Get stats out of the card */ /* Get stats out of the card */
clear_bit(JOB_WSTATS, &local->flags); clear_bit(JOB_WSTATS, &local->jobs);
if (local->power.event) { if (local->power.event) {
up(&local->sem); up(&local->sem);
return; return;
@ -7565,10 +7682,10 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
if (!test_bit(JOB_WSTATS, &local->flags)) { if (!test_bit(JOB_WSTATS, &local->jobs)) {
/* Get stats out of the card if available */ /* Get stats out of the card if available */
if (down_trylock(&local->sem) != 0) { if (down_trylock(&local->sem) != 0) {
set_bit(JOB_WSTATS, &local->flags); set_bit(JOB_WSTATS, &local->jobs);
wake_up_interruptible(&local->thr_wait); wake_up_interruptible(&local->thr_wait);
} else } else
airo_read_wireless_stats(local); airo_read_wireless_stats(local);

View File

@ -645,7 +645,6 @@ struct bcm43xx_private {
unsigned int irq; unsigned int irq;
void __iomem *mmio_addr; void __iomem *mmio_addr;
unsigned int mmio_len;
/* Do not use the lock directly. Use the bcm43xx_lock* helper /* Do not use the lock directly. Use the bcm43xx_lock* helper
* functions, to be MMIO-safe. */ * functions, to be MMIO-safe. */

View File

@ -92,7 +92,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n", fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n",
pci_dev->subsystem_vendor, pci_dev->subsystem_device); pci_dev->subsystem_vendor, pci_dev->subsystem_device);
fappend("IRQ: %d\n", bcm->irq); fappend("IRQ: %d\n", bcm->irq);
fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len); fappend("mmio_addr: 0x%p\n", bcm->mmio_addr);
fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev); fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16))) if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
fappend("Radio disabled by hardware!\n"); fappend("Radio disabled by hardware!\n");

View File

@ -3288,8 +3288,7 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
bcm43xx_chipset_detach(bcm); bcm43xx_chipset_detach(bcm);
/* Do _not_ access the chip, after it is detached. */ /* Do _not_ access the chip, after it is detached. */
iounmap(bcm->mmio_addr); pci_iounmap(pci_dev, bcm->mmio_addr);
pci_release_regions(pci_dev); pci_release_regions(pci_dev);
pci_disable_device(pci_dev); pci_disable_device(pci_dev);
@ -3379,40 +3378,26 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
struct net_device *net_dev = bcm->net_dev; struct net_device *net_dev = bcm->net_dev;
int err; int err;
int i; int i;
unsigned long mmio_start, mmio_flags, mmio_len;
u32 coremask; u32 coremask;
err = pci_enable_device(pci_dev); err = pci_enable_device(pci_dev);
if (err) { if (err) {
printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err); printk(KERN_ERR PFX "pci_enable_device() failed\n");
goto out; goto out;
} }
mmio_start = pci_resource_start(pci_dev, 0);
mmio_flags = pci_resource_flags(pci_dev, 0);
mmio_len = pci_resource_len(pci_dev, 0);
if (!(mmio_flags & IORESOURCE_MEM)) {
printk(KERN_ERR PFX
"%s, region #0 not an MMIO resource, aborting\n",
pci_name(pci_dev));
err = -ENODEV;
goto err_pci_disable;
}
err = pci_request_regions(pci_dev, KBUILD_MODNAME); err = pci_request_regions(pci_dev, KBUILD_MODNAME);
if (err) { if (err) {
printk(KERN_ERR PFX printk(KERN_ERR PFX "pci_request_regions() failed\n");
"could not access PCI resources (%i)\n", err);
goto err_pci_disable; goto err_pci_disable;
} }
/* enable PCI bus-mastering */ /* enable PCI bus-mastering */
pci_set_master(pci_dev); pci_set_master(pci_dev);
bcm->mmio_addr = ioremap(mmio_start, mmio_len); bcm->mmio_addr = pci_iomap(pci_dev, 0, ~0UL);
if (!bcm->mmio_addr) { if (!bcm->mmio_addr) {
printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", printk(KERN_ERR PFX "pci_iomap() failed\n");
pci_name(pci_dev));
err = -EIO; err = -EIO;
goto err_pci_release; goto err_pci_release;
} }
bcm->mmio_len = mmio_len;
net_dev->base_addr = (unsigned long)bcm->mmio_addr; net_dev->base_addr = (unsigned long)bcm->mmio_addr;
bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
@ -3505,7 +3490,7 @@ err_80211_unwind:
err_chipset_detach: err_chipset_detach:
bcm43xx_chipset_detach(bcm); bcm43xx_chipset_detach(bcm);
err_iounmap: err_iounmap:
iounmap(bcm->mmio_addr); pci_iounmap(pci_dev, bcm->mmio_addr);
err_pci_release: err_pci_release:
pci_release_regions(pci_dev); pci_release_regions(pci_dev);
err_pci_disable: err_pci_disable:

View File

@ -121,12 +121,6 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
hw->iobase = address; hw->iobase = address;
hw->reg_spacing = reg_spacing; hw->reg_spacing = reg_spacing;
hw->inten = 0x0; hw->inten = 0x0;
#ifdef HERMES_DEBUG_BUFFER
hw->dbufp = 0;
memset(&hw->dbuf, 0xff, sizeof(hw->dbuf));
memset(&hw->profile, 0, sizeof(hw->profile));
#endif
} }
int hermes_init(hermes_t *hw) int hermes_init(hermes_t *hw)
@ -347,19 +341,6 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
reg = hermes_read_reg(hw, oreg); reg = hermes_read_reg(hw, oreg);
} }
#ifdef HERMES_DEBUG_BUFFER
hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++;
if (k < HERMES_BAP_BUSY_TIMEOUT) {
struct hermes_debug_entry *e =
&hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE];
e->bap = bap;
e->id = id;
e->offset = offset;
e->cycles = HERMES_BAP_BUSY_TIMEOUT - k;
}
#endif
if (reg & HERMES_OFFSET_BUSY) if (reg & HERMES_OFFSET_BUSY)
return -ETIMEDOUT; return -ETIMEDOUT;
@ -419,8 +400,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
} }
/* Write a block of data to the chip's buffer, via the /* Write a block of data to the chip's buffer, via the
* BAP. Synchronization/serialization is the caller's problem. len * BAP. Synchronization/serialization is the caller's problem.
* must be even.
* *
* Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
*/ */
@ -430,7 +410,7 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
int err = 0; int err = 0;
if ( (len < 0) || (len % 2) ) if (len < 0)
return -EINVAL; return -EINVAL;
err = hermes_bap_seek(hw, bap, id, offset); err = hermes_bap_seek(hw, bap, id, offset);
@ -438,49 +418,12 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
goto out; goto out;
/* Actually do the transfer */ /* Actually do the transfer */
hermes_write_words(hw, dreg, buf, len/2); hermes_write_bytes(hw, dreg, buf, len);
out: out:
return err; return err;
} }
/* Write a block of data to the chip's buffer with padding if
* neccessary, via the BAP. Synchronization/serialization is the
* caller's problem. len must be even.
*
* Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
*/
int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, int len,
u16 id, u16 offset)
{
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
int err = 0;
if (len < 0 || len % 2 || data_len > len)
return -EINVAL;
err = hermes_bap_seek(hw, bap, id, offset);
if (err)
goto out;
/* Transfer all the complete words of data */
hermes_write_words(hw, dreg, buf, data_len/2);
/* If there is an odd byte left over pad and transfer it */
if (data_len & 1) {
u8 end[2];
end[1] = 0;
end[0] = ((unsigned char *)buf)[data_len - 1];
hermes_write_words(hw, dreg, end, 1);
data_len ++;
}
/* Now send zeros for the padding */
if (data_len < len)
hermes_clear_words(hw, dreg, (len - data_len) / 2);
/* Complete */
out:
return err;
}
/* Read a Length-Type-Value record from the card. /* Read a Length-Type-Value record from the card.
* *
* If length is NULL, we ignore the length read from the card, and * If length is NULL, we ignore the length read from the card, and
@ -553,7 +496,7 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
count = length - 1; count = length - 1;
hermes_write_words(hw, dreg, value, count); hermes_write_bytes(hw, dreg, value, count << 1);
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
rid, NULL); rid, NULL);
@ -568,7 +511,6 @@ EXPORT_SYMBOL(hermes_allocate);
EXPORT_SYMBOL(hermes_bap_pread); EXPORT_SYMBOL(hermes_bap_pread);
EXPORT_SYMBOL(hermes_bap_pwrite); EXPORT_SYMBOL(hermes_bap_pwrite);
EXPORT_SYMBOL(hermes_bap_pwrite_pad);
EXPORT_SYMBOL(hermes_read_ltv); EXPORT_SYMBOL(hermes_read_ltv);
EXPORT_SYMBOL(hermes_write_ltv); EXPORT_SYMBOL(hermes_write_ltv);

View File

@ -328,16 +328,6 @@ struct hermes_multicast {
u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
} __attribute__ ((packed)); } __attribute__ ((packed));
// #define HERMES_DEBUG_BUFFER 1
#define HERMES_DEBUG_BUFSIZE 4096
struct hermes_debug_entry {
int bap;
u16 id, offset;
int cycles;
};
#ifdef __KERNEL__
/* Timeouts */ /* Timeouts */
#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ #define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
@ -347,14 +337,7 @@ typedef struct hermes {
int reg_spacing; int reg_spacing;
#define HERMES_16BIT_REGSPACING 0 #define HERMES_16BIT_REGSPACING 0
#define HERMES_32BIT_REGSPACING 1 #define HERMES_32BIT_REGSPACING 1
u16 inten; /* Which interrupts should be enabled? */ u16 inten; /* Which interrupts should be enabled? */
#ifdef HERMES_DEBUG_BUFFER
struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE];
unsigned long dbufp;
unsigned long profile[HERMES_BAP_BUSY_TIMEOUT+1];
#endif
} hermes_t; } hermes_t;
/* Register access convenience macros */ /* Register access convenience macros */
@ -376,8 +359,6 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
u16 id, u16 offset); u16 id, u16 offset);
int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
u16 id, u16 offset); u16 id, u16 offset);
int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf,
unsigned data_len, int len, u16 id, u16 offset);
int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
u16 *length, void *buf); u16 *length, void *buf);
int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
@ -425,10 +406,13 @@ static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsi
ioread16_rep(hw->iobase + off, buf, count); ioread16_rep(hw->iobase + off, buf, count);
} }
static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count) static inline void hermes_write_bytes(struct hermes *hw, int off,
const char *buf, unsigned count)
{ {
off = off << hw->reg_spacing; off = off << hw->reg_spacing;
iowrite16_rep(hw->iobase + off, buf, count); iowrite16_rep(hw->iobase + off, buf, count >> 1);
if (unlikely(count & 1))
iowrite8(buf[count - 1], hw->iobase + off);
} }
static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count) static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
@ -462,21 +446,4 @@ static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word)
return HERMES_WRITE_RECORD(hw, bap, rid, &rec); return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
} }
#else /* ! __KERNEL__ */
/* These are provided for the benefit of userspace drivers and testing programs
which use ioperm() or iopl() */
#define hermes_read_reg(base, off) (inw((base) + (off)))
#define hermes_write_reg(base, off, val) (outw((val), (base) + (off)))
#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name))
#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val)))
/* Note that for the next two, the count is in 16-bit words, not bytes */
#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count)))
#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count)))
#endif /* ! __KERNEL__ */
#endif /* _HERMES_H */ #endif /* _HERMES_H */

File diff suppressed because it is too large Load Diff

View File

@ -789,7 +789,7 @@ struct ipw_sys_config {
u8 bt_coexist_collision_thr; u8 bt_coexist_collision_thr;
u8 silence_threshold; u8 silence_threshold;
u8 accept_all_mgmt_bcpr; u8 accept_all_mgmt_bcpr;
u8 accept_all_mgtm_frames; u8 accept_all_mgmt_frames;
u8 pass_noise_stats_to_host; u8 pass_noise_stats_to_host;
u8 reserved3; u8 reserved3;
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -1122,6 +1122,52 @@ struct ipw_fw_error {
u8 payload[0]; u8 payload[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
#ifdef CONFIG_IPW2200_PROMISCUOUS
enum ipw_prom_filter {
IPW_PROM_CTL_HEADER_ONLY = (1 << 0),
IPW_PROM_MGMT_HEADER_ONLY = (1 << 1),
IPW_PROM_DATA_HEADER_ONLY = (1 << 2),
IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */
IPW_PROM_NO_TX = (1 << 4),
IPW_PROM_NO_RX = (1 << 5),
IPW_PROM_NO_CTL = (1 << 6),
IPW_PROM_NO_MGMT = (1 << 7),
IPW_PROM_NO_DATA = (1 << 8),
};
struct ipw_priv;
struct ipw_prom_priv {
struct ipw_priv *priv;
struct ieee80211_device *ieee;
enum ipw_prom_filter filter;
int tx_packets;
int rx_packets;
};
#endif
#if defined(CONFIG_IPW2200_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS)
/* Magic struct that slots into the radiotap header -- no reason
* to build this manually element by element, we can write it much
* more efficiently than we can parse it. ORDER MATTERS HERE
*
* When sent to us via the simulated Rx interface in sysfs, the entire
* structure is provided regardless of any bits unset.
*/
struct ipw_rt_hdr {
struct ieee80211_radiotap_header rt_hdr;
u64 rt_tsf; /* TSF */
u8 rt_flags; /* radiotap packet flags */
u8 rt_rate; /* rate in 500kb/s */
u16 rt_channel; /* channel in mhz */
u16 rt_chbitmask; /* channel bitfield */
s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
s8 rt_dbmnoise;
u8 rt_antenna; /* antenna number */
u8 payload[0]; /* payload... */
} __attribute__ ((packed));
#endif
struct ipw_priv { struct ipw_priv {
/* ieee device used by generic ieee processing code */ /* ieee device used by generic ieee processing code */
struct ieee80211_device *ieee; struct ieee80211_device *ieee;
@ -1133,6 +1179,12 @@ struct ipw_priv {
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
struct net_device *net_dev; struct net_device *net_dev;
#ifdef CONFIG_IPW2200_PROMISCUOUS
/* Promiscuous mode */
struct ipw_prom_priv *prom_priv;
struct net_device *prom_net_dev;
#endif
/* pci hardware address support */ /* pci hardware address support */
void __iomem *hw_base; void __iomem *hw_base;
unsigned long hw_len; unsigned long hw_len;
@ -1153,11 +1205,9 @@ struct ipw_priv {
u32 config; u32 config;
u32 capability; u32 capability;
u8 last_rx_rssi;
u8 last_noise;
struct average average_missed_beacons; struct average average_missed_beacons;
struct average average_rssi; s16 exp_avg_rssi;
struct average average_noise; s16 exp_avg_noise;
u32 port_type; u32 port_type;
int rx_bufs_min; /**< minimum number of bufs in Rx queue */ int rx_bufs_min; /**< minimum number of bufs in Rx queue */
int rx_pend_max; /**< maximum pending buffers for one IRQ */ int rx_pend_max; /**< maximum pending buffers for one IRQ */
@ -1308,6 +1358,29 @@ struct ipw_priv {
/* debug macros */ /* debug macros */
/* Debug and printf string expansion helpers for printing bitfields */
#define BIT_FMT8 "%c%c%c%c-%c%c%c%c"
#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8
#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16
#define BITC(x,y) (((x>>y)&1)?'1':'0')
#define BIT_ARG8(x) \
BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\
BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0)
#define BIT_ARG16(x) \
BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\
BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\
BIT_ARG8(x)
#define BIT_ARG32(x) \
BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\
BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\
BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\
BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\
BIT_ARG16(x)
#ifdef CONFIG_IPW2200_DEBUG #ifdef CONFIG_IPW2200_DEBUG
#define IPW_DEBUG(level, fmt, args...) \ #define IPW_DEBUG(level, fmt, args...) \
do { if (ipw_debug_level & (level)) \ do { if (ipw_debug_level & (level)) \

View File

@ -201,41 +201,12 @@ static struct {
/* Data types */ /* Data types */
/********************************************************************/ /********************************************************************/
/* Used in Event handling. /* Beginning of the Tx descriptor, used in TxExc handling */
* We avoid nested structures as they break on ARM -- Moustafa */ struct hermes_txexc_data {
struct hermes_tx_descriptor_802_11 { struct hermes_tx_descriptor desc;
/* hermes_tx_descriptor */
__le16 status;
__le16 reserved1;
__le16 reserved2;
__le32 sw_support;
u8 retry_count;
u8 tx_rate;
__le16 tx_control;
/* ieee80211_hdr */
__le16 frame_ctl; __le16 frame_ctl;
__le16 duration_id; __le16 duration_id;
u8 addr1[ETH_ALEN]; u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
__le16 seq_ctl;
u8 addr4[ETH_ALEN];
__le16 data_len;
/* ethhdr */
u8 h_dest[ETH_ALEN]; /* destination eth addr */
u8 h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
/* p8022_hdr */
u8 dsap;
u8 ssap;
u8 ctrl;
u8 oui[3];
__be16 ethertype;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Rx frame header except compatibility 802.3 header */ /* Rx frame header except compatibility 802.3 header */
@ -450,53 +421,39 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int err = 0; int err = 0;
u16 txfid = priv->txfid; u16 txfid = priv->txfid;
char *p;
struct ethhdr *eh; struct ethhdr *eh;
int len, data_len, data_off; int data_off;
struct hermes_tx_descriptor desc; struct hermes_tx_descriptor desc;
unsigned long flags; unsigned long flags;
TRACE_ENTER(dev->name);
if (! netif_running(dev)) { if (! netif_running(dev)) {
printk(KERN_ERR "%s: Tx on stopped device!\n", printk(KERN_ERR "%s: Tx on stopped device!\n",
dev->name); dev->name);
TRACE_EXIT(dev->name); return NETDEV_TX_BUSY;
return 1;
} }
if (netif_queue_stopped(dev)) { if (netif_queue_stopped(dev)) {
printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
dev->name); dev->name);
TRACE_EXIT(dev->name); return NETDEV_TX_BUSY;
return 1;
} }
if (orinoco_lock(priv, &flags) != 0) { if (orinoco_lock(priv, &flags) != 0) {
printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
dev->name); dev->name);
TRACE_EXIT(dev->name); return NETDEV_TX_BUSY;
return 1;
} }
if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) { if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
/* Oops, the firmware hasn't established a connection, /* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the silently drop the packet (this seems to be the
safest approach). */ safest approach). */
stats->tx_errors++; goto drop;
orinoco_unlock(priv, &flags);
dev_kfree_skb(skb);
TRACE_EXIT(dev->name);
return 0;
} }
/* Length of the packet body */ /* Check packet length */
/* FIXME: what if the skb is smaller than this? */ if (skb->len < ETH_HLEN)
len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN); goto drop;
skb = skb_padto(skb, len);
if (skb == NULL)
goto fail;
len -= ETH_HLEN;
eh = (struct ethhdr *)skb->data; eh = (struct ethhdr *)skb->data;
@ -507,8 +464,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_ERR "%s: Error %d writing Tx descriptor " printk(KERN_ERR "%s: Error %d writing Tx descriptor "
"to BAP\n", dev->name, err); "to BAP\n", dev->name, err);
stats->tx_errors++; goto busy;
goto fail;
} }
/* Clear the 802.11 header and data length fields - some /* Clear the 802.11 header and data length fields - some
@ -519,50 +475,38 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
/* Encapsulate Ethernet-II frames */ /* Encapsulate Ethernet-II frames */
if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
struct header_struct hdr; struct header_struct {
data_len = len; struct ethhdr eth; /* 802.3 header */
data_off = HERMES_802_3_OFFSET + sizeof(hdr); u8 encap[6]; /* 802.2 header */
p = skb->data + ETH_HLEN; } __attribute__ ((packed)) hdr;
/* 802.3 header */ /* Strip destination and source from the data */
memcpy(hdr.dest, eh->h_dest, ETH_ALEN); skb_pull(skb, 2 * ETH_ALEN);
memcpy(hdr.src, eh->h_source, ETH_ALEN); data_off = HERMES_802_2_OFFSET + sizeof(encaps_hdr);
hdr.len = htons(data_len + ENCAPS_OVERHEAD);
/* 802.2 header */ /* And move them to a separate header */
memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
hdr.ethertype = eh->h_proto; err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, HERMES_802_3_OFFSET);
txfid, HERMES_802_3_OFFSET);
if (err) { if (err) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_ERR "%s: Error %d writing packet " printk(KERN_ERR "%s: Error %d writing packet "
"header to BAP\n", dev->name, err); "header to BAP\n", dev->name, err);
stats->tx_errors++; goto busy;
goto fail;
} }
/* Actual xfer length - allow for padding */
len = ALIGN(data_len, 2);
if (len < ETH_ZLEN - ETH_HLEN)
len = ETH_ZLEN - ETH_HLEN;
} else { /* IEEE 802.3 frame */ } else { /* IEEE 802.3 frame */
data_len = len + ETH_HLEN;
data_off = HERMES_802_3_OFFSET; data_off = HERMES_802_3_OFFSET;
p = skb->data;
/* Actual xfer length - round up for odd length packets */
len = ALIGN(data_len, 2);
if (len < ETH_ZLEN)
len = ETH_ZLEN;
} }
err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len, err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
txfid, data_off); txfid, data_off);
if (err) { if (err) {
printk(KERN_ERR "%s: Error %d writing packet to BAP\n", printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
dev->name, err); dev->name, err);
stats->tx_errors++; goto busy;
goto fail;
} }
/* Finally, we actually initiate the send */ /* Finally, we actually initiate the send */
@ -575,25 +519,27 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_ERR "%s: Error %d transmitting packet\n", printk(KERN_ERR "%s: Error %d transmitting packet\n",
dev->name, err); dev->name, err);
stats->tx_errors++; goto busy;
goto fail;
} }
dev->trans_start = jiffies; dev->trans_start = jiffies;
stats->tx_bytes += data_off + data_len; stats->tx_bytes += data_off + skb->len;
goto ok;
drop:
stats->tx_errors++;
stats->tx_dropped++;
ok:
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return NETDEV_TX_OK;
TRACE_EXIT(dev->name); busy:
if (err == -EIO)
return 0; schedule_work(&priv->reset_work);
fail:
TRACE_EXIT(dev->name);
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return err; return NETDEV_TX_BUSY;
} }
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
@ -629,7 +575,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
struct net_device_stats *stats = &priv->stats; struct net_device_stats *stats = &priv->stats;
u16 fid = hermes_read_regn(hw, TXCOMPLFID); u16 fid = hermes_read_regn(hw, TXCOMPLFID);
u16 status; u16 status;
struct hermes_tx_descriptor_802_11 hdr; struct hermes_txexc_data hdr;
int err = 0; int err = 0;
if (fid == DUMMY_FID) if (fid == DUMMY_FID)
@ -637,8 +583,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
/* Read part of the frame header - we need status and addr1 */ /* Read part of the frame header - we need status and addr1 */
err = hermes_bap_pread(hw, IRQ_BAP, &hdr, err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
offsetof(struct hermes_tx_descriptor_802_11, sizeof(struct hermes_txexc_data),
addr2),
fid, 0); fid, 0);
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
@ -658,7 +603,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
* exceeded, because that's the only status that really mean * exceeded, because that's the only status that really mean
* that this particular node went away. * that this particular node went away.
* Other errors means that *we* screwed up. - Jean II */ * Other errors means that *we* screwed up. - Jean II */
status = le16_to_cpu(hdr.status); status = le16_to_cpu(hdr.desc.status);
if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
union iwreq_data wrqu; union iwreq_data wrqu;
@ -1400,16 +1345,12 @@ int __orinoco_down(struct net_device *dev)
return 0; return 0;
} }
int orinoco_reinit_firmware(struct net_device *dev) static int orinoco_allocate_fid(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw; struct hermes *hw = &priv->hw;
int err; int err;
err = hermes_init(hw);
if (err)
return err;
err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
/* Try workaround for old Symbol firmware bug */ /* Try workaround for old Symbol firmware bug */
@ -1428,6 +1369,19 @@ int orinoco_reinit_firmware(struct net_device *dev)
return err; return err;
} }
int orinoco_reinit_firmware(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
err = hermes_init(hw);
if (!err)
err = orinoco_allocate_fid(dev);
return err;
}
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
{ {
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
@ -2274,14 +2228,12 @@ static int orinoco_init(struct net_device *dev)
u16 reclen; u16 reclen;
int len; int len;
TRACE_ENTER(dev->name);
/* No need to lock, the hw_unavailable flag is already set in /* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */ * alloc_orinocodev() */
priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN; priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
/* Initialize the firmware */ /* Initialize the firmware */
err = orinoco_reinit_firmware(dev); err = hermes_init(hw);
if (err != 0) { if (err != 0) {
printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n", printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
dev->name, err); dev->name, err);
@ -2339,6 +2291,13 @@ static int orinoco_init(struct net_device *dev)
printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
err = orinoco_allocate_fid(dev);
if (err) {
printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
dev->name);
goto out;
}
/* Get allowed channels */ /* Get allowed channels */
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
&priv->channel_mask); &priv->channel_mask);
@ -2429,7 +2388,6 @@ static int orinoco_init(struct net_device *dev)
printk(KERN_DEBUG "%s: ready\n", dev->name); printk(KERN_DEBUG "%s: ready\n", dev->name);
out: out:
TRACE_EXIT(dev->name);
return err; return err;
} }
@ -2797,8 +2755,6 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
int numrates; int numrates;
int i, k; int i, k;
TRACE_ENTER(dev->name);
rrq->length = sizeof(struct iw_range); rrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range)); memset(range, 0, sizeof(struct iw_range));
@ -2888,8 +2844,6 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
TRACE_EXIT(dev->name);
return 0; return 0;
} }
@ -3071,8 +3025,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
TRACE_ENTER(dev->name);
if (netif_running(dev)) { if (netif_running(dev)) {
err = orinoco_hw_get_essid(priv, &active, essidbuf); err = orinoco_hw_get_essid(priv, &active, essidbuf);
if (err) if (err)
@ -3087,8 +3039,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
erq->flags = 1; erq->flags = 1;
erq->length = strlen(essidbuf) + 1; erq->length = strlen(essidbuf) + 1;
TRACE_EXIT(dev->name);
return 0; return 0;
} }
@ -4348,69 +4298,6 @@ static struct ethtool_ops orinoco_ethtool_ops = {
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
}; };
/********************************************************************/
/* Debugging */
/********************************************************************/
#if 0
static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
{
printk(KERN_DEBUG "RX descriptor:\n");
printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status);
printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time);
printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence);
printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal);
printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate);
printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow);
printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved);
printk(KERN_DEBUG "IEEE 802.11 header:\n");
printk(KERN_DEBUG " frame_ctl = 0x%04x\n",
frame->p80211.frame_ctl);
printk(KERN_DEBUG " duration_id = 0x%04x\n",
frame->p80211.duration_id);
printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr1[0], frame->p80211.addr1[1],
frame->p80211.addr1[2], frame->p80211.addr1[3],
frame->p80211.addr1[4], frame->p80211.addr1[5]);
printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr2[0], frame->p80211.addr2[1],
frame->p80211.addr2[2], frame->p80211.addr2[3],
frame->p80211.addr2[4], frame->p80211.addr2[5]);
printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr3[0], frame->p80211.addr3[1],
frame->p80211.addr3[2], frame->p80211.addr3[3],
frame->p80211.addr3[4], frame->p80211.addr3[5]);
printk(KERN_DEBUG " seq_ctl = 0x%04x\n",
frame->p80211.seq_ctl);
printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr4[0], frame->p80211.addr4[1],
frame->p80211.addr4[2], frame->p80211.addr4[3],
frame->p80211.addr4[4], frame->p80211.addr4[5]);
printk(KERN_DEBUG " data_len = 0x%04x\n",
frame->p80211.data_len);
printk(KERN_DEBUG "IEEE 802.3 header:\n");
printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p8023.h_dest[0], frame->p8023.h_dest[1],
frame->p8023.h_dest[2], frame->p8023.h_dest[3],
frame->p8023.h_dest[4], frame->p8023.h_dest[5]);
printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p8023.h_source[0], frame->p8023.h_source[1],
frame->p8023.h_source[2], frame->p8023.h_source[3],
frame->p8023.h_source[4], frame->p8023.h_source[5]);
printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto);
printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n");
printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap);
printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap);
printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl);
printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n",
frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype);
}
#endif /* 0 */
/********************************************************************/ /********************************************************************/
/* Module initialization */ /* Module initialization */
/********************************************************************/ /********************************************************************/

View File

@ -7,7 +7,7 @@
#ifndef _ORINOCO_H #ifndef _ORINOCO_H
#define _ORINOCO_H #define _ORINOCO_H
#define DRIVER_VERSION "0.15rc3" #define DRIVER_VERSION "0.15"
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/wireless.h> #include <linux/wireless.h>
@ -30,20 +30,6 @@ struct orinoco_key {
char data[ORINOCO_MAX_KEY_SIZE]; char data[ORINOCO_MAX_KEY_SIZE];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct header_struct {
/* 802.3 */
u8 dest[ETH_ALEN];
u8 src[ETH_ALEN];
__be16 len;
/* 802.2 */
u8 dsap;
u8 ssap;
u8 ctrl;
/* SNAP */
u8 oui[3];
unsigned short ethertype;
} __attribute__ ((packed));
typedef enum { typedef enum {
FIRMWARE_TYPE_AGERE, FIRMWARE_TYPE_AGERE,
FIRMWARE_TYPE_INTERSIL, FIRMWARE_TYPE_INTERSIL,
@ -132,9 +118,6 @@ extern int orinoco_debug;
#define DEBUG(n, args...) do { } while (0) #define DEBUG(n, args...) do { } while (0)
#endif /* ORINOCO_DEBUG */ #endif /* ORINOCO_DEBUG */
#define TRACE_ENTER(devname) DEBUG(2, "%s: -> %s()\n", devname, __FUNCTION__);
#define TRACE_EXIT(devname) DEBUG(2, "%s: <- %s()\n", devname, __FUNCTION__);
/********************************************************************/ /********************************************************************/
/* Exported prototypes */ /* Exported prototypes */
/********************************************************************/ /********************************************************************/

View File

@ -178,13 +178,10 @@ orinoco_cs_config(struct pcmcia_device *link)
int last_fn, last_ret; int last_fn, last_ret;
u_char buf[64]; u_char buf[64];
config_info_t conf; config_info_t conf;
cisinfo_t info;
tuple_t tuple; tuple_t tuple;
cisparse_t parse; cisparse_t parse;
void __iomem *mem; void __iomem *mem;
CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
/* /*
* This reads the card's CONFIG tuple to find its * This reads the card's CONFIG tuple to find its
* configuration registers. * configuration registers.
@ -234,12 +231,6 @@ orinoco_cs_config(struct pcmcia_device *link)
goto next_entry; goto next_entry;
link->conf.ConfigIndex = cfg->index; link->conf.ConfigIndex = cfg->index;
/* Does this card need audio output? */
if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
}
/* Use power settings for Vcc and Vpp if present */ /* Use power settings for Vcc and Vpp if present */
/* Note that the CIS values need to be rescaled */ /* Note that the CIS values need to be rescaled */
if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {

View File

@ -3,7 +3,6 @@
* Driver for Prism II devices which would usually be driven by orinoco_cs, * Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
* Nortel emobility, Symbol LA-4113 and Symbol LA-4123. * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
* but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter.
* *
* Copyright (C) 2002 Tobias Hoffmann * Copyright (C) 2002 Tobias Hoffmann
* (C) 2003 Christoph Jungegger <disdos@traum404.de> * (C) 2003 Christoph Jungegger <disdos@traum404.de>
@ -50,67 +49,62 @@
#include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h>
#include "orinoco.h" #include "orinoco.h"
#include "orinoco_pci.h"
#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ #define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
/* Nortel specific data */
struct nortel_pci_card {
unsigned long iobase1;
unsigned long iobase2;
};
/* /*
* Do a soft reset of the PCI card using the Configuration Option Register * Do a soft reset of the card using the Configuration Option Register
* We need this to get going... * We need this to get going...
* This is the part of the code that is strongly inspired from wlan-ng * This is the part of the code that is strongly inspired from wlan-ng
* *
* Note bis : Don't try to access HERMES_CMD during the reset phase. * Note bis : Don't try to access HERMES_CMD during the reset phase.
* It just won't work ! * It just won't work !
*/ */
static int nortel_pci_cor_reset(struct orinoco_private *priv) static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
{ {
struct nortel_pci_card *card = priv->card; struct orinoco_pci_card *card = priv->card;
/* Assert the reset until the card notice */ /* Assert the reset until the card notices */
outw_p(8, card->iobase1 + 2); iowrite16(8, card->bridge_io + 2);
inw(card->iobase2 + COR_OFFSET); ioread16(card->attr_io + COR_OFFSET);
outw_p(0x80, card->iobase2 + COR_OFFSET); iowrite16(0x80, card->attr_io + COR_OFFSET);
mdelay(1); mdelay(1);
/* Give time for the card to recover from this hard effort */ /* Give time for the card to recover from this hard effort */
outw_p(0, card->iobase2 + COR_OFFSET); iowrite16(0, card->attr_io + COR_OFFSET);
outw_p(0, card->iobase2 + COR_OFFSET); iowrite16(0, card->attr_io + COR_OFFSET);
mdelay(1); mdelay(1);
/* set COR as usual */ /* Set COR as usual */
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET); iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET); iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
mdelay(1); mdelay(1);
outw_p(0x228, card->iobase1 + 2); iowrite16(0x228, card->bridge_io + 2);
return 0; return 0;
} }
static int nortel_pci_hw_init(struct nortel_pci_card *card) static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
{ {
int i; int i;
u32 reg; u32 reg;
/* setup bridge */ /* Setup bridge */
if (inw(card->iobase1) & 1) { if (ioread16(card->bridge_io) & 1) {
printk(KERN_ERR PFX "brg1 answer1 wrong\n"); printk(KERN_ERR PFX "brg1 answer1 wrong\n");
return -EBUSY; return -EBUSY;
} }
outw_p(0x118, card->iobase1 + 2); iowrite16(0x118, card->bridge_io + 2);
outw_p(0x108, card->iobase1 + 2); iowrite16(0x108, card->bridge_io + 2);
mdelay(30); mdelay(30);
outw_p(0x8, card->iobase1 + 2); iowrite16(0x8, card->bridge_io + 2);
for (i = 0; i < 30; i++) { for (i = 0; i < 30; i++) {
mdelay(30); mdelay(30);
if (inw(card->iobase1) & 0x10) { if (ioread16(card->bridge_io) & 0x10) {
break; break;
} }
} }
@ -118,42 +112,42 @@ static int nortel_pci_hw_init(struct nortel_pci_card *card)
printk(KERN_ERR PFX "brg1 timed out\n"); printk(KERN_ERR PFX "brg1 timed out\n");
return -EBUSY; return -EBUSY;
} }
if (inw(card->iobase2 + 0xe0) & 1) { if (ioread16(card->attr_io + COR_OFFSET) & 1) {
printk(KERN_ERR PFX "brg2 answer1 wrong\n"); printk(KERN_ERR PFX "brg2 answer1 wrong\n");
return -EBUSY; return -EBUSY;
} }
if (inw(card->iobase2 + 0xe2) & 1) { if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
printk(KERN_ERR PFX "brg2 answer2 wrong\n"); printk(KERN_ERR PFX "brg2 answer2 wrong\n");
return -EBUSY; return -EBUSY;
} }
if (inw(card->iobase2 + 0xe4) & 1) { if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
printk(KERN_ERR PFX "brg2 answer3 wrong\n"); printk(KERN_ERR PFX "brg2 answer3 wrong\n");
return -EBUSY; return -EBUSY;
} }
/* set the PCMCIA COR-Register */ /* Set the PCMCIA COR register */
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET); iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
mdelay(1); mdelay(1);
reg = inw(card->iobase2 + COR_OFFSET); reg = ioread16(card->attr_io + COR_OFFSET);
if (reg != COR_VALUE) { if (reg != COR_VALUE) {
printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n", printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
reg); reg);
return -EBUSY; return -EBUSY;
} }
/* set leds */ /* Set LEDs */
outw_p(1, card->iobase1 + 10); iowrite16(1, card->bridge_io + 10);
return 0; return 0;
} }
static int nortel_pci_init_one(struct pci_dev *pdev, static int orinoco_nortel_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
int err; int err;
struct orinoco_private *priv; struct orinoco_private *priv;
struct nortel_pci_card *card; struct orinoco_pci_card *card;
struct net_device *dev; struct net_device *dev;
void __iomem *iomem; void __iomem *hermes_io, *bridge_io, *attr_io;
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) { if (err) {
@ -162,19 +156,34 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
} }
err = pci_request_regions(pdev, DRIVER_NAME); err = pci_request_regions(pdev, DRIVER_NAME);
if (err != 0) { if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources; goto fail_resources;
} }
iomem = pci_iomap(pdev, 2, 0); bridge_io = pci_iomap(pdev, 0, 0);
if (!iomem) { if (!bridge_io) {
err = -ENOMEM; printk(KERN_ERR PFX "Cannot map bridge registers\n");
goto fail_map_io; err = -EIO;
goto fail_map_bridge;
}
attr_io = pci_iomap(pdev, 1, 0);
if (!attr_io) {
printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
err = -EIO;
goto fail_map_attr;
}
hermes_io = pci_iomap(pdev, 2, 0);
if (!hermes_io) {
printk(KERN_ERR PFX "Cannot map chipset registers\n");
err = -EIO;
goto fail_map_hermes;
} }
/* Allocate network device */ /* Allocate network device */
dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset); dev = alloc_orinocodev(sizeof(*card), orinoco_nortel_cor_reset);
if (!dev) { if (!dev) {
printk(KERN_ERR PFX "Cannot allocate network device\n"); printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM; err = -ENOMEM;
@ -183,16 +192,12 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev); priv = netdev_priv(dev);
card = priv->card; card = priv->card;
card->iobase1 = pci_resource_start(pdev, 0); card->bridge_io = bridge_io;
card->iobase2 = pci_resource_start(pdev, 1); card->attr_io = attr_io;
dev->base_addr = pci_resource_start(pdev, 2);
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, iomem, HERMES_16BIT_REGSPACING); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
printk(KERN_DEBUG PFX "Detected Nortel PCI device at %s irq:%d, "
"io addr:0x%lx\n", pci_name(pdev), pdev->irq, dev->base_addr);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev); dev->name, dev);
@ -201,21 +206,20 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
err = -EBUSY; err = -EBUSY;
goto fail_irq; goto fail_irq;
} }
dev->irq = pdev->irq; orinoco_pci_setup_netdev(dev, pdev, 2);
err = nortel_pci_hw_init(card); err = orinoco_nortel_hw_init(card);
if (err) { if (err) {
printk(KERN_ERR PFX "Hardware initialization failed\n"); printk(KERN_ERR PFX "Hardware initialization failed\n");
goto fail; goto fail;
} }
err = nortel_pci_cor_reset(priv); err = orinoco_nortel_cor_reset(priv);
if (err) { if (err) {
printk(KERN_ERR PFX "Initial reset failed\n"); printk(KERN_ERR PFX "Initial reset failed\n");
goto fail; goto fail;
} }
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
printk(KERN_ERR PFX "Cannot register network device\n"); printk(KERN_ERR PFX "Cannot register network device\n");
@ -234,9 +238,15 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
free_orinocodev(dev); free_orinocodev(dev);
fail_alloc: fail_alloc:
pci_iounmap(pdev, iomem); pci_iounmap(pdev, hermes_io);
fail_map_io: fail_map_hermes:
pci_iounmap(pdev, attr_io);
fail_map_attr:
pci_iounmap(pdev, bridge_io);
fail_map_bridge:
pci_release_regions(pdev); pci_release_regions(pdev);
fail_resources: fail_resources:
@ -245,26 +255,27 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
return err; return err;
} }
static void __devexit nortel_pci_remove_one(struct pci_dev *pdev) static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct nortel_pci_card *card = priv->card; struct orinoco_pci_card *card = priv->card;
/* clear leds */ /* Clear LEDs */
outw_p(0, card->iobase1 + 10); iowrite16(0, card->bridge_io + 10);
unregister_netdev(dev); unregister_netdev(dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
free_orinocodev(dev); free_orinocodev(dev);
pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev); pci_release_regions(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static struct pci_device_id orinoco_nortel_id_table[] = {
static struct pci_device_id nortel_pci_id_table[] = {
/* Nortel emobility PCI */ /* Nortel emobility PCI */
{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
/* Symbol LA-4123 PCI */ /* Symbol LA-4123 PCI */
@ -272,13 +283,15 @@ static struct pci_device_id nortel_pci_id_table[] = {
{0,}, {0,},
}; };
MODULE_DEVICE_TABLE(pci, nortel_pci_id_table); MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
static struct pci_driver nortel_pci_driver = { static struct pci_driver orinoco_nortel_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = nortel_pci_id_table, .id_table = orinoco_nortel_id_table,
.probe = nortel_pci_init_one, .probe = orinoco_nortel_init_one,
.remove = __devexit_p(nortel_pci_remove_one), .remove = __devexit_p(orinoco_nortel_remove_one),
.suspend = orinoco_pci_suspend,
.resume = orinoco_pci_resume,
}; };
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
@ -288,20 +301,19 @@ MODULE_DESCRIPTION
("Driver for wireless LAN cards using the Nortel PCI bridge"); ("Driver for wireless LAN cards using the Nortel PCI bridge");
MODULE_LICENSE("Dual MPL/GPL"); MODULE_LICENSE("Dual MPL/GPL");
static int __init nortel_pci_init(void) static int __init orinoco_nortel_init(void)
{ {
printk(KERN_DEBUG "%s\n", version); printk(KERN_DEBUG "%s\n", version);
return pci_module_init(&nortel_pci_driver); return pci_module_init(&orinoco_nortel_driver);
} }
static void __exit nortel_pci_exit(void) static void __exit orinoco_nortel_exit(void)
{ {
pci_unregister_driver(&nortel_pci_driver); pci_unregister_driver(&orinoco_nortel_driver);
ssleep(1);
} }
module_init(nortel_pci_init); module_init(orinoco_nortel_init);
module_exit(nortel_pci_exit); module_exit(orinoco_nortel_exit);
/* /*
* Local variables: * Local variables:

View File

@ -1,11 +1,11 @@
/* orinoco_pci.c /* orinoco_pci.c
* *
* Driver for Prism II devices that have a direct PCI interface * Driver for Prism 2.5/3 devices that have a direct PCI interface
* (i.e., not in a Pcmcia or PLX bridge) * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
* The card contains only one PCI region, which contains all the usual
* hermes registers, as well as the COR register.
* *
* Specifically here we're talking about the Linksys WMP11 * Current maintainers are:
*
* Current maintainers (as of 29 September 2003) are:
* Pavel Roskin <proski AT gnu.org> * Pavel Roskin <proski AT gnu.org>
* and David Gibson <hermes AT gibson.dropbear.id.au> * and David Gibson <hermes AT gibson.dropbear.id.au>
* *
@ -41,54 +41,6 @@
* under either the MPL or the GPL. * under either the MPL or the GPL.
*/ */
/*
* Theory of operation...
* -------------------
* Maybe you had a look in orinoco_plx. Well, this is totally different...
*
* The card contains only one PCI region, which contains all the usual
* hermes registers.
*
* The driver will memory map this region in normal memory. Because
* the hermes registers are mapped in normal memory and not in ISA I/O
* post space, we can't use the usual inw/outw macros and we need to
* use readw/writew.
* This slight difference force us to compile our own version of
* hermes.c with the register access macro changed. That's a bit
* hackish but works fine.
*
* Note that the PCI region is pretty big (4K). That's much more than
* the usual set of hermes register (0x0 -> 0x3E). I've got a strong
* suspicion that the whole memory space of the adapter is in fact in
* this region. Accessing directly the adapter memory instead of going
* through the usual register would speed up significantely the
* operations...
*
* Finally, the card looks like this :
-----------------------
Bus 0, device 14, function 0:
Network controller: PCI device 1260:3873 (Harris Semiconductor) (rev 1).
IRQ 11.
Master Capable. Latency=248.
Prefetchable 32 bit memory at 0xffbcc000 [0xffbccfff].
-----------------------
00:0e.0 Network controller: Harris Semiconductor: Unknown device 3873 (rev 01)
Subsystem: Unknown device 1737:3874
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Latency: 248 set, cache line size 08
Interrupt: pin A routed to IRQ 11
Region 0: Memory at ffbcc000 (32-bit, prefetchable) [size=4K]
Capabilities: [dc] Power Management version 2
Flags: PMEClk- AuxPwr- DSI- D1+ D2+ PME+
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
-----------------------
*
* That's all..
*
* Jean II
*/
#define DRIVER_NAME "orinoco_pci" #define DRIVER_NAME "orinoco_pci"
#define PFX DRIVER_NAME ": " #define PFX DRIVER_NAME ": "
@ -100,12 +52,14 @@
#include <linux/pci.h> #include <linux/pci.h>
#include "orinoco.h" #include "orinoco.h"
#include "orinoco_pci.h"
/* All the magic there is from wlan-ng */ /* Offset of the COR register of the PCI card */
/* Magic offset of the reset register of the PCI card */
#define HERMES_PCI_COR (0x26) #define HERMES_PCI_COR (0x26)
/* Magic bitmask to reset the card */
/* Bitmask to reset the card */
#define HERMES_PCI_COR_MASK (0x0080) #define HERMES_PCI_COR_MASK (0x0080)
/* Magic timeouts for doing the reset. /* Magic timeouts for doing the reset.
* Those times are straight from wlan-ng, and it is claimed that they * Those times are straight from wlan-ng, and it is claimed that they
* are necessary. Alan will kill me. Take your time and grab a coffee. */ * are necessary. Alan will kill me. Take your time and grab a coffee. */
@ -113,13 +67,8 @@
#define HERMES_PCI_COR_OFFT (500) /* ms */ #define HERMES_PCI_COR_OFFT (500) /* ms */
#define HERMES_PCI_COR_BUSYT (500) /* ms */ #define HERMES_PCI_COR_BUSYT (500) /* ms */
/* Orinoco PCI specific data */
struct orinoco_pci_card {
void __iomem *pci_ioaddr;
};
/* /*
* Do a soft reset of the PCI card using the Configuration Option Register * Do a soft reset of the card using the Configuration Option Register
* We need this to get going... * We need this to get going...
* This is the part of the code that is strongly inspired from wlan-ng * This is the part of the code that is strongly inspired from wlan-ng
* *
@ -131,14 +80,13 @@ struct orinoco_pci_card {
* Note bis : Don't try to access HERMES_CMD during the reset phase. * Note bis : Don't try to access HERMES_CMD during the reset phase.
* It just won't work ! * It just won't work !
*/ */
static int static int orinoco_pci_cor_reset(struct orinoco_private *priv)
orinoco_pci_cor_reset(struct orinoco_private *priv)
{ {
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
unsigned long timeout; unsigned long timeout;
u16 reg; u16 reg;
/* Assert the reset until the card notice */ /* Assert the reset until the card notices */
hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
mdelay(HERMES_PCI_COR_ONT); mdelay(HERMES_PCI_COR_ONT);
@ -163,19 +111,14 @@ orinoco_pci_cor_reset(struct orinoco_private *priv)
return 0; return 0;
} }
/*
* Initialise a card. Mostly similar to PLX code.
*/
static int orinoco_pci_init_one(struct pci_dev *pdev, static int orinoco_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
int err = 0; int err;
unsigned long pci_iorange; struct orinoco_private *priv;
u16 __iomem *pci_ioaddr = NULL;
unsigned long pci_iolen;
struct orinoco_private *priv = NULL;
struct orinoco_pci_card *card; struct orinoco_pci_card *card;
struct net_device *dev = NULL; struct net_device *dev;
void __iomem *hermes_io;
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) { if (err) {
@ -184,39 +127,32 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
} }
err = pci_request_regions(pdev, DRIVER_NAME); err = pci_request_regions(pdev, DRIVER_NAME);
if (err != 0) { if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources; goto fail_resources;
} }
/* Resource 0 is mapped to the hermes registers */ hermes_io = pci_iomap(pdev, 0, 0);
pci_iorange = pci_resource_start(pdev, 0); if (!hermes_io) {
pci_iolen = pci_resource_len(pdev, 0); printk(KERN_ERR PFX "Cannot remap chipset registers\n");
pci_ioaddr = ioremap(pci_iorange, pci_iolen); err = -EIO;
if (!pci_iorange) { goto fail_map_hermes;
printk(KERN_ERR PFX "Cannot remap hardware registers\n");
goto fail_map;
} }
/* Allocate network device */ /* Allocate network device */
dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset); dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset);
if (! dev) { if (!dev) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM; err = -ENOMEM;
goto fail_alloc; goto fail_alloc;
} }
priv = netdev_priv(dev); priv = netdev_priv(dev);
card = priv->card; card = priv->card;
card->pci_ioaddr = pci_ioaddr;
dev->mem_start = pci_iorange;
dev->mem_end = pci_iorange + pci_iolen - 1;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, pci_ioaddr, HERMES_32BIT_REGSPACING); hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
printk(KERN_DEBUG PFX "Detected device %s, mem:0x%lx-0x%lx, irq %d\n",
pci_name(pdev), dev->mem_start, dev->mem_end, pdev->irq);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev); dev->name, dev);
@ -225,9 +161,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
err = -EBUSY; err = -EBUSY;
goto fail_irq; goto fail_irq;
} }
dev->irq = pdev->irq; orinoco_pci_setup_netdev(dev, pdev, 0);
/* Perform a COR reset to start the card */
err = orinoco_pci_cor_reset(priv); err = orinoco_pci_cor_reset(priv);
if (err) { if (err) {
printk(KERN_ERR PFX "Initial reset failed\n"); printk(KERN_ERR PFX "Initial reset failed\n");
@ -236,7 +171,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
printk(KERN_ERR PFX "Failed to register net device\n"); printk(KERN_ERR PFX "Cannot register network device\n");
goto fail; goto fail;
} }
@ -252,9 +187,9 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
free_orinocodev(dev); free_orinocodev(dev);
fail_alloc: fail_alloc:
iounmap(pci_ioaddr); pci_iounmap(pdev, hermes_io);
fail_map: fail_map_hermes:
pci_release_regions(pdev); pci_release_regions(pdev);
fail_resources: fail_resources:
@ -267,87 +202,17 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct orinoco_pci_card *card = priv->card;
unregister_netdev(dev); unregister_netdev(dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
free_orinocodev(dev); free_orinocodev(dev);
iounmap(card->pci_ioaddr); pci_iounmap(pdev, priv->hw.iobase);
pci_release_regions(pdev); pci_release_regions(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) static struct pci_device_id orinoco_pci_id_table[] = {
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
unsigned long flags;
int err;
err = orinoco_lock(priv, &flags);
if (err) {
printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n",
dev->name);
return err;
}
err = __orinoco_down(dev);
if (err)
printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n",
dev->name, err);
netif_device_detach(dev);
priv->hw_unavailable++;
orinoco_unlock(priv, &flags);
pci_save_state(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int orinoco_pci_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
unsigned long flags;
int err;
printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
pci_set_power_state(pdev, 0);
pci_restore_state(pdev);
err = orinoco_reinit_firmware(dev);
if (err) {
printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",
dev->name, err);
return err;
}
spin_lock_irqsave(&priv->lock, flags);
netif_device_attach(dev);
priv->hw_unavailable--;
if (priv->open && (! priv->hw_unavailable)) {
err = __orinoco_up(dev);
if (err)
printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n",
dev->name, err);
}
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static struct pci_device_id orinoco_pci_pci_id_table[] = {
/* Intersil Prism 3 */ /* Intersil Prism 3 */
{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
/* Intersil Prism 2.5 */ /* Intersil Prism 2.5 */
@ -357,11 +222,11 @@ static struct pci_device_id orinoco_pci_pci_id_table[] = {
{0,}, {0,},
}; };
MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table); MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
static struct pci_driver orinoco_pci_driver = { static struct pci_driver orinoco_pci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = orinoco_pci_pci_id_table, .id_table = orinoco_pci_id_table,
.probe = orinoco_pci_init_one, .probe = orinoco_pci_init_one,
.remove = __devexit_p(orinoco_pci_remove_one), .remove = __devexit_p(orinoco_pci_remove_one),
.suspend = orinoco_pci_suspend, .suspend = orinoco_pci_suspend,

View File

@ -0,0 +1,125 @@
/* orinoco_pci.h
*
* Common code for all Orinoco drivers for PCI devices, including
* both native PCI and PCMCIA-to-PCI bridges.
*
* Copyright (C) 2005, Pavel Roskin.
* See orinoco.c for license.
*/
#ifndef _ORINOCO_PCI_H
#define _ORINOCO_PCI_H
#include <linux/netdevice.h>
/* Driver specific data */
struct orinoco_pci_card {
void __iomem *bridge_io;
void __iomem *attr_io;
};
/* Set base address or memory range of the network device based on
* the PCI device it's using. Specify BAR of the "main" resource.
* To be used after request_irq(). */
static inline void orinoco_pci_setup_netdev(struct net_device *dev,
struct pci_dev *pdev, int bar)
{
char *range_type;
unsigned long start = pci_resource_start(pdev, bar);
unsigned long len = pci_resource_len(pdev, bar);
unsigned long flags = pci_resource_flags(pdev, bar);
unsigned long end = start + len - 1;
dev->irq = pdev->irq;
if (flags & IORESOURCE_IO) {
dev->base_addr = start;
range_type = "ports";
} else {
dev->mem_start = start;
dev->mem_end = end;
range_type = "memory";
}
printk(KERN_DEBUG PFX "%s: irq %d, %s 0x%lx-0x%lx\n",
pci_name(pdev), pdev->irq, range_type, start, end);
}
static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
unsigned long flags;
int err;
err = orinoco_lock(priv, &flags);
if (err) {
printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
dev->name);
return err;
}
err = __orinoco_down(dev);
if (err)
printk(KERN_WARNING "%s: error %d bringing interface down "
"for suspend\n", dev->name, err);
netif_device_detach(dev);
priv->hw_unavailable++;
orinoco_unlock(priv, &flags);
free_irq(pdev->irq, dev);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int orinoco_pci_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
unsigned long flags;
int err;
pci_set_power_state(pdev, 0);
pci_enable_device(pdev);
pci_restore_state(pdev);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev);
if (err) {
printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
dev->name);
pci_disable_device(pdev);
return -EBUSY;
}
err = orinoco_reinit_firmware(dev);
if (err) {
printk(KERN_ERR "%s: error %d re-initializing firmware "
"on resume\n", dev->name, err);
return err;
}
spin_lock_irqsave(&priv->lock, flags);
netif_device_attach(dev);
priv->hw_unavailable--;
if (priv->open && (! priv->hw_unavailable)) {
err = __orinoco_up(dev);
if (err)
printk(KERN_ERR "%s: Error %d restarting card on resume\n",
dev->name, err);
}
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
#endif /* _ORINOCO_PCI_H */

View File

@ -3,7 +3,7 @@
* Driver for Prism II devices which would usually be driven by orinoco_cs, * Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a PLX9052. * but are connected to the PCI bus by a PLX9052.
* *
* Current maintainers (as of 29 September 2003) are: * Current maintainers are:
* Pavel Roskin <proski AT gnu.org> * Pavel Roskin <proski AT gnu.org>
* and David Gibson <hermes AT gibson.dropbear.id.au> * and David Gibson <hermes AT gibson.dropbear.id.au>
* *
@ -30,38 +30,18 @@
* other provisions required by the GPL. If you do not delete the * other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the MPL or the GPL. * under either the MPL or the GPL.
* Caution: this is experimental and probably buggy. For success and
* failure reports for different cards and adaptors, see
* orinoco_plx_pci_id_table near the end of the file. If you have a
* card we don't have the PCI id for, and looks like it should work,
* drop me mail with the id and "it works"/"it doesn't work".
* *
* Note: if everything gets detected fine but it doesn't actually send * Here's the general details on how the PLX9052 adapter works:
* or receive packets, your first port of call should probably be to
* try newer firmware in the card. Especially if you're doing Ad-Hoc
* modes.
*
* The actual driving is done by orinoco.c, this is just resource
* allocation stuff. The explanation below is courtesy of Ryan Niemi
* on the linux-wlan-ng list at
* http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html
*
* The PLX9052-based cards (WL11000 and several others) are a
* different beast than the usual PCMCIA-based PRISM2 configuration
* expected by wlan-ng. Here's the general details on how the WL11000
* PCI adapter works:
* *
* - Two PCI I/O address spaces, one 0x80 long which contains the * - Two PCI I/O address spaces, one 0x80 long which contains the
* PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
* slot I/O address space. * slot I/O address space.
* *
* - One PCI memory address space, mapped to the PCMCIA memory space * - One PCI memory address space, mapped to the PCMCIA attribute space
* (containing the CIS). * (containing the CIS).
* *
* After identifying the I/O and memory space, you can read through * Using the later, you can read through the CIS data to make sure the
* the memory space to confirm the CIS's device ID or manufacturer ID * card is compatible with the driver. Keep in mind that the PCMCIA
* to make sure it's the expected card. qKeep in mind that the PCMCIA
* spec specifies the CIS as the lower 8 bits of each word read from * spec specifies the CIS as the lower 8 bits of each word read from
* the CIS, so to read the bytes of the CIS, read every other byte * the CIS, so to read the bytes of the CIS, read every other byte
* (0,2,4,...). Passing that test, you need to enable the I/O address * (0,2,4,...). Passing that test, you need to enable the I/O address
@ -71,7 +51,7 @@
* within the PCI memory space. Write 0x41 to the COR register to * within the PCI memory space. Write 0x41 to the COR register to
* enable I/O mode and to select level triggered interrupts. To * enable I/O mode and to select level triggered interrupts. To
* confirm you actually succeeded, read the COR register back and make * confirm you actually succeeded, read the COR register back and make
* sure it actually got set to 0x41, incase you have an unexpected * sure it actually got set to 0x41, in case you have an unexpected
* card inserted. * card inserted.
* *
* Following that, you can treat the second PCI I/O address space (the * Following that, you can treat the second PCI I/O address space (the
@ -101,16 +81,6 @@
* that, I've hot-swapped a number of times during debugging and * that, I've hot-swapped a number of times during debugging and
* driver development for various reasons (stuck WAIT# line after the * driver development for various reasons (stuck WAIT# line after the
* radio card's firmware locks up). * radio card's firmware locks up).
*
* Hope this is enough info for someone to add PLX9052 support to the
* wlan-ng card. In the case of the WL11000, the PCI ID's are
* 0x1639/0x0200, with matching subsystem ID's. Other PLX9052-based
* manufacturers other than Eumitcom (or on cards other than the
* WL11000) may have different PCI ID's.
*
* If anyone needs any more specific info, let me know. I haven't had
* time to implement support myself yet, and with the way things are
* going, might not have time for a while..
*/ */
#define DRIVER_NAME "orinoco_plx" #define DRIVER_NAME "orinoco_plx"
@ -125,6 +95,7 @@
#include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h>
#include "orinoco.h" #include "orinoco.h"
#include "orinoco_pci.h"
#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
@ -134,30 +105,20 @@
#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ #define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */
#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */
static const u8 cis_magic[] = {
0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
};
/* Orinoco PLX specific data */
struct orinoco_plx_card {
void __iomem *attr_mem;
};
/* /*
* Do a soft reset of the card using the Configuration Option Register * Do a soft reset of the card using the Configuration Option Register
*/ */
static int orinoco_plx_cor_reset(struct orinoco_private *priv) static int orinoco_plx_cor_reset(struct orinoco_private *priv)
{ {
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
struct orinoco_plx_card *card = priv->card; struct orinoco_pci_card *card = priv->card;
u8 __iomem *attr_mem = card->attr_mem;
unsigned long timeout; unsigned long timeout;
u16 reg; u16 reg;
writeb(COR_VALUE | COR_RESET, attr_mem + COR_OFFSET); iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
mdelay(1); mdelay(1);
writeb(COR_VALUE, attr_mem + COR_OFFSET); iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
mdelay(1); mdelay(1);
/* Just in case, wait more until the card is no longer busy */ /* Just in case, wait more until the card is no longer busy */
@ -168,7 +129,7 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv)
reg = hermes_read_regn(hw, CMD); reg = hermes_read_regn(hw, CMD);
} }
/* Did we timeout ? */ /* Still busy? */
if (reg & HERMES_CMD_BUSY) { if (reg & HERMES_CMD_BUSY) {
printk(KERN_ERR PFX "Busy timeout\n"); printk(KERN_ERR PFX "Busy timeout\n");
return -ETIMEDOUT; return -ETIMEDOUT;
@ -177,20 +138,55 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv)
return 0; return 0;
} }
static int orinoco_plx_hw_init(struct orinoco_pci_card *card)
{
int i;
u32 csr_reg;
static const u8 cis_magic[] = {
0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
};
printk(KERN_DEBUG PFX "CIS: ");
for (i = 0; i < 16; i++) {
printk("%02X:", ioread8(card->attr_io + (i << 1)));
}
printk("\n");
/* Verify whether a supported PC card is present */
/* FIXME: we probably need to be smarted about this */
for (i = 0; i < sizeof(cis_magic); i++) {
if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
printk(KERN_ERR PFX "The CIS value of Prism2 PC "
"card is unexpected\n");
return -ENODEV;
}
}
/* bjoern: We need to tell the card to enable interrupts, in
case the serial eprom didn't do this already. See the
PLX9052 data book, p8-1 and 8-24 for reference. */
csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
if (!(csr_reg & PLX_INTCSR_INTEN)) {
csr_reg |= PLX_INTCSR_INTEN;
iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
if (!(csr_reg & PLX_INTCSR_INTEN)) {
printk(KERN_ERR PFX "Cannot enable interrupts\n");
return -EIO;
}
}
return 0;
}
static int orinoco_plx_init_one(struct pci_dev *pdev, static int orinoco_plx_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
int err = 0; int err;
u8 __iomem *attr_mem = NULL; struct orinoco_private *priv;
u32 csr_reg, plx_addr; struct orinoco_pci_card *card;
struct orinoco_private *priv = NULL; struct net_device *dev;
struct orinoco_plx_card *card; void __iomem *hermes_io, *attr_io, *bridge_io;
unsigned long pccard_ioaddr = 0;
unsigned long pccard_iolen = 0;
struct net_device *dev = NULL;
void __iomem *mem;
int i;
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) { if (err) {
@ -199,30 +195,30 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
} }
err = pci_request_regions(pdev, DRIVER_NAME); err = pci_request_regions(pdev, DRIVER_NAME);
if (err != 0) { if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources; goto fail_resources;
} }
/* Resource 1 is mapped to PLX-specific registers */ bridge_io = pci_iomap(pdev, 1, 0);
plx_addr = pci_resource_start(pdev, 1); if (!bridge_io) {
printk(KERN_ERR PFX "Cannot map bridge registers\n");
err = -EIO;
goto fail_map_bridge;
}
/* Resource 2 is mapped to the PCMCIA attribute memory */ attr_io = pci_iomap(pdev, 2, 0);
attr_mem = ioremap(pci_resource_start(pdev, 2), if (!attr_io) {
pci_resource_len(pdev, 2)); printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
if (!attr_mem) { err = -EIO;
printk(KERN_ERR PFX "Cannot remap PCMCIA space\n");
goto fail_map_attr; goto fail_map_attr;
} }
/* Resource 3 is mapped to the PCMCIA I/O address space */ hermes_io = pci_iomap(pdev, 3, 0);
pccard_ioaddr = pci_resource_start(pdev, 3); if (!hermes_io) {
pccard_iolen = pci_resource_len(pdev, 3); printk(KERN_ERR PFX "Cannot map chipset registers\n");
err = -EIO;
mem = pci_iomap(pdev, 3, 0); goto fail_map_hermes;
if (!mem) {
err = -ENOMEM;
goto fail_map_io;
} }
/* Allocate network device */ /* Allocate network device */
@ -235,16 +231,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev); priv = netdev_priv(dev);
card = priv->card; card = priv->card;
card->attr_mem = attr_mem; card->bridge_io = bridge_io;
dev->base_addr = pccard_ioaddr; card->attr_io = attr_io;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device "
"at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
pccard_ioaddr);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev); dev->name, dev);
@ -253,20 +245,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
err = -EBUSY; err = -EBUSY;
goto fail_irq; goto fail_irq;
} }
dev->irq = pdev->irq; orinoco_pci_setup_netdev(dev, pdev, 2);
/* bjoern: We need to tell the card to enable interrupts, in err = orinoco_plx_hw_init(card);
case the serial eprom didn't do this already. See the if (err) {
PLX9052 data book, p8-1 and 8-24 for reference. */ printk(KERN_ERR PFX "Hardware initialization failed\n");
csr_reg = inl(plx_addr + PLX_INTCSR); goto fail;
if (!(csr_reg & PLX_INTCSR_INTEN)) {
csr_reg |= PLX_INTCSR_INTEN;
outl(csr_reg, plx_addr + PLX_INTCSR);
csr_reg = inl(plx_addr + PLX_INTCSR);
if (!(csr_reg & PLX_INTCSR_INTEN)) {
printk(KERN_ERR PFX "Cannot enable interrupts\n");
goto fail;
}
} }
err = orinoco_plx_cor_reset(priv); err = orinoco_plx_cor_reset(priv);
@ -275,23 +259,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
goto fail; goto fail;
} }
printk(KERN_DEBUG PFX "CIS: ");
for (i = 0; i < 16; i++) {
printk("%02X:", readb(attr_mem + 2*i));
}
printk("\n");
/* Verify whether a supported PC card is present */
/* FIXME: we probably need to be smarted about this */
for (i = 0; i < sizeof(cis_magic); i++) {
if (cis_magic[i] != readb(attr_mem +2*i)) {
printk(KERN_ERR PFX "The CIS value of Prism2 PC "
"card is unexpected\n");
err = -EIO;
goto fail;
}
}
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
printk(KERN_ERR PFX "Cannot register network device\n"); printk(KERN_ERR PFX "Cannot register network device\n");
@ -310,12 +277,15 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
free_orinocodev(dev); free_orinocodev(dev);
fail_alloc: fail_alloc:
pci_iounmap(pdev, mem); pci_iounmap(pdev, hermes_io);
fail_map_io: fail_map_hermes:
iounmap(attr_mem); pci_iounmap(pdev, attr_io);
fail_map_attr: fail_map_attr:
pci_iounmap(pdev, bridge_io);
fail_map_bridge:
pci_release_regions(pdev); pci_release_regions(pdev);
fail_resources: fail_resources:
@ -328,23 +298,20 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct orinoco_plx_card *card = priv->card; struct orinoco_pci_card *card = priv->card;
u8 __iomem *attr_mem = card->attr_mem;
BUG_ON(! dev);
unregister_netdev(dev); unregister_netdev(dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
free_orinocodev(dev); free_orinocodev(dev);
pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, priv->hw.iobase);
iounmap(attr_mem); pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev); pci_release_regions(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static struct pci_device_id orinoco_plx_id_table[] = {
static struct pci_device_id orinoco_plx_pci_id_table[] = {
{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */
{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */
@ -362,13 +329,15 @@ static struct pci_device_id orinoco_plx_pci_id_table[] = {
{0,}, {0,},
}; };
MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table); MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
static struct pci_driver orinoco_plx_driver = { static struct pci_driver orinoco_plx_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = orinoco_plx_pci_id_table, .id_table = orinoco_plx_id_table,
.probe = orinoco_plx_init_one, .probe = orinoco_plx_init_one,
.remove = __devexit_p(orinoco_plx_remove_one), .remove = __devexit_p(orinoco_plx_remove_one),
.suspend = orinoco_pci_suspend,
.resume = orinoco_pci_resume,
}; };
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
@ -388,7 +357,6 @@ static int __init orinoco_plx_init(void)
static void __exit orinoco_plx_exit(void) static void __exit orinoco_plx_exit(void)
{ {
pci_unregister_driver(&orinoco_plx_driver); pci_unregister_driver(&orinoco_plx_driver);
ssleep(1);
} }
module_init(orinoco_plx_init); module_init(orinoco_plx_init);

View File

@ -26,25 +26,13 @@
* other provisions required by the GPL. If you do not delete the * other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the MPL or the GPL. * under either the MPL or the GPL.
* Caution: this is experimental and probably buggy. For success and
* failure reports for different cards and adaptors, see
* orinoco_tmd_pci_id_table near the end of the file. If you have a
* card we don't have the PCI id for, and looks like it should work,
* drop me mail with the id and "it works"/"it doesn't work".
*
* Note: if everything gets detected fine but it doesn't actually send
* or receive packets, your first port of call should probably be to
* try newer firmware in the card. Especially if you're doing Ad-Hoc
* modes
* *
* The actual driving is done by orinoco.c, this is just resource * The actual driving is done by orinoco.c, this is just resource
* allocation stuff. * allocation stuff.
* *
* This driver is modeled after the orinoco_plx driver. The main * This driver is modeled after the orinoco_plx driver. The main
* difference is that the TMD chip has only IO port ranges and no * difference is that the TMD chip has only IO port ranges and doesn't
* memory space, i.e. no access to the CIS. Compared to the PLX chip, * provide access to the PCMCIA attribute space.
* the io range functionalities are exchanged.
* *
* Pheecom sells cards with the TMD chip as "ASIC version" * Pheecom sells cards with the TMD chip as "ASIC version"
*/ */
@ -61,32 +49,26 @@
#include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h>
#include "orinoco.h" #include "orinoco.h"
#include "orinoco_pci.h"
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
#define COR_RESET (0x80) /* reset bit in the COR register */ #define COR_RESET (0x80) /* reset bit in the COR register */
#define TMD_RESET_TIME (500) /* milliseconds */ #define TMD_RESET_TIME (500) /* milliseconds */
/* Orinoco TMD specific data */
struct orinoco_tmd_card {
u32 tmd_io;
};
/* /*
* Do a soft reset of the card using the Configuration Option Register * Do a soft reset of the card using the Configuration Option Register
*/ */
static int orinoco_tmd_cor_reset(struct orinoco_private *priv) static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
{ {
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
struct orinoco_tmd_card *card = priv->card; struct orinoco_pci_card *card = priv->card;
u32 addr = card->tmd_io;
unsigned long timeout; unsigned long timeout;
u16 reg; u16 reg;
outb(COR_VALUE | COR_RESET, addr); iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
mdelay(1); mdelay(1);
outb(COR_VALUE, addr); iowrite8(COR_VALUE, card->bridge_io);
mdelay(1); mdelay(1);
/* Just in case, wait more until the card is no longer busy */ /* Just in case, wait more until the card is no longer busy */
@ -97,7 +79,7 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
reg = hermes_read_regn(hw, CMD); reg = hermes_read_regn(hw, CMD);
} }
/* Did we timeout ? */ /* Still busy? */
if (reg & HERMES_CMD_BUSY) { if (reg & HERMES_CMD_BUSY) {
printk(KERN_ERR PFX "Busy timeout\n"); printk(KERN_ERR PFX "Busy timeout\n");
return -ETIMEDOUT; return -ETIMEDOUT;
@ -110,11 +92,11 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
static int orinoco_tmd_init_one(struct pci_dev *pdev, static int orinoco_tmd_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
int err = 0; int err;
struct orinoco_private *priv = NULL; struct orinoco_private *priv;
struct orinoco_tmd_card *card; struct orinoco_pci_card *card;
struct net_device *dev = NULL; struct net_device *dev;
void __iomem *mem; void __iomem *hermes_io, *bridge_io;
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) { if (err) {
@ -123,20 +105,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
} }
err = pci_request_regions(pdev, DRIVER_NAME); err = pci_request_regions(pdev, DRIVER_NAME);
if (err != 0) { if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources; goto fail_resources;
} }
mem = pci_iomap(pdev, 2, 0); bridge_io = pci_iomap(pdev, 1, 0);
if (! mem) { if (!bridge_io) {
err = -ENOMEM; printk(KERN_ERR PFX "Cannot map bridge registers\n");
goto fail_iomap; err = -EIO;
goto fail_map_bridge;
}
hermes_io = pci_iomap(pdev, 2, 0);
if (!hermes_io) {
printk(KERN_ERR PFX "Cannot map chipset registers\n");
err = -EIO;
goto fail_map_hermes;
} }
/* Allocate network device */ /* Allocate network device */
dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset); dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset);
if (! dev) { if (!dev) {
printk(KERN_ERR PFX "Cannot allocate network device\n"); printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM; err = -ENOMEM;
goto fail_alloc; goto fail_alloc;
@ -144,16 +134,11 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev); priv = netdev_priv(dev);
card = priv->card; card = priv->card;
card->tmd_io = pci_resource_start(pdev, 1); card->bridge_io = bridge_io;
dev->base_addr = pci_resource_start(pdev, 2);
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device "
"at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
dev->base_addr);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev); dev->name, dev);
@ -162,7 +147,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
err = -EBUSY; err = -EBUSY;
goto fail_irq; goto fail_irq;
} }
dev->irq = pdev->irq; orinoco_pci_setup_netdev(dev, pdev, 2);
err = orinoco_tmd_cor_reset(priv); err = orinoco_tmd_cor_reset(priv);
if (err) { if (err) {
@ -188,9 +173,12 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
free_orinocodev(dev); free_orinocodev(dev);
fail_alloc: fail_alloc:
pci_iounmap(pdev, mem); pci_iounmap(pdev, hermes_io);
fail_iomap: fail_map_hermes:
pci_iounmap(pdev, bridge_io);
fail_map_bridge:
pci_release_regions(pdev); pci_release_regions(pdev);
fail_resources: fail_resources:
@ -203,31 +191,32 @@ static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = dev->priv; struct orinoco_private *priv = dev->priv;
struct orinoco_pci_card *card = priv->card;
BUG_ON(! dev);
unregister_netdev(dev); unregister_netdev(dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
free_orinocodev(dev); free_orinocodev(dev);
pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev); pci_release_regions(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static struct pci_device_id orinoco_tmd_id_table[] = {
static struct pci_device_id orinoco_tmd_pci_id_table[] = {
{0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
{0,}, {0,},
}; };
MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table); MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table);
static struct pci_driver orinoco_tmd_driver = { static struct pci_driver orinoco_tmd_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = orinoco_tmd_pci_id_table, .id_table = orinoco_tmd_id_table,
.probe = orinoco_tmd_init_one, .probe = orinoco_tmd_init_one,
.remove = __devexit_p(orinoco_tmd_remove_one), .remove = __devexit_p(orinoco_tmd_remove_one),
.suspend = orinoco_pci_suspend,
.resume = orinoco_pci_resume,
}; };
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
@ -245,7 +234,6 @@ static int __init orinoco_tmd_init(void)
static void __exit orinoco_tmd_exit(void) static void __exit orinoco_tmd_exit(void)
{ {
pci_unregister_driver(&orinoco_tmd_driver); pci_unregister_driver(&orinoco_tmd_driver);
ssleep(1);
} }
module_init(orinoco_tmd_init); module_init(orinoco_tmd_init);

View File

@ -1,6 +1,6 @@
/* /*
* Driver for 802.11b cards using RAM-loadable Symbol firmware, such as * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
* Symbol Wireless Networker LA4100, CompactFlash cards by Socket * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
* Communications and Intel PRO/Wireless 2011B. * Communications and Intel PRO/Wireless 2011B.
* *
* The driver implements Symbol firmware download. The rest is handled * The driver implements Symbol firmware download. The rest is handled
@ -120,8 +120,8 @@ static void spectrum_cs_release(struct pcmcia_device *link);
* Each block has the following structure. * Each block has the following structure.
*/ */
struct dblock { struct dblock {
__le32 _addr; /* adapter address where to write the block */ __le32 addr; /* adapter address where to write the block */
__le16 _len; /* length of the data only, in bytes */ __le16 len; /* length of the data only, in bytes */
char data[0]; /* data to be written */ char data[0]; /* data to be written */
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -131,9 +131,9 @@ struct dblock {
* items with matching ID should be written. * items with matching ID should be written.
*/ */
struct pdr { struct pdr {
__le32 _id; /* record ID */ __le32 id; /* record ID */
__le32 _addr; /* adapter address where to write the data */ __le32 addr; /* adapter address where to write the data */
__le32 _len; /* expected length of the data, in bytes */ __le32 len; /* expected length of the data, in bytes */
char next[0]; /* next PDR starts here */ char next[0]; /* next PDR starts here */
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -144,8 +144,8 @@ struct pdr {
* be plugged into the secondary firmware. * be plugged into the secondary firmware.
*/ */
struct pdi { struct pdi {
__le16 _len; /* length of ID and data, in words */ __le16 len; /* length of ID and data, in words */
__le16 _id; /* record ID */ __le16 id; /* record ID */
char data[0]; /* plug data */ char data[0]; /* plug data */
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -154,44 +154,44 @@ struct pdi {
static inline u32 static inline u32
dblock_addr(const struct dblock *blk) dblock_addr(const struct dblock *blk)
{ {
return le32_to_cpu(blk->_addr); return le32_to_cpu(blk->addr);
} }
static inline u32 static inline u32
dblock_len(const struct dblock *blk) dblock_len(const struct dblock *blk)
{ {
return le16_to_cpu(blk->_len); return le16_to_cpu(blk->len);
} }
static inline u32 static inline u32
pdr_id(const struct pdr *pdr) pdr_id(const struct pdr *pdr)
{ {
return le32_to_cpu(pdr->_id); return le32_to_cpu(pdr->id);
} }
static inline u32 static inline u32
pdr_addr(const struct pdr *pdr) pdr_addr(const struct pdr *pdr)
{ {
return le32_to_cpu(pdr->_addr); return le32_to_cpu(pdr->addr);
} }
static inline u32 static inline u32
pdr_len(const struct pdr *pdr) pdr_len(const struct pdr *pdr)
{ {
return le32_to_cpu(pdr->_len); return le32_to_cpu(pdr->len);
} }
static inline u32 static inline u32
pdi_id(const struct pdi *pdi) pdi_id(const struct pdi *pdi)
{ {
return le16_to_cpu(pdi->_id); return le16_to_cpu(pdi->id);
} }
/* Return length of the data only, in bytes */ /* Return length of the data only, in bytes */
static inline u32 static inline u32
pdi_len(const struct pdi *pdi) pdi_len(const struct pdi *pdi)
{ {
return 2 * (le16_to_cpu(pdi->_len) - 1); return 2 * (le16_to_cpu(pdi->len) - 1);
} }
@ -343,8 +343,7 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
/* do the actual plugging */ /* do the actual plugging */
spectrum_aux_setaddr(hw, pdr_addr(pdr)); spectrum_aux_setaddr(hw, pdr_addr(pdr));
hermes_write_words(hw, HERMES_AUXDATA, pdi->data, hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
pdi_len(pdi) / 2);
return 0; return 0;
} }
@ -424,8 +423,8 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
while (dblock_addr(blk) != BLOCK_END) { while (dblock_addr(blk) != BLOCK_END) {
spectrum_aux_setaddr(hw, blkaddr); spectrum_aux_setaddr(hw, blkaddr);
hermes_write_words(hw, HERMES_AUXDATA, blk->data, hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
blklen / 2); blklen);
blk = (struct dblock *) &blk->data[blklen]; blk = (struct dblock *) &blk->data[blklen];
blkaddr = dblock_addr(blk); blkaddr = dblock_addr(blk);
@ -653,13 +652,10 @@ spectrum_cs_config(struct pcmcia_device *link)
int last_fn, last_ret; int last_fn, last_ret;
u_char buf[64]; u_char buf[64];
config_info_t conf; config_info_t conf;
cisinfo_t info;
tuple_t tuple; tuple_t tuple;
cisparse_t parse; cisparse_t parse;
void __iomem *mem; void __iomem *mem;
CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
/* /*
* This reads the card's CONFIG tuple to find its * This reads the card's CONFIG tuple to find its
* configuration registers. * configuration registers.
@ -709,12 +705,6 @@ spectrum_cs_config(struct pcmcia_device *link)
goto next_entry; goto next_entry;
link->conf.ConfigIndex = cfg->index; link->conf.ConfigIndex = cfg->index;
/* Does this card need audio output? */
if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
}
/* Use power settings for Vcc and Vpp if present */ /* Use power settings for Vcc and Vpp if present */
/* Note that the CIS values need to be rescaled */ /* Note that the CIS values need to be rescaled */
if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
@ -932,7 +922,7 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
" David Gibson <hermes@gibson.dropbear.id.au>, et al)"; " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
static struct pcmcia_device_id spectrum_cs_ids[] = { static struct pcmcia_device_id spectrum_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */ PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
PCMCIA_DEVICE_NULL, PCMCIA_DEVICE_NULL,

View File

@ -29,7 +29,7 @@
#include <linux/kernel.h> /* ARRAY_SIZE */ #include <linux/kernel.h> /* ARRAY_SIZE */
#include <linux/wireless.h> #include <linux/wireless.h>
#define IEEE80211_VERSION "git-1.1.7" #define IEEE80211_VERSION "git-1.1.13"
#define IEEE80211_DATA_LEN 2304 #define IEEE80211_DATA_LEN 2304
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
@ -104,6 +104,9 @@
#define IEEE80211_SCTL_FRAG 0x000F #define IEEE80211_SCTL_FRAG 0x000F
#define IEEE80211_SCTL_SEQ 0xFFF0 #define IEEE80211_SCTL_SEQ 0xFFF0
/* QOS control */
#define IEEE80211_QCTL_TID 0x000F
/* debug macros */ /* debug macros */
#ifdef CONFIG_IEEE80211_DEBUG #ifdef CONFIG_IEEE80211_DEBUG
@ -1073,6 +1076,7 @@ struct ieee80211_device {
int (*handle_management) (struct net_device * dev, int (*handle_management) (struct net_device * dev,
struct ieee80211_network * network, u16 type); struct ieee80211_network * network, u16 type);
int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
/* Typical STA methods */ /* Typical STA methods */
int (*handle_auth) (struct net_device * dev, int (*handle_auth) (struct net_device * dev,

View File

@ -91,4 +91,9 @@ ieee80211softmac_wx_get_genie(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
union iwreq_data *wrqu, union iwreq_data *wrqu,
char *extra); char *extra);
extern int
ieee80211softmac_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra);
#endif /* _IEEE80211SOFTMAC_WX */ #endif /* _IEEE80211SOFTMAC_WX */

View File

@ -501,8 +501,11 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
{ {
struct ieee80211_hdr_4addr *hdr11; struct ieee80211_hdr_4addr *hdr11;
u16 stype;
hdr11 = (struct ieee80211_hdr_4addr *)skb->data; hdr11 = (struct ieee80211_hdr_4addr *)skb->data;
stype = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl));
switch (le16_to_cpu(hdr11->frame_ctl) & switch (le16_to_cpu(hdr11->frame_ctl) &
(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
case IEEE80211_FCTL_TODS: case IEEE80211_FCTL_TODS:
@ -523,7 +526,13 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
break; break;
} }
hdr[12] = 0; /* priority */ if (stype & IEEE80211_STYPE_QOS_DATA) {
const struct ieee80211_hdr_3addrqos *qoshdr =
(struct ieee80211_hdr_3addrqos *)skb->data;
hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID;
} else
hdr[12] = 0; /* priority */
hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
} }

View File

@ -369,7 +369,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* Put this code here so that we avoid duplicating it in all /* Put this code here so that we avoid duplicating it in all
* Rx paths. - Jean II */ * Rx paths. - Jean II */
#ifdef CONFIG_WIRELESS_EXT
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
/* If spy monitoring on */ /* If spy monitoring on */
if (ieee->spy_data.spy_number > 0) { if (ieee->spy_data.spy_number > 0) {
@ -398,7 +397,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
wireless_spy_update(ieee->dev, hdr->addr2, &wstats); wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
} }
#endif /* IW_WIRELESS_SPY */ #endif /* IW_WIRELESS_SPY */
#endif /* CONFIG_WIRELESS_EXT */
#ifdef NOT_YET #ifdef NOT_YET
hostap_update_rx_stats(local->ap, hdr, rx_stats); hostap_update_rx_stats(local->ap, hdr, rx_stats);
@ -1692,8 +1690,8 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
WLAN_FC_GET_STYPE(le16_to_cpu WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl))); (header->frame_ctl)));
IEEE80211_WARNING("%s: IEEE80211_REASSOC_REQ received\n", IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n",
ieee->dev->name); ieee->dev->name);
if (ieee->handle_reassoc_request != NULL) if (ieee->handle_reassoc_request != NULL)
ieee->handle_reassoc_request(ieee->dev, ieee->handle_reassoc_request(ieee->dev,
(struct ieee80211_reassoc_request *) (struct ieee80211_reassoc_request *)
@ -1705,8 +1703,8 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
WLAN_FC_GET_STYPE(le16_to_cpu WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl))); (header->frame_ctl)));
IEEE80211_WARNING("%s: IEEE80211_ASSOC_REQ received\n", IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n",
ieee->dev->name); ieee->dev->name);
if (ieee->handle_assoc_request != NULL) if (ieee->handle_assoc_request != NULL)
ieee->handle_assoc_request(ieee->dev); ieee->handle_assoc_request(ieee->dev);
break; break;
@ -1722,10 +1720,10 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl))); (header->frame_ctl)));
IEEE80211_WARNING("%s: Unknown management packet: %d\n", IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n",
ieee->dev->name, ieee->dev->name,
WLAN_FC_GET_STYPE(le16_to_cpu WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl))); (header->frame_ctl)));
break; break;
} }
} }

View File

@ -220,13 +220,43 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
return txb; return txb;
} }
static int ieee80211_classify(struct sk_buff *skb)
{
struct ethhdr *eth;
struct iphdr *ip;
eth = (struct ethhdr *)skb->data;
if (eth->h_proto != __constant_htons(ETH_P_IP))
return 0;
ip = skb->nh.iph;
switch (ip->tos & 0xfc) {
case 0x20:
return 2;
case 0x40:
return 1;
case 0x60:
return 3;
case 0x80:
return 4;
case 0xa0:
return 5;
case 0xc0:
return 6;
case 0xe0:
return 7;
default:
return 0;
}
}
/* Incoming skb is converted to a txb which consists of /* Incoming skb is converted to a txb which consists of
* a block of 802.11 fragment packets (stored as skbs) */ * a block of 802.11 fragment packets (stored as skbs) */
int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct ieee80211_device *ieee = netdev_priv(dev); struct ieee80211_device *ieee = netdev_priv(dev);
struct ieee80211_txb *txb = NULL; struct ieee80211_txb *txb = NULL;
struct ieee80211_hdr_3addr *frag_hdr; struct ieee80211_hdr_3addrqos *frag_hdr;
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
rts_required; rts_required;
unsigned long flags; unsigned long flags;
@ -234,9 +264,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
int bytes, fc, hdr_len; int bytes, fc, hdr_len;
struct sk_buff *skb_frag; struct sk_buff *skb_frag;
struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */
.duration_id = 0, .duration_id = 0,
.seq_ctl = 0 .seq_ctl = 0,
.qos_ctl = 0
}; };
u8 dest[ETH_ALEN], src[ETH_ALEN]; u8 dest[ETH_ALEN], src[ETH_ALEN];
struct ieee80211_crypt_data *crypt; struct ieee80211_crypt_data *crypt;
@ -282,12 +313,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy(dest, skb->data, ETH_ALEN); memcpy(dest, skb->data, ETH_ALEN);
memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); memcpy(src, skb->data + ETH_ALEN, ETH_ALEN);
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
if (host_encrypt || host_build_iv) if (host_encrypt || host_build_iv)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_PROTECTED; IEEE80211_FCTL_PROTECTED;
@ -306,9 +331,23 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr2, src, ETH_ALEN);
memcpy(header.addr3, ieee->bssid, ETH_ALEN); memcpy(header.addr3, ieee->bssid, ETH_ALEN);
} }
header.frame_ctl = cpu_to_le16(fc);
hdr_len = IEEE80211_3ADDR_LEN; hdr_len = IEEE80211_3ADDR_LEN;
if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
fc |= IEEE80211_STYPE_QOS_DATA;
hdr_len += 2;
skb->priority = ieee80211_classify(skb);
header.qos_ctl |= skb->priority & IEEE80211_QCTL_TID;
}
header.frame_ctl = cpu_to_le16(fc);
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
/* Encrypt msdu first on the whole data packet. */ /* Encrypt msdu first on the whole data packet. */
if ((host_encrypt || host_encrypt_msdu) && if ((host_encrypt || host_encrypt_msdu) &&
crypt && crypt->ops && crypt->ops->encrypt_msdu) { crypt && crypt->ops && crypt->ops->encrypt_msdu) {
@ -402,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
if (rts_required) { if (rts_required) {
skb_frag = txb->fragments[0]; skb_frag = txb->fragments[0];
frag_hdr = frag_hdr =
(struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
/* /*
* Set header frame_ctl to the RTS. * Set header frame_ctl to the RTS.
@ -433,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
crypt->ops->extra_mpdu_prefix_len); crypt->ops->extra_mpdu_prefix_len);
frag_hdr = frag_hdr =
(struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
memcpy(frag_hdr, &header, hdr_len); memcpy(frag_hdr, &header, hdr_len);
/* If this is not the last fragment, then add the MOREFRAGS /* If this is not the last fragment, then add the MOREFRAGS

View File

@ -50,7 +50,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
char *p; char *p;
struct iw_event iwe; struct iw_event iwe;
int i, j; int i, j;
u8 max_rate, rate; char *current_val; /* For rates */
u8 rate;
/* First entry *MUST* be the AP MAC address */ /* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP; iwe.cmd = SIOCGIWAP;
@ -107,9 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
start = iwe_stream_add_point(start, stop, &iwe, network->ssid); start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
/* Add basic and extended rates */ /* Add basic and extended rates */
max_rate = 0; /* Rate : stuffing multiple values in a single event require a bit
p = custom; * more of magic - Jean II */
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); current_val = start + IW_EV_LCP_LEN;
iwe.cmd = SIOCGIWRATE;
/* Those two flags are ignored... */
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
for (i = 0, j = 0; i < network->rates_len;) { for (i = 0, j = 0; i < network->rates_len;) {
if (j < network->rates_ex_len && if (j < network->rates_ex_len &&
((network->rates_ex[j] & 0x7F) < ((network->rates_ex[j] & 0x7F) <
@ -117,28 +122,21 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
rate = network->rates_ex[j++] & 0x7F; rate = network->rates_ex[j++] & 0x7F;
else else
rate = network->rates[i++] & 0x7F; rate = network->rates[i++] & 0x7F;
if (rate > max_rate) /* Bit rate given in 500 kb/s units (+ 0x80) */
max_rate = rate; iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), /* Add new value to event */
"%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
} }
for (; j < network->rates_ex_len; j++) { for (; j < network->rates_ex_len; j++) {
rate = network->rates_ex[j] & 0x7F; rate = network->rates_ex[j] & 0x7F;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), /* Bit rate given in 500 kb/s units (+ 0x80) */
"%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
if (rate > max_rate) /* Add new value to event */
max_rate = rate; current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
} }
/* Check if we added any rate */
iwe.cmd = SIOCGIWRATE; if((current_val - start) > IW_EV_LCP_LEN)
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; start = current_val;
iwe.u.bitrate.value = max_rate * 500000;
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
iwe.cmd = IWEVCUSTOM;
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
start = iwe_stream_add_point(start, stop, &iwe, custom);
/* Add quality statistics */ /* Add quality statistics */
iwe.cmd = IWEVQUAL; iwe.cmd = IWEVQUAL;

View File

@ -82,7 +82,7 @@ ieee80211softmac_assoc_timeout(void *d)
} }
/* Sends out a disassociation request to the desired AP */ /* Sends out a disassociation request to the desired AP */
static void void
ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason) ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
{ {
unsigned long flags; unsigned long flags;

View File

@ -38,7 +38,8 @@
* The event context is private and can only be used from * The event context is private and can only be used from
* within this module. Its meaning varies with the event * within this module. Its meaning varies with the event
* type: * type:
* SCAN_FINISHED: no special meaning * SCAN_FINISHED,
* DISASSOCIATED: NULL
* ASSOCIATED, * ASSOCIATED,
* ASSOCIATE_FAILED, * ASSOCIATE_FAILED,
* ASSOCIATE_TIMEOUT, * ASSOCIATE_TIMEOUT,
@ -59,15 +60,15 @@
*/ */
static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
"scan finished", NULL, /* scan finished */
"associated", NULL, /* associated */
"associating failed", "associating failed",
"associating timed out", "associating timed out",
"authenticated", "authenticated",
"authenticating failed", "authenticating failed",
"authenticating timed out", "authenticating timed out",
"associating failed because no suitable network was found", "associating failed because no suitable network was found",
"disassociated", NULL, /* disassociated */
}; };
@ -136,30 +137,24 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve
int we_event; int we_event;
char *msg = NULL; char *msg = NULL;
memset(&wrqu, '\0', sizeof (union iwreq_data));
switch(event) { switch(event) {
case IEEE80211SOFTMAC_EVENT_ASSOCIATED: case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
network = (struct ieee80211softmac_network *)event_ctx; network = (struct ieee80211softmac_network *)event_ctx;
wrqu.data.length = 0;
wrqu.data.flags = 0;
memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN); memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* fall through */
we_event = SIOCGIWAP;
break;
case IEEE80211SOFTMAC_EVENT_DISASSOCIATED: case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
wrqu.data.length = 0;
wrqu.data.flags = 0;
memset(&wrqu, '\0', sizeof (union iwreq_data));
wrqu.ap_addr.sa_family = ARPHRD_ETHER; wrqu.ap_addr.sa_family = ARPHRD_ETHER;
we_event = SIOCGIWAP; we_event = SIOCGIWAP;
break; break;
case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED: case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
wrqu.data.length = 0;
wrqu.data.flags = 0;
memset(&wrqu, '\0', sizeof (union iwreq_data));
we_event = SIOCGIWSCAN; we_event = SIOCGIWSCAN;
break; break;
default: default:
msg = event_descriptions[event]; msg = event_descriptions[event];
if (!msg)
msg = "SOFTMAC EVENT BUG";
wrqu.data.length = strlen(msg); wrqu.data.length = strlen(msg);
we_event = IWEVCUSTOM; we_event = IWEVCUSTOM;
break; break;

View File

@ -150,6 +150,7 @@ int ieee80211softmac_handle_disassoc(struct net_device * dev,
int ieee80211softmac_handle_reassoc_req(struct net_device * dev, int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
struct ieee80211_reassoc_request * reassoc); struct ieee80211_reassoc_request * reassoc);
void ieee80211softmac_assoc_timeout(void *d); void ieee80211softmac_assoc_timeout(void *d);
void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason);
/* some helper functions */ /* some helper functions */
static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm) static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)

View File

@ -431,3 +431,35 @@ ieee80211softmac_wx_get_genie(struct net_device *dev,
} }
EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie); EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
int
ieee80211softmac_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
u16 reason = cpu_to_le16(mlme->reason_code);
struct ieee80211softmac_network *net;
if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
return -EINVAL;
}
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
if (!net) {
printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
return -EINVAL;
}
return ieee80211softmac_deauth_req(mac, net, reason);
case IW_MLME_DISASSOC:
ieee80211softmac_disassoc(mac, reason);
return 0;
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);