mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 23:31:29 +00:00
Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6 into upstream
This commit is contained in:
commit
00355cd938
@ -14,8 +14,8 @@ Copyright (C) 2004-2006, Intel Corporation
|
||||
|
||||
README.ipw2200
|
||||
|
||||
Version: 1.0.8
|
||||
Date : October 20, 2005
|
||||
Version: 1.1.2
|
||||
Date : March 30, 2006
|
||||
|
||||
|
||||
Index
|
||||
@ -103,7 +103,7 @@ file.
|
||||
|
||||
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)
|
||||
+ 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
|
||||
|
||||
Will report the current debug level of the driver's logging subsystem
|
||||
(only available if CONFIG_IPW_DEBUG was configured when the driver was
|
||||
built).
|
||||
(only available if CONFIG_IPW2200_DEBUG was configured when the driver
|
||||
was built).
|
||||
|
||||
You can set the debug level via:
|
||||
|
||||
|
@ -235,7 +235,35 @@ config IPW2200_MONITOR
|
||||
promiscuous mode via the Wireless Tool's Monitor mode. While in this
|
||||
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"
|
||||
depends on IPW2200 && EXPERIMENTAL
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <net/ieee80211.h>
|
||||
|
||||
#include "airo.h"
|
||||
|
||||
@ -467,6 +468,8 @@ static int do8bitIO = 0;
|
||||
#define RID_ECHOTEST_RESULTS 0xFF71
|
||||
#define RID_BSSLISTFIRST 0xFF72
|
||||
#define RID_BSSLISTNEXT 0xFF73
|
||||
#define RID_WPA_BSSLISTFIRST 0xFF74
|
||||
#define RID_WPA_BSSLISTNEXT 0xFF75
|
||||
|
||||
typedef struct {
|
||||
u16 cmd;
|
||||
@ -739,6 +742,14 @@ typedef struct {
|
||||
u16 extSoftCap;
|
||||
} 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 {
|
||||
u16 len;
|
||||
u16 index; /* First is 0 and 0xffff means end of list */
|
||||
@ -767,6 +778,9 @@ typedef struct {
|
||||
} fh;
|
||||
u16 dsChannel;
|
||||
u16 atimWindow;
|
||||
|
||||
/* Only present on firmware >= 5.30.17 */
|
||||
BSSListRidExtra extra;
|
||||
} BSSListRid;
|
||||
|
||||
typedef struct {
|
||||
@ -1140,8 +1154,6 @@ struct airo_info {
|
||||
char defindex; // Used with auto wep
|
||||
struct proc_dir_entry *proc_entry;
|
||||
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_DOWN 1 /* ifup/ifdown disabling of MAC */
|
||||
#define FLAG_RADIO_MASK 0x03
|
||||
@ -1151,6 +1163,7 @@ struct airo_info {
|
||||
#define FLAG_UPDATE_MULTI 5
|
||||
#define FLAG_UPDATE_UNI 6
|
||||
#define FLAG_802_11 7
|
||||
#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
|
||||
#define FLAG_PENDING_XMIT 9
|
||||
#define FLAG_PENDING_XMIT11 10
|
||||
#define FLAG_MPI 11
|
||||
@ -1158,17 +1171,19 @@ struct airo_info {
|
||||
#define FLAG_COMMIT 13
|
||||
#define FLAG_RESET 14
|
||||
#define FLAG_FLASHING 15
|
||||
#define JOB_MASK 0x2ff0000
|
||||
#define JOB_DIE 16
|
||||
#define JOB_XMIT 17
|
||||
#define JOB_XMIT11 18
|
||||
#define JOB_STATS 19
|
||||
#define JOB_PROMISC 20
|
||||
#define JOB_MIC 21
|
||||
#define JOB_EVENT 22
|
||||
#define JOB_AUTOWEP 23
|
||||
#define JOB_WSTATS 24
|
||||
#define JOB_SCAN_RESULTS 25
|
||||
#define FLAG_WPA_CAPABLE 16
|
||||
unsigned long flags;
|
||||
#define JOB_DIE 0
|
||||
#define JOB_XMIT 1
|
||||
#define JOB_XMIT11 2
|
||||
#define JOB_STATS 3
|
||||
#define JOB_PROMISC 4
|
||||
#define JOB_MIC 5
|
||||
#define JOB_EVENT 6
|
||||
#define JOB_AUTOWEP 7
|
||||
#define JOB_WSTATS 8
|
||||
#define JOB_SCAN_RESULTS 9
|
||||
unsigned long jobs;
|
||||
int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
|
||||
int whichbap);
|
||||
unsigned short *flash;
|
||||
@ -1208,6 +1223,11 @@ struct airo_info {
|
||||
#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
|
||||
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_free_list;
|
||||
BSSListElement *networks;
|
||||
@ -1264,7 +1284,7 @@ static void micinit(struct airo_info *ai)
|
||||
{
|
||||
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);
|
||||
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,
|
||||
BSSListRid *list) {
|
||||
int rc;
|
||||
Cmd cmd;
|
||||
Resp rsp;
|
||||
Cmd cmd;
|
||||
Resp rsp;
|
||||
|
||||
if (first == 1) {
|
||||
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.cmd=CMD_LISTBSS;
|
||||
if (down_interruptible(&ai->sem))
|
||||
return -ERESTARTSYS;
|
||||
issuecommand(ai, &cmd, &rsp);
|
||||
up(&ai->sem);
|
||||
/* Let the command take effect */
|
||||
ai->task = current;
|
||||
ssleep(3);
|
||||
ai->task = NULL;
|
||||
}
|
||||
rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
|
||||
list, sizeof(*list), 1);
|
||||
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.cmd=CMD_LISTBSS;
|
||||
if (down_interruptible(&ai->sem))
|
||||
return -ERESTARTSYS;
|
||||
issuecommand(ai, &cmd, &rsp);
|
||||
up(&ai->sem);
|
||||
/* Let the command take effect */
|
||||
ai->task = current;
|
||||
ssleep(3);
|
||||
ai->task = NULL;
|
||||
}
|
||||
rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
|
||||
list, ai->bssListRidLen, 1);
|
||||
|
||||
list->len = le16_to_cpu(list->len);
|
||||
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;
|
||||
u32 *fids = priv->fids;
|
||||
|
||||
clear_bit(JOB_XMIT, &priv->flags);
|
||||
clear_bit(JOB_XMIT, &priv->jobs);
|
||||
clear_bit(FLAG_PENDING_XMIT, &priv->flags);
|
||||
status = transmit_802_3_packet (priv, fids[fid], skb->data);
|
||||
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) {
|
||||
set_bit(FLAG_PENDING_XMIT, &priv->flags);
|
||||
netif_stop_queue(dev);
|
||||
set_bit(JOB_XMIT, &priv->flags);
|
||||
set_bit(JOB_XMIT, &priv->jobs);
|
||||
wake_up_interruptible(&priv->thr_wait);
|
||||
} else
|
||||
airo_end_xmit(dev);
|
||||
@ -2177,7 +2197,7 @@ static void airo_end_xmit11(struct net_device *dev) {
|
||||
int fid = priv->xmit11.fid;
|
||||
u32 *fids = priv->fids;
|
||||
|
||||
clear_bit(JOB_XMIT11, &priv->flags);
|
||||
clear_bit(JOB_XMIT11, &priv->jobs);
|
||||
clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
|
||||
status = transmit_802_11_packet (priv, fids[fid], skb->data);
|
||||
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) {
|
||||
set_bit(FLAG_PENDING_XMIT11, &priv->flags);
|
||||
netif_stop_queue(dev);
|
||||
set_bit(JOB_XMIT11, &priv->flags);
|
||||
set_bit(JOB_XMIT11, &priv->jobs);
|
||||
wake_up_interruptible(&priv->thr_wait);
|
||||
} else
|
||||
airo_end_xmit11(dev);
|
||||
@ -2244,7 +2264,7 @@ static void airo_read_stats(struct airo_info *ai) {
|
||||
StatsRid stats_rid;
|
||||
u32 *vals = stats_rid.vals;
|
||||
|
||||
clear_bit(JOB_STATS, &ai->flags);
|
||||
clear_bit(JOB_STATS, &ai->jobs);
|
||||
if (ai->power.event) {
|
||||
up(&ai->sem);
|
||||
return;
|
||||
@ -2272,10 +2292,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev)
|
||||
{
|
||||
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 */
|
||||
if (down_trylock(&local->sem) != 0) {
|
||||
set_bit(JOB_STATS, &local->flags);
|
||||
set_bit(JOB_STATS, &local->jobs);
|
||||
wake_up_interruptible(&local->thr_wait);
|
||||
} else
|
||||
airo_read_stats(local);
|
||||
@ -2290,7 +2310,7 @@ static void airo_set_promisc(struct airo_info *ai) {
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.cmd=CMD_SETMODE;
|
||||
clear_bit(JOB_PROMISC, &ai->flags);
|
||||
clear_bit(JOB_PROMISC, &ai->jobs);
|
||||
cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
|
||||
issuecommand(ai, &cmd, &rsp);
|
||||
up(&ai->sem);
|
||||
@ -2302,7 +2322,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
|
||||
if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
|
||||
change_bit(FLAG_PROMISC, &ai->flags);
|
||||
if (down_trylock(&ai->sem) != 0) {
|
||||
set_bit(JOB_PROMISC, &ai->flags);
|
||||
set_bit(JOB_PROMISC, &ai->jobs);
|
||||
wake_up_interruptible(&ai->thr_wait);
|
||||
} else
|
||||
airo_set_promisc(ai);
|
||||
@ -2380,7 +2400,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
|
||||
}
|
||||
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);
|
||||
wait_for_completion(&ai->thr_exited);
|
||||
|
||||
@ -2701,14 +2721,14 @@ static int reset_card( struct net_device *dev , int lock) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_NETWORK_COUNT 64
|
||||
#define AIRO_MAX_NETWORK_COUNT 64
|
||||
static int airo_networks_allocate(struct airo_info *ai)
|
||||
{
|
||||
if (ai->networks)
|
||||
return 0;
|
||||
|
||||
ai->networks =
|
||||
kzalloc(MAX_NETWORK_COUNT * sizeof(BSSListElement),
|
||||
kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
|
||||
GFP_KERNEL);
|
||||
if (!ai->networks) {
|
||||
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_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,
|
||||
&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,
|
||||
int is_pcmcia, struct pci_dev *pci,
|
||||
struct device *dmdev )
|
||||
@ -2759,6 +2801,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
|
||||
ai = dev->priv;
|
||||
ai->wifidev = NULL;
|
||||
ai->flags = 0;
|
||||
ai->jobs = 0;
|
||||
ai->dev = dev;
|
||||
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (rc) {
|
||||
airo_print_err(dev->name, "Couldn't register_netdev");
|
||||
@ -2875,7 +2930,7 @@ err_out_irq:
|
||||
err_out_unlink:
|
||||
del_airo_dev(dev);
|
||||
err_out_thr:
|
||||
set_bit(JOB_DIE, &ai->flags);
|
||||
set_bit(JOB_DIE, &ai->jobs);
|
||||
kill_proc(ai->thr_pid, SIGTERM, 1);
|
||||
wait_for_completion(&ai->thr_exited);
|
||||
err_out_free:
|
||||
@ -2933,7 +2988,7 @@ static void airo_send_event(struct net_device *dev) {
|
||||
union iwreq_data wrqu;
|
||||
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);
|
||||
up(&ai->sem);
|
||||
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) {
|
||||
union iwreq_data wrqu;
|
||||
BSSListRid BSSList;
|
||||
BSSListRid bss;
|
||||
int rc;
|
||||
BSSListElement * loop_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 */
|
||||
rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0);
|
||||
if((rc) || (BSSList.index == 0xffff)) {
|
||||
rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
|
||||
if((rc) || (bss.index == 0xffff)) {
|
||||
/* No scan results */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read and parse all entries */
|
||||
tmp_net = NULL;
|
||||
while((!rc) && (BSSList.index != 0xffff)) {
|
||||
while((!rc) && (bss.index != 0xffff)) {
|
||||
/* Grab a network off the free list */
|
||||
if (!list_empty(&ai->network_free_list)) {
|
||||
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) {
|
||||
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);
|
||||
tmp_net = NULL;
|
||||
}
|
||||
|
||||
/* Read next entry */
|
||||
rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
|
||||
&BSSList, sizeof(BSSList), 0);
|
||||
rc = PC4500_readrid(ai, ai->bssListNext,
|
||||
&bss, ai->bssListRidLen, 0);
|
||||
}
|
||||
|
||||
out:
|
||||
ai->scan_timeout = 0;
|
||||
clear_bit(JOB_SCAN_RESULTS, &ai->flags);
|
||||
clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
|
||||
up(&ai->sem);
|
||||
|
||||
/* Send an empty event to user space.
|
||||
@ -3019,10 +3074,10 @@ static int airo_thread(void *data) {
|
||||
/* make swsusp happy with our thread */
|
||||
try_to_freeze();
|
||||
|
||||
if (test_bit(JOB_DIE, &ai->flags))
|
||||
if (test_bit(JOB_DIE, &ai->jobs))
|
||||
break;
|
||||
|
||||
if (ai->flags & JOB_MASK) {
|
||||
if (ai->jobs) {
|
||||
locked = down_interruptible(&ai->sem);
|
||||
} else {
|
||||
wait_queue_t wait;
|
||||
@ -3031,16 +3086,16 @@ static int airo_thread(void *data) {
|
||||
add_wait_queue(&ai->thr_wait, &wait);
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (ai->flags & JOB_MASK)
|
||||
if (ai->jobs)
|
||||
break;
|
||||
if (ai->expires || ai->scan_timeout) {
|
||||
if (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;
|
||||
} else if (ai->expires &&
|
||||
time_after_eq(jiffies,ai->expires)){
|
||||
set_bit(JOB_AUTOWEP,&ai->flags);
|
||||
set_bit(JOB_AUTOWEP, &ai->jobs);
|
||||
break;
|
||||
}
|
||||
if (!signal_pending(current)) {
|
||||
@ -3069,7 +3124,7 @@ static int airo_thread(void *data) {
|
||||
if (locked)
|
||||
continue;
|
||||
|
||||
if (test_bit(JOB_DIE, &ai->flags)) {
|
||||
if (test_bit(JOB_DIE, &ai->jobs)) {
|
||||
up(&ai->sem);
|
||||
break;
|
||||
}
|
||||
@ -3079,23 +3134,23 @@ static int airo_thread(void *data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (test_bit(JOB_XMIT, &ai->flags))
|
||||
if (test_bit(JOB_XMIT, &ai->jobs))
|
||||
airo_end_xmit(dev);
|
||||
else if (test_bit(JOB_XMIT11, &ai->flags))
|
||||
else if (test_bit(JOB_XMIT11, &ai->jobs))
|
||||
airo_end_xmit11(dev);
|
||||
else if (test_bit(JOB_STATS, &ai->flags))
|
||||
else if (test_bit(JOB_STATS, &ai->jobs))
|
||||
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);
|
||||
else if (test_bit(JOB_PROMISC, &ai->flags))
|
||||
else if (test_bit(JOB_PROMISC, &ai->jobs))
|
||||
airo_set_promisc(ai);
|
||||
else if (test_bit(JOB_MIC, &ai->flags))
|
||||
else if (test_bit(JOB_MIC, &ai->jobs))
|
||||
micinit(ai);
|
||||
else if (test_bit(JOB_EVENT, &ai->flags))
|
||||
else if (test_bit(JOB_EVENT, &ai->jobs))
|
||||
airo_send_event(dev);
|
||||
else if (test_bit(JOB_AUTOWEP, &ai->flags))
|
||||
else if (test_bit(JOB_AUTOWEP, &ai->jobs))
|
||||
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);
|
||||
else /* Shouldn't get here, but we make sure to unlock */
|
||||
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 ) {
|
||||
OUT4500( apriv, EVACK, EV_MIC );
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
if (down_trylock(&apriv->sem) != 0) {
|
||||
set_bit(JOB_EVENT, &apriv->flags);
|
||||
set_bit(JOB_EVENT, &apriv->jobs);
|
||||
wake_up_interruptible(&apriv->thr_wait);
|
||||
} else
|
||||
airo_send_event(dev);
|
||||
@ -5485,7 +5540,7 @@ static void timer_func( struct net_device *dev ) {
|
||||
up(&apriv->sem);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@ -6876,7 +6931,7 @@ static int airo_get_range(struct net_device *dev,
|
||||
}
|
||||
range->num_txpower = i;
|
||||
range->txpower_capa = IW_TXPOW_MWATT;
|
||||
range->we_version_source = 12;
|
||||
range->we_version_source = 19;
|
||||
range->we_version_compiled = WIRELESS_EXT;
|
||||
range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
|
||||
range->retry_flags = IW_RETRY_LIMIT;
|
||||
@ -7152,6 +7207,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
||||
u16 capabilities;
|
||||
char * current_val; /* For rates */
|
||||
int i;
|
||||
char * buf;
|
||||
|
||||
/* First entry *MUST* be the AP MAC address */
|
||||
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)
|
||||
current_ev = current_val;
|
||||
|
||||
/* The other data in the scan result are not really
|
||||
* interesting, so for now drop it - Jean II */
|
||||
/* Beacon interval */
|
||||
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;
|
||||
}
|
||||
|
||||
@ -7521,7 +7638,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
|
||||
u32 *vals = stats_rid.vals;
|
||||
|
||||
/* Get stats out of the card */
|
||||
clear_bit(JOB_WSTATS, &local->flags);
|
||||
clear_bit(JOB_WSTATS, &local->jobs);
|
||||
if (local->power.event) {
|
||||
up(&local->sem);
|
||||
return;
|
||||
@ -7565,10 +7682,10 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
|
||||
{
|
||||
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 */
|
||||
if (down_trylock(&local->sem) != 0) {
|
||||
set_bit(JOB_WSTATS, &local->flags);
|
||||
set_bit(JOB_WSTATS, &local->jobs);
|
||||
wake_up_interruptible(&local->thr_wait);
|
||||
} else
|
||||
airo_read_wireless_stats(local);
|
||||
|
@ -645,7 +645,6 @@ struct bcm43xx_private {
|
||||
unsigned int irq;
|
||||
|
||||
void __iomem *mmio_addr;
|
||||
unsigned int mmio_len;
|
||||
|
||||
/* Do not use the lock directly. Use the bcm43xx_lock* helper
|
||||
* functions, to be MMIO-safe. */
|
||||
|
@ -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",
|
||||
pci_dev->subsystem_vendor, pci_dev->subsystem_device);
|
||||
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);
|
||||
if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
|
||||
fappend("Radio disabled by hardware!\n");
|
||||
|
@ -3288,8 +3288,7 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
|
||||
|
||||
bcm43xx_chipset_detach(bcm);
|
||||
/* 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_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;
|
||||
int err;
|
||||
int i;
|
||||
unsigned long mmio_start, mmio_flags, mmio_len;
|
||||
u32 coremask;
|
||||
|
||||
err = pci_enable_device(pci_dev);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX
|
||||
"could not access PCI resources (%i)\n", err);
|
||||
printk(KERN_ERR PFX "pci_request_regions() failed\n");
|
||||
goto err_pci_disable;
|
||||
}
|
||||
/* enable PCI bus-mastering */
|
||||
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) {
|
||||
printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
|
||||
pci_name(pci_dev));
|
||||
printk(KERN_ERR PFX "pci_iomap() failed\n");
|
||||
err = -EIO;
|
||||
goto err_pci_release;
|
||||
}
|
||||
bcm->mmio_len = mmio_len;
|
||||
net_dev->base_addr = (unsigned long)bcm->mmio_addr;
|
||||
|
||||
bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
|
||||
@ -3505,7 +3490,7 @@ err_80211_unwind:
|
||||
err_chipset_detach:
|
||||
bcm43xx_chipset_detach(bcm);
|
||||
err_iounmap:
|
||||
iounmap(bcm->mmio_addr);
|
||||
pci_iounmap(pci_dev, bcm->mmio_addr);
|
||||
err_pci_release:
|
||||
pci_release_regions(pci_dev);
|
||||
err_pci_disable:
|
||||
|
@ -121,12 +121,6 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
|
||||
hw->iobase = address;
|
||||
hw->reg_spacing = reg_spacing;
|
||||
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)
|
||||
@ -347,19 +341,6 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
|
||||
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)
|
||||
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
|
||||
* BAP. Synchronization/serialization is the caller's problem. len
|
||||
* must be even.
|
||||
* BAP. Synchronization/serialization is the caller's problem.
|
||||
*
|
||||
* 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 err = 0;
|
||||
|
||||
if ( (len < 0) || (len % 2) )
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
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;
|
||||
|
||||
/* Actually do the transfer */
|
||||
hermes_write_words(hw, dreg, buf, len/2);
|
||||
hermes_write_bytes(hw, dreg, buf, len);
|
||||
|
||||
out:
|
||||
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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
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,
|
||||
rid, NULL);
|
||||
@ -568,7 +511,6 @@ EXPORT_SYMBOL(hermes_allocate);
|
||||
|
||||
EXPORT_SYMBOL(hermes_bap_pread);
|
||||
EXPORT_SYMBOL(hermes_bap_pwrite);
|
||||
EXPORT_SYMBOL(hermes_bap_pwrite_pad);
|
||||
EXPORT_SYMBOL(hermes_read_ltv);
|
||||
EXPORT_SYMBOL(hermes_write_ltv);
|
||||
|
||||
|
@ -328,16 +328,6 @@ struct hermes_multicast {
|
||||
u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
|
||||
} __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 */
|
||||
#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
|
||||
|
||||
@ -347,14 +337,7 @@ typedef struct hermes {
|
||||
int reg_spacing;
|
||||
#define HERMES_16BIT_REGSPACING 0
|
||||
#define HERMES_32BIT_REGSPACING 1
|
||||
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
|
||||
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,
|
||||
u16 *length, void *buf);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
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)
|
||||
@ -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);
|
||||
}
|
||||
|
||||
#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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -789,7 +789,7 @@ struct ipw_sys_config {
|
||||
u8 bt_coexist_collision_thr;
|
||||
u8 silence_threshold;
|
||||
u8 accept_all_mgmt_bcpr;
|
||||
u8 accept_all_mgtm_frames;
|
||||
u8 accept_all_mgmt_frames;
|
||||
u8 pass_noise_stats_to_host;
|
||||
u8 reserved3;
|
||||
} __attribute__ ((packed));
|
||||
@ -1122,6 +1122,52 @@ struct ipw_fw_error {
|
||||
u8 payload[0];
|
||||
} __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 {
|
||||
/* ieee device used by generic ieee processing code */
|
||||
struct ieee80211_device *ieee;
|
||||
@ -1133,6 +1179,12 @@ struct ipw_priv {
|
||||
struct pci_dev *pci_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 */
|
||||
void __iomem *hw_base;
|
||||
unsigned long hw_len;
|
||||
@ -1153,11 +1205,9 @@ struct ipw_priv {
|
||||
u32 config;
|
||||
u32 capability;
|
||||
|
||||
u8 last_rx_rssi;
|
||||
u8 last_noise;
|
||||
struct average average_missed_beacons;
|
||||
struct average average_rssi;
|
||||
struct average average_noise;
|
||||
s16 exp_avg_rssi;
|
||||
s16 exp_avg_noise;
|
||||
u32 port_type;
|
||||
int rx_bufs_min; /**< minimum number of bufs in Rx queue */
|
||||
int rx_pend_max; /**< maximum pending buffers for one IRQ */
|
||||
@ -1308,6 +1358,29 @@ struct ipw_priv {
|
||||
|
||||
/* 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
|
||||
#define IPW_DEBUG(level, fmt, args...) \
|
||||
do { if (ipw_debug_level & (level)) \
|
||||
|
@ -201,41 +201,12 @@ static struct {
|
||||
/* Data types */
|
||||
/********************************************************************/
|
||||
|
||||
/* Used in Event handling.
|
||||
* We avoid nested structures as they break on ARM -- Moustafa */
|
||||
struct hermes_tx_descriptor_802_11 {
|
||||
/* hermes_tx_descriptor */
|
||||
__le16 status;
|
||||
__le16 reserved1;
|
||||
__le16 reserved2;
|
||||
__le32 sw_support;
|
||||
u8 retry_count;
|
||||
u8 tx_rate;
|
||||
__le16 tx_control;
|
||||
|
||||
/* ieee80211_hdr */
|
||||
/* Beginning of the Tx descriptor, used in TxExc handling */
|
||||
struct hermes_txexc_data {
|
||||
struct hermes_tx_descriptor desc;
|
||||
__le16 frame_ctl;
|
||||
__le16 duration_id;
|
||||
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));
|
||||
|
||||
/* 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;
|
||||
int err = 0;
|
||||
u16 txfid = priv->txfid;
|
||||
char *p;
|
||||
struct ethhdr *eh;
|
||||
int len, data_len, data_off;
|
||||
int data_off;
|
||||
struct hermes_tx_descriptor desc;
|
||||
unsigned long flags;
|
||||
|
||||
TRACE_ENTER(dev->name);
|
||||
|
||||
if (! netif_running(dev)) {
|
||||
printk(KERN_ERR "%s: Tx on stopped device!\n",
|
||||
dev->name);
|
||||
TRACE_EXIT(dev->name);
|
||||
return 1;
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (netif_queue_stopped(dev)) {
|
||||
printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
|
||||
dev->name);
|
||||
TRACE_EXIT(dev->name);
|
||||
return 1;
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (orinoco_lock(priv, &flags) != 0) {
|
||||
printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
|
||||
dev->name);
|
||||
TRACE_EXIT(dev->name);
|
||||
return 1;
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
|
||||
/* Oops, the firmware hasn't established a connection,
|
||||
silently drop the packet (this seems to be the
|
||||
safest approach). */
|
||||
stats->tx_errors++;
|
||||
orinoco_unlock(priv, &flags);
|
||||
dev_kfree_skb(skb);
|
||||
TRACE_EXIT(dev->name);
|
||||
return 0;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* Length of the packet body */
|
||||
/* FIXME: what if the skb is smaller than this? */
|
||||
len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN);
|
||||
skb = skb_padto(skb, len);
|
||||
if (skb == NULL)
|
||||
goto fail;
|
||||
len -= ETH_HLEN;
|
||||
/* Check packet length */
|
||||
if (skb->len < ETH_HLEN)
|
||||
goto drop;
|
||||
|
||||
eh = (struct ethhdr *)skb->data;
|
||||
|
||||
@ -507,8 +464,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "%s: Error %d writing Tx descriptor "
|
||||
"to BAP\n", dev->name, err);
|
||||
stats->tx_errors++;
|
||||
goto fail;
|
||||
goto busy;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
|
||||
struct header_struct hdr;
|
||||
data_len = len;
|
||||
data_off = HERMES_802_3_OFFSET + sizeof(hdr);
|
||||
p = skb->data + ETH_HLEN;
|
||||
struct header_struct {
|
||||
struct ethhdr eth; /* 802.3 header */
|
||||
u8 encap[6]; /* 802.2 header */
|
||||
} __attribute__ ((packed)) hdr;
|
||||
|
||||
/* 802.3 header */
|
||||
memcpy(hdr.dest, eh->h_dest, ETH_ALEN);
|
||||
memcpy(hdr.src, eh->h_source, ETH_ALEN);
|
||||
hdr.len = htons(data_len + ENCAPS_OVERHEAD);
|
||||
|
||||
/* 802.2 header */
|
||||
memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr));
|
||||
|
||||
hdr.ethertype = eh->h_proto;
|
||||
err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
|
||||
txfid, HERMES_802_3_OFFSET);
|
||||
/* Strip destination and source from the data */
|
||||
skb_pull(skb, 2 * ETH_ALEN);
|
||||
data_off = HERMES_802_2_OFFSET + sizeof(encaps_hdr);
|
||||
|
||||
/* And move them to a separate header */
|
||||
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));
|
||||
|
||||
err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
|
||||
txfid, HERMES_802_3_OFFSET);
|
||||
if (err) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "%s: Error %d writing packet "
|
||||
"header to BAP\n", dev->name, err);
|
||||
stats->tx_errors++;
|
||||
goto fail;
|
||||
goto busy;
|
||||
}
|
||||
/* 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 */
|
||||
data_len = len + ETH_HLEN;
|
||||
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);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
|
||||
dev->name, err);
|
||||
stats->tx_errors++;
|
||||
goto fail;
|
||||
goto busy;
|
||||
}
|
||||
|
||||
/* 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())
|
||||
printk(KERN_ERR "%s: Error %d transmitting packet\n",
|
||||
dev->name, err);
|
||||
stats->tx_errors++;
|
||||
goto fail;
|
||||
goto busy;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
TRACE_EXIT(dev->name);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
TRACE_EXIT(dev->name);
|
||||
|
||||
busy:
|
||||
if (err == -EIO)
|
||||
schedule_work(&priv->reset_work);
|
||||
orinoco_unlock(priv, &flags);
|
||||
return err;
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
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;
|
||||
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
|
||||
u16 status;
|
||||
struct hermes_tx_descriptor_802_11 hdr;
|
||||
struct hermes_txexc_data hdr;
|
||||
int err = 0;
|
||||
|
||||
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 */
|
||||
err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
|
||||
offsetof(struct hermes_tx_descriptor_802_11,
|
||||
addr2),
|
||||
sizeof(struct hermes_txexc_data),
|
||||
fid, 0);
|
||||
|
||||
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
|
||||
* that this particular node went away.
|
||||
* 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)) {
|
||||
union iwreq_data wrqu;
|
||||
|
||||
@ -1400,16 +1345,12 @@ int __orinoco_down(struct net_device *dev)
|
||||
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 hermes *hw = &priv->hw;
|
||||
int err;
|
||||
|
||||
err = hermes_init(hw);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
|
||||
if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
|
||||
/* Try workaround for old Symbol firmware bug */
|
||||
@ -1428,6 +1369,19 @@ int orinoco_reinit_firmware(struct net_device *dev)
|
||||
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)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
@ -2274,14 +2228,12 @@ static int orinoco_init(struct net_device *dev)
|
||||
u16 reclen;
|
||||
int len;
|
||||
|
||||
TRACE_ENTER(dev->name);
|
||||
|
||||
/* No need to lock, the hw_unavailable flag is already set in
|
||||
* alloc_orinocodev() */
|
||||
priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
|
||||
|
||||
/* Initialize the firmware */
|
||||
err = orinoco_reinit_firmware(dev);
|
||||
err = hermes_init(hw);
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
|
||||
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);
|
||||
|
||||
err = orinoco_allocate_fid(dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
|
||||
dev->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get allowed channels */
|
||||
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
|
||||
&priv->channel_mask);
|
||||
@ -2429,7 +2388,6 @@ static int orinoco_init(struct net_device *dev)
|
||||
printk(KERN_DEBUG "%s: ready\n", dev->name);
|
||||
|
||||
out:
|
||||
TRACE_EXIT(dev->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2797,8 +2755,6 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
|
||||
int numrates;
|
||||
int i, k;
|
||||
|
||||
TRACE_ENTER(dev->name);
|
||||
|
||||
rrq->length = 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, IWEVTXDROP);
|
||||
|
||||
TRACE_EXIT(dev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3071,8 +3025,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
|
||||
int err = 0;
|
||||
unsigned long flags;
|
||||
|
||||
TRACE_ENTER(dev->name);
|
||||
|
||||
if (netif_running(dev)) {
|
||||
err = orinoco_hw_get_essid(priv, &active, essidbuf);
|
||||
if (err)
|
||||
@ -3087,8 +3039,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
|
||||
erq->flags = 1;
|
||||
erq->length = strlen(essidbuf) + 1;
|
||||
|
||||
TRACE_EXIT(dev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4348,69 +4298,6 @@ static struct ethtool_ops orinoco_ethtool_ops = {
|
||||
.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 */
|
||||
/********************************************************************/
|
||||
|
@ -7,7 +7,7 @@
|
||||
#ifndef _ORINOCO_H
|
||||
#define _ORINOCO_H
|
||||
|
||||
#define DRIVER_VERSION "0.15rc3"
|
||||
#define DRIVER_VERSION "0.15"
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
@ -30,20 +30,6 @@ struct orinoco_key {
|
||||
char data[ORINOCO_MAX_KEY_SIZE];
|
||||
} __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 {
|
||||
FIRMWARE_TYPE_AGERE,
|
||||
FIRMWARE_TYPE_INTERSIL,
|
||||
@ -132,9 +118,6 @@ extern int orinoco_debug;
|
||||
#define DEBUG(n, args...) do { } while (0)
|
||||
#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 */
|
||||
/********************************************************************/
|
||||
|
@ -178,13 +178,10 @@ orinoco_cs_config(struct pcmcia_device *link)
|
||||
int last_fn, last_ret;
|
||||
u_char buf[64];
|
||||
config_info_t conf;
|
||||
cisinfo_t info;
|
||||
tuple_t tuple;
|
||||
cisparse_t parse;
|
||||
void __iomem *mem;
|
||||
|
||||
CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
|
||||
|
||||
/*
|
||||
* This reads the card's CONFIG tuple to find its
|
||||
* configuration registers.
|
||||
@ -234,12 +231,6 @@ orinoco_cs_config(struct pcmcia_device *link)
|
||||
goto next_entry;
|
||||
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 */
|
||||
/* Note that the CIS values need to be rescaled */
|
||||
if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
|
||||
|
@ -1,9 +1,8 @@
|
||||
/* orinoco_nortel.c
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* (C) 2003 Christoph Jungegger <disdos@traum404.de>
|
||||
@ -50,67 +49,62 @@
|
||||
#include <pcmcia/cisreg.h>
|
||||
|
||||
#include "orinoco.h"
|
||||
#include "orinoco_pci.h"
|
||||
|
||||
#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 */
|
||||
|
||||
|
||||
/* 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...
|
||||
* 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.
|
||||
* 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 */
|
||||
outw_p(8, card->iobase1 + 2);
|
||||
inw(card->iobase2 + COR_OFFSET);
|
||||
outw_p(0x80, card->iobase2 + COR_OFFSET);
|
||||
/* Assert the reset until the card notices */
|
||||
iowrite16(8, card->bridge_io + 2);
|
||||
ioread16(card->attr_io + COR_OFFSET);
|
||||
iowrite16(0x80, card->attr_io + COR_OFFSET);
|
||||
mdelay(1);
|
||||
|
||||
/* Give time for the card to recover from this hard effort */
|
||||
outw_p(0, card->iobase2 + COR_OFFSET);
|
||||
outw_p(0, card->iobase2 + COR_OFFSET);
|
||||
iowrite16(0, card->attr_io + COR_OFFSET);
|
||||
iowrite16(0, card->attr_io + COR_OFFSET);
|
||||
mdelay(1);
|
||||
|
||||
/* set COR as usual */
|
||||
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
|
||||
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
|
||||
/* Set COR as usual */
|
||||
iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
|
||||
iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
|
||||
mdelay(1);
|
||||
|
||||
outw_p(0x228, card->iobase1 + 2);
|
||||
iowrite16(0x228, card->bridge_io + 2);
|
||||
|
||||
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;
|
||||
u32 reg;
|
||||
|
||||
/* setup bridge */
|
||||
if (inw(card->iobase1) & 1) {
|
||||
/* Setup bridge */
|
||||
if (ioread16(card->bridge_io) & 1) {
|
||||
printk(KERN_ERR PFX "brg1 answer1 wrong\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
outw_p(0x118, card->iobase1 + 2);
|
||||
outw_p(0x108, card->iobase1 + 2);
|
||||
iowrite16(0x118, card->bridge_io + 2);
|
||||
iowrite16(0x108, card->bridge_io + 2);
|
||||
mdelay(30);
|
||||
outw_p(0x8, card->iobase1 + 2);
|
||||
iowrite16(0x8, card->bridge_io + 2);
|
||||
for (i = 0; i < 30; i++) {
|
||||
mdelay(30);
|
||||
if (inw(card->iobase1) & 0x10) {
|
||||
if (ioread16(card->bridge_io) & 0x10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -118,42 +112,42 @@ static int nortel_pci_hw_init(struct nortel_pci_card *card)
|
||||
printk(KERN_ERR PFX "brg1 timed out\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (inw(card->iobase2 + 0xe0) & 1) {
|
||||
if (ioread16(card->attr_io + COR_OFFSET) & 1) {
|
||||
printk(KERN_ERR PFX "brg2 answer1 wrong\n");
|
||||
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");
|
||||
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");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* set the PCMCIA COR-Register */
|
||||
outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
|
||||
/* Set the PCMCIA COR register */
|
||||
iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
|
||||
mdelay(1);
|
||||
reg = inw(card->iobase2 + COR_OFFSET);
|
||||
reg = ioread16(card->attr_io + COR_OFFSET);
|
||||
if (reg != COR_VALUE) {
|
||||
printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
|
||||
reg);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* set leds */
|
||||
outw_p(1, card->iobase1 + 10);
|
||||
/* Set LEDs */
|
||||
iowrite16(1, card->bridge_io + 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nortel_pci_init_one(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
static int orinoco_nortel_init_one(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int err;
|
||||
struct orinoco_private *priv;
|
||||
struct nortel_pci_card *card;
|
||||
struct orinoco_pci_card *card;
|
||||
struct net_device *dev;
|
||||
void __iomem *iomem;
|
||||
void __iomem *hermes_io, *bridge_io, *attr_io;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
@ -162,19 +156,34 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
err = pci_request_regions(pdev, DRIVER_NAME);
|
||||
if (err != 0) {
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
|
||||
goto fail_resources;
|
||||
}
|
||||
|
||||
iomem = pci_iomap(pdev, 2, 0);
|
||||
if (!iomem) {
|
||||
err = -ENOMEM;
|
||||
goto fail_map_io;
|
||||
bridge_io = pci_iomap(pdev, 0, 0);
|
||||
if (!bridge_io) {
|
||||
printk(KERN_ERR PFX "Cannot map bridge registers\n");
|
||||
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 */
|
||||
dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset);
|
||||
dev = alloc_orinocodev(sizeof(*card), orinoco_nortel_cor_reset);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR PFX "Cannot allocate network device\n");
|
||||
err = -ENOMEM;
|
||||
@ -183,16 +192,12 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
card = priv->card;
|
||||
card->iobase1 = pci_resource_start(pdev, 0);
|
||||
card->iobase2 = pci_resource_start(pdev, 1);
|
||||
dev->base_addr = pci_resource_start(pdev, 2);
|
||||
card->bridge_io = bridge_io;
|
||||
card->attr_io = attr_io;
|
||||
SET_MODULE_OWNER(dev);
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
hermes_struct_init(&priv->hw, iomem, 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);
|
||||
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
|
||||
|
||||
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
|
||||
dev->name, dev);
|
||||
@ -201,21 +206,20 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
|
||||
err = -EBUSY;
|
||||
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) {
|
||||
printk(KERN_ERR PFX "Hardware initialization failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = nortel_pci_cor_reset(priv);
|
||||
err = orinoco_nortel_cor_reset(priv);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Initial reset failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
fail_resources:
|
||||
@ -245,26 +255,27 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
|
||||
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 orinoco_private *priv = netdev_priv(dev);
|
||||
struct nortel_pci_card *card = priv->card;
|
||||
struct orinoco_pci_card *card = priv->card;
|
||||
|
||||
/* clear leds */
|
||||
outw_p(0, card->iobase1 + 10);
|
||||
/* Clear LEDs */
|
||||
iowrite16(0, card->bridge_io + 10);
|
||||
|
||||
unregister_netdev(dev);
|
||||
free_irq(dev->irq, dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
free_orinocodev(dev);
|
||||
pci_iounmap(pdev, priv->hw.iobase);
|
||||
pci_iounmap(pdev, card->attr_io);
|
||||
pci_iounmap(pdev, card->bridge_io);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
||||
static struct pci_device_id nortel_pci_id_table[] = {
|
||||
static struct pci_device_id orinoco_nortel_id_table[] = {
|
||||
/* Nortel emobility PCI */
|
||||
{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
/* Symbol LA-4123 PCI */
|
||||
@ -272,13 +283,15 @@ static struct pci_device_id nortel_pci_id_table[] = {
|
||||
{0,},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, nortel_pci_id_table);
|
||||
MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
|
||||
|
||||
static struct pci_driver nortel_pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = nortel_pci_id_table,
|
||||
.probe = nortel_pci_init_one,
|
||||
.remove = __devexit_p(nortel_pci_remove_one),
|
||||
static struct pci_driver orinoco_nortel_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = orinoco_nortel_id_table,
|
||||
.probe = orinoco_nortel_init_one,
|
||||
.remove = __devexit_p(orinoco_nortel_remove_one),
|
||||
.suspend = orinoco_pci_suspend,
|
||||
.resume = orinoco_pci_resume,
|
||||
};
|
||||
|
||||
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
|
||||
@ -288,20 +301,19 @@ MODULE_DESCRIPTION
|
||||
("Driver for wireless LAN cards using the Nortel PCI bridge");
|
||||
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);
|
||||
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);
|
||||
ssleep(1);
|
||||
pci_unregister_driver(&orinoco_nortel_driver);
|
||||
}
|
||||
|
||||
module_init(nortel_pci_init);
|
||||
module_exit(nortel_pci_exit);
|
||||
module_init(orinoco_nortel_init);
|
||||
module_exit(orinoco_nortel_exit);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
@ -1,11 +1,11 @@
|
||||
/* orinoco_pci.c
|
||||
*
|
||||
* Driver for Prism II devices that have a direct PCI interface
|
||||
* (i.e., not in a Pcmcia or PLX bridge)
|
||||
* Driver for Prism 2.5/3 devices that have a direct PCI interface
|
||||
* (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 (as of 29 September 2003) are:
|
||||
* Current maintainers are:
|
||||
* Pavel Roskin <proski AT gnu.org>
|
||||
* and David Gibson <hermes AT gibson.dropbear.id.au>
|
||||
*
|
||||
@ -41,54 +41,6 @@
|
||||
* 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 PFX DRIVER_NAME ": "
|
||||
|
||||
@ -100,12 +52,14 @@
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "orinoco.h"
|
||||
#include "orinoco_pci.h"
|
||||
|
||||
/* All the magic there is from wlan-ng */
|
||||
/* Magic offset of the reset register of the PCI card */
|
||||
/* Offset of the COR register of the PCI card */
|
||||
#define HERMES_PCI_COR (0x26)
|
||||
/* Magic bitmask to reset the card */
|
||||
|
||||
/* Bitmask to reset the card */
|
||||
#define HERMES_PCI_COR_MASK (0x0080)
|
||||
|
||||
/* Magic timeouts for doing the reset.
|
||||
* 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. */
|
||||
@ -113,13 +67,8 @@
|
||||
#define HERMES_PCI_COR_OFFT (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...
|
||||
* 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.
|
||||
* It just won't work !
|
||||
*/
|
||||
static int
|
||||
orinoco_pci_cor_reset(struct orinoco_private *priv)
|
||||
static int orinoco_pci_cor_reset(struct orinoco_private *priv)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
unsigned long timeout;
|
||||
u16 reg;
|
||||
unsigned long timeout;
|
||||
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);
|
||||
mdelay(HERMES_PCI_COR_ONT);
|
||||
|
||||
@ -163,19 +111,14 @@ orinoco_pci_cor_reset(struct orinoco_private *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise a card. Mostly similar to PLX code.
|
||||
*/
|
||||
static int orinoco_pci_init_one(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned long pci_iorange;
|
||||
u16 __iomem *pci_ioaddr = NULL;
|
||||
unsigned long pci_iolen;
|
||||
struct orinoco_private *priv = NULL;
|
||||
int err;
|
||||
struct orinoco_private *priv;
|
||||
struct orinoco_pci_card *card;
|
||||
struct net_device *dev = NULL;
|
||||
struct net_device *dev;
|
||||
void __iomem *hermes_io;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
@ -184,39 +127,32 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
err = pci_request_regions(pdev, DRIVER_NAME);
|
||||
if (err != 0) {
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
|
||||
goto fail_resources;
|
||||
}
|
||||
|
||||
/* Resource 0 is mapped to the hermes registers */
|
||||
pci_iorange = pci_resource_start(pdev, 0);
|
||||
pci_iolen = pci_resource_len(pdev, 0);
|
||||
pci_ioaddr = ioremap(pci_iorange, pci_iolen);
|
||||
if (!pci_iorange) {
|
||||
printk(KERN_ERR PFX "Cannot remap hardware registers\n");
|
||||
goto fail_map;
|
||||
hermes_io = pci_iomap(pdev, 0, 0);
|
||||
if (!hermes_io) {
|
||||
printk(KERN_ERR PFX "Cannot remap chipset registers\n");
|
||||
err = -EIO;
|
||||
goto fail_map_hermes;
|
||||
}
|
||||
|
||||
/* Allocate network device */
|
||||
dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset);
|
||||
if (! dev) {
|
||||
if (!dev) {
|
||||
printk(KERN_ERR PFX "Cannot allocate network device\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
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_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
hermes_struct_init(&priv->hw, pci_ioaddr, 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);
|
||||
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
|
||||
|
||||
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
|
||||
dev->name, dev);
|
||||
@ -225,9 +161,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
|
||||
err = -EBUSY;
|
||||
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);
|
||||
if (err) {
|
||||
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);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Failed to register net device\n");
|
||||
printk(KERN_ERR PFX "Cannot register network device\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -252,9 +187,9 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
|
||||
free_orinocodev(dev);
|
||||
|
||||
fail_alloc:
|
||||
iounmap(pci_ioaddr);
|
||||
pci_iounmap(pdev, hermes_io);
|
||||
|
||||
fail_map:
|
||||
fail_map_hermes:
|
||||
pci_release_regions(pdev);
|
||||
|
||||
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 orinoco_private *priv = netdev_priv(dev);
|
||||
struct orinoco_pci_card *card = priv->card;
|
||||
|
||||
unregister_netdev(dev);
|
||||
free_irq(dev->irq, dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
free_orinocodev(dev);
|
||||
iounmap(card->pci_ioaddr);
|
||||
pci_iounmap(pdev, priv->hw.iobase);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
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: 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[] = {
|
||||
static struct pci_device_id orinoco_pci_id_table[] = {
|
||||
/* Intersil Prism 3 */
|
||||
{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
/* Intersil Prism 2.5 */
|
||||
@ -357,11 +222,11 @@ static struct pci_device_id orinoco_pci_pci_id_table[] = {
|
||||
{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 = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = orinoco_pci_pci_id_table,
|
||||
.id_table = orinoco_pci_id_table,
|
||||
.probe = orinoco_pci_init_one,
|
||||
.remove = __devexit_p(orinoco_pci_remove_one),
|
||||
.suspend = orinoco_pci_suspend,
|
||||
|
125
drivers/net/wireless/orinoco_pci.h
Normal file
125
drivers/net/wireless/orinoco_pci.h
Normal 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 */
|
@ -3,7 +3,7 @@
|
||||
* Driver for Prism II devices which would usually be driven by orinoco_cs,
|
||||
* 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>
|
||||
* 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
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* 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
|
||||
* 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:
|
||||
* Here's the general details on how the PLX9052 adapter works:
|
||||
*
|
||||
* - Two PCI I/O address spaces, one 0x80 long which contains the
|
||||
* PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
|
||||
* 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).
|
||||
*
|
||||
* After identifying the I/O and memory space, you can read through
|
||||
* the memory space to confirm the CIS's device ID or manufacturer ID
|
||||
* to make sure it's the expected card. qKeep in mind that the PCMCIA
|
||||
* Using the later, you can read through the CIS data to make sure the
|
||||
* card is compatible with the driver. Keep in mind that the PCMCIA
|
||||
* 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
|
||||
* (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
|
||||
* enable I/O mode and to select level triggered interrupts. To
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* driver development for various reasons (stuck WAIT# line after the
|
||||
* 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"
|
||||
@ -125,6 +95,7 @@
|
||||
#include <pcmcia/cisreg.h>
|
||||
|
||||
#include "orinoco.h"
|
||||
#include "orinoco_pci.h"
|
||||
|
||||
#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 */
|
||||
@ -134,30 +105,20 @@
|
||||
#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */
|
||||
#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
|
||||
*/
|
||||
static int orinoco_plx_cor_reset(struct orinoco_private *priv)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
struct orinoco_plx_card *card = priv->card;
|
||||
u8 __iomem *attr_mem = card->attr_mem;
|
||||
struct orinoco_pci_card *card = priv->card;
|
||||
unsigned long timeout;
|
||||
u16 reg;
|
||||
|
||||
writeb(COR_VALUE | COR_RESET, attr_mem + COR_OFFSET);
|
||||
iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
|
||||
mdelay(1);
|
||||
|
||||
writeb(COR_VALUE, attr_mem + COR_OFFSET);
|
||||
iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
|
||||
mdelay(1);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Did we timeout ? */
|
||||
/* Still busy? */
|
||||
if (reg & HERMES_CMD_BUSY) {
|
||||
printk(KERN_ERR PFX "Busy timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
@ -177,20 +138,55 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv)
|
||||
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,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int err = 0;
|
||||
u8 __iomem *attr_mem = NULL;
|
||||
u32 csr_reg, plx_addr;
|
||||
struct orinoco_private *priv = NULL;
|
||||
struct orinoco_plx_card *card;
|
||||
unsigned long pccard_ioaddr = 0;
|
||||
unsigned long pccard_iolen = 0;
|
||||
struct net_device *dev = NULL;
|
||||
void __iomem *mem;
|
||||
int i;
|
||||
int err;
|
||||
struct orinoco_private *priv;
|
||||
struct orinoco_pci_card *card;
|
||||
struct net_device *dev;
|
||||
void __iomem *hermes_io, *attr_io, *bridge_io;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
@ -199,30 +195,30 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
err = pci_request_regions(pdev, DRIVER_NAME);
|
||||
if (err != 0) {
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
|
||||
goto fail_resources;
|
||||
}
|
||||
|
||||
/* Resource 1 is mapped to PLX-specific registers */
|
||||
plx_addr = pci_resource_start(pdev, 1);
|
||||
bridge_io = pci_iomap(pdev, 1, 0);
|
||||
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_mem = ioremap(pci_resource_start(pdev, 2),
|
||||
pci_resource_len(pdev, 2));
|
||||
if (!attr_mem) {
|
||||
printk(KERN_ERR PFX "Cannot remap PCMCIA space\n");
|
||||
attr_io = pci_iomap(pdev, 2, 0);
|
||||
if (!attr_io) {
|
||||
printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
|
||||
err = -EIO;
|
||||
goto fail_map_attr;
|
||||
}
|
||||
|
||||
/* Resource 3 is mapped to the PCMCIA I/O address space */
|
||||
pccard_ioaddr = pci_resource_start(pdev, 3);
|
||||
pccard_iolen = pci_resource_len(pdev, 3);
|
||||
|
||||
mem = pci_iomap(pdev, 3, 0);
|
||||
if (!mem) {
|
||||
err = -ENOMEM;
|
||||
goto fail_map_io;
|
||||
hermes_io = pci_iomap(pdev, 3, 0);
|
||||
if (!hermes_io) {
|
||||
printk(KERN_ERR PFX "Cannot map chipset registers\n");
|
||||
err = -EIO;
|
||||
goto fail_map_hermes;
|
||||
}
|
||||
|
||||
/* Allocate network device */
|
||||
@ -235,16 +231,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
card = priv->card;
|
||||
card->attr_mem = attr_mem;
|
||||
dev->base_addr = pccard_ioaddr;
|
||||
card->bridge_io = bridge_io;
|
||||
card->attr_io = attr_io;
|
||||
SET_MODULE_OWNER(dev);
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
hermes_struct_init(&priv->hw, mem, 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);
|
||||
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
|
||||
|
||||
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
|
||||
dev->name, dev);
|
||||
@ -253,20 +245,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
|
||||
err = -EBUSY;
|
||||
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
|
||||
case the serial eprom didn't do this already. See the
|
||||
PLX9052 data book, p8-1 and 8-24 for reference. */
|
||||
csr_reg = inl(plx_addr + PLX_INTCSR);
|
||||
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_hw_init(card);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Hardware initialization failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = orinoco_plx_cor_reset(priv);
|
||||
@ -275,23 +259,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
|
||||
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);
|
||||
if (err) {
|
||||
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);
|
||||
|
||||
fail_alloc:
|
||||
pci_iounmap(pdev, mem);
|
||||
pci_iounmap(pdev, hermes_io);
|
||||
|
||||
fail_map_io:
|
||||
iounmap(attr_mem);
|
||||
fail_map_hermes:
|
||||
pci_iounmap(pdev, attr_io);
|
||||
|
||||
fail_map_attr:
|
||||
pci_iounmap(pdev, bridge_io);
|
||||
|
||||
fail_map_bridge:
|
||||
pci_release_regions(pdev);
|
||||
|
||||
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 orinoco_private *priv = netdev_priv(dev);
|
||||
struct orinoco_plx_card *card = priv->card;
|
||||
u8 __iomem *attr_mem = card->attr_mem;
|
||||
|
||||
BUG_ON(! dev);
|
||||
struct orinoco_pci_card *card = priv->card;
|
||||
|
||||
unregister_netdev(dev);
|
||||
free_irq(dev->irq, dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
free_orinocodev(dev);
|
||||
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_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
||||
static struct pci_device_id orinoco_plx_pci_id_table[] = {
|
||||
static struct pci_device_id orinoco_plx_id_table[] = {
|
||||
{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */
|
||||
{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
|
||||
{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,},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
|
||||
MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
|
||||
|
||||
static struct pci_driver orinoco_plx_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = orinoco_plx_pci_id_table,
|
||||
.id_table = orinoco_plx_id_table,
|
||||
.probe = orinoco_plx_init_one,
|
||||
.remove = __devexit_p(orinoco_plx_remove_one),
|
||||
.suspend = orinoco_pci_suspend,
|
||||
.resume = orinoco_pci_resume,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
pci_unregister_driver(&orinoco_plx_driver);
|
||||
ssleep(1);
|
||||
}
|
||||
|
||||
module_init(orinoco_plx_init);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* orinoco_tmd.c
|
||||
*
|
||||
*
|
||||
* Driver for Prism II devices which would usually be driven by orinoco_cs,
|
||||
* but are connected to the PCI bus by a TMD7160.
|
||||
*
|
||||
@ -26,25 +26,13 @@
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* 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
|
||||
* allocation stuff.
|
||||
*
|
||||
* This driver is modeled after the orinoco_plx driver. The main
|
||||
* difference is that the TMD chip has only IO port ranges and no
|
||||
* memory space, i.e. no access to the CIS. Compared to the PLX chip,
|
||||
* the io range functionalities are exchanged.
|
||||
* difference is that the TMD chip has only IO port ranges and doesn't
|
||||
* provide access to the PCMCIA attribute space.
|
||||
*
|
||||
* Pheecom sells cards with the TMD chip as "ASIC version"
|
||||
*/
|
||||
@ -61,32 +49,26 @@
|
||||
#include <pcmcia/cisreg.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_RESET (0x80) /* reset bit in the COR register */
|
||||
#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
|
||||
*/
|
||||
static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
struct orinoco_tmd_card *card = priv->card;
|
||||
u32 addr = card->tmd_io;
|
||||
struct orinoco_pci_card *card = priv->card;
|
||||
unsigned long timeout;
|
||||
u16 reg;
|
||||
|
||||
outb(COR_VALUE | COR_RESET, addr);
|
||||
iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
|
||||
mdelay(1);
|
||||
|
||||
outb(COR_VALUE, addr);
|
||||
iowrite8(COR_VALUE, card->bridge_io);
|
||||
mdelay(1);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Did we timeout ? */
|
||||
/* Still busy? */
|
||||
if (reg & HERMES_CMD_BUSY) {
|
||||
printk(KERN_ERR PFX "Busy timeout\n");
|
||||
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,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int err = 0;
|
||||
struct orinoco_private *priv = NULL;
|
||||
struct orinoco_tmd_card *card;
|
||||
struct net_device *dev = NULL;
|
||||
void __iomem *mem;
|
||||
int err;
|
||||
struct orinoco_private *priv;
|
||||
struct orinoco_pci_card *card;
|
||||
struct net_device *dev;
|
||||
void __iomem *hermes_io, *bridge_io;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
@ -123,20 +105,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
err = pci_request_regions(pdev, DRIVER_NAME);
|
||||
if (err != 0) {
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
|
||||
goto fail_resources;
|
||||
}
|
||||
|
||||
mem = pci_iomap(pdev, 2, 0);
|
||||
if (! mem) {
|
||||
err = -ENOMEM;
|
||||
goto fail_iomap;
|
||||
bridge_io = pci_iomap(pdev, 1, 0);
|
||||
if (!bridge_io) {
|
||||
printk(KERN_ERR PFX "Cannot map bridge registers\n");
|
||||
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 */
|
||||
dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset);
|
||||
if (! dev) {
|
||||
if (!dev) {
|
||||
printk(KERN_ERR PFX "Cannot allocate network device\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_alloc;
|
||||
@ -144,16 +134,11 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
card = priv->card;
|
||||
card->tmd_io = pci_resource_start(pdev, 1);
|
||||
dev->base_addr = pci_resource_start(pdev, 2);
|
||||
card->bridge_io = bridge_io;
|
||||
SET_MODULE_OWNER(dev);
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
hermes_struct_init(&priv->hw, mem, 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);
|
||||
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
|
||||
|
||||
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
|
||||
dev->name, dev);
|
||||
@ -162,7 +147,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
|
||||
err = -EBUSY;
|
||||
goto fail_irq;
|
||||
}
|
||||
dev->irq = pdev->irq;
|
||||
orinoco_pci_setup_netdev(dev, pdev, 2);
|
||||
|
||||
err = orinoco_tmd_cor_reset(priv);
|
||||
if (err) {
|
||||
@ -188,9 +173,12 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
|
||||
free_orinocodev(dev);
|
||||
|
||||
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);
|
||||
|
||||
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 orinoco_private *priv = dev->priv;
|
||||
|
||||
BUG_ON(! dev);
|
||||
struct orinoco_pci_card *card = priv->card;
|
||||
|
||||
unregister_netdev(dev);
|
||||
free_irq(dev->irq, dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
free_orinocodev(dev);
|
||||
pci_iounmap(pdev, priv->hw.iobase);
|
||||
pci_iounmap(pdev, card->bridge_io);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
||||
static struct pci_device_id orinoco_tmd_pci_id_table[] = {
|
||||
static struct pci_device_id orinoco_tmd_id_table[] = {
|
||||
{0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
|
||||
{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 = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = orinoco_tmd_pci_id_table,
|
||||
.id_table = orinoco_tmd_id_table,
|
||||
.probe = orinoco_tmd_init_one,
|
||||
.remove = __devexit_p(orinoco_tmd_remove_one),
|
||||
.suspend = orinoco_pci_suspend,
|
||||
.resume = orinoco_pci_resume,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
pci_unregister_driver(&orinoco_tmd_driver);
|
||||
ssleep(1);
|
||||
}
|
||||
|
||||
module_init(orinoco_tmd_init);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
struct dblock {
|
||||
__le32 _addr; /* adapter address where to write the block */
|
||||
__le16 _len; /* length of the data only, in bytes */
|
||||
__le32 addr; /* adapter address where to write the block */
|
||||
__le16 len; /* length of the data only, in bytes */
|
||||
char data[0]; /* data to be written */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
@ -131,9 +131,9 @@ struct dblock {
|
||||
* items with matching ID should be written.
|
||||
*/
|
||||
struct pdr {
|
||||
__le32 _id; /* record ID */
|
||||
__le32 _addr; /* adapter address where to write the data */
|
||||
__le32 _len; /* expected length of the data, in bytes */
|
||||
__le32 id; /* record ID */
|
||||
__le32 addr; /* adapter address where to write the data */
|
||||
__le32 len; /* expected length of the data, in bytes */
|
||||
char next[0]; /* next PDR starts here */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
@ -144,8 +144,8 @@ struct pdr {
|
||||
* be plugged into the secondary firmware.
|
||||
*/
|
||||
struct pdi {
|
||||
__le16 _len; /* length of ID and data, in words */
|
||||
__le16 _id; /* record ID */
|
||||
__le16 len; /* length of ID and data, in words */
|
||||
__le16 id; /* record ID */
|
||||
char data[0]; /* plug data */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
@ -154,44 +154,44 @@ struct pdi {
|
||||
static inline u32
|
||||
dblock_addr(const struct dblock *blk)
|
||||
{
|
||||
return le32_to_cpu(blk->_addr);
|
||||
return le32_to_cpu(blk->addr);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
dblock_len(const struct dblock *blk)
|
||||
{
|
||||
return le16_to_cpu(blk->_len);
|
||||
return le16_to_cpu(blk->len);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pdr_id(const struct pdr *pdr)
|
||||
{
|
||||
return le32_to_cpu(pdr->_id);
|
||||
return le32_to_cpu(pdr->id);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pdr_addr(const struct pdr *pdr)
|
||||
{
|
||||
return le32_to_cpu(pdr->_addr);
|
||||
return le32_to_cpu(pdr->addr);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pdr_len(const struct pdr *pdr)
|
||||
{
|
||||
return le32_to_cpu(pdr->_len);
|
||||
return le32_to_cpu(pdr->len);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
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 */
|
||||
static inline u32
|
||||
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 */
|
||||
spectrum_aux_setaddr(hw, pdr_addr(pdr));
|
||||
hermes_write_words(hw, HERMES_AUXDATA, pdi->data,
|
||||
pdi_len(pdi) / 2);
|
||||
hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -424,8 +423,8 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
|
||||
|
||||
while (dblock_addr(blk) != BLOCK_END) {
|
||||
spectrum_aux_setaddr(hw, blkaddr);
|
||||
hermes_write_words(hw, HERMES_AUXDATA, blk->data,
|
||||
blklen / 2);
|
||||
hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
|
||||
blklen);
|
||||
|
||||
blk = (struct dblock *) &blk->data[blklen];
|
||||
blkaddr = dblock_addr(blk);
|
||||
@ -653,13 +652,10 @@ spectrum_cs_config(struct pcmcia_device *link)
|
||||
int last_fn, last_ret;
|
||||
u_char buf[64];
|
||||
config_info_t conf;
|
||||
cisinfo_t info;
|
||||
tuple_t tuple;
|
||||
cisparse_t parse;
|
||||
void __iomem *mem;
|
||||
|
||||
CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
|
||||
|
||||
/*
|
||||
* This reads the card's CONFIG tuple to find its
|
||||
* configuration registers.
|
||||
@ -709,12 +705,6 @@ spectrum_cs_config(struct pcmcia_device *link)
|
||||
goto next_entry;
|
||||
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 */
|
||||
/* Note that the CIS values need to be rescaled */
|
||||
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)";
|
||||
|
||||
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_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
|
||||
PCMCIA_DEVICE_NULL,
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <linux/kernel.h> /* ARRAY_SIZE */
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#define IEEE80211_VERSION "git-1.1.7"
|
||||
#define IEEE80211_VERSION "git-1.1.13"
|
||||
|
||||
#define IEEE80211_DATA_LEN 2304
|
||||
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
|
||||
@ -104,6 +104,9 @@
|
||||
#define IEEE80211_SCTL_FRAG 0x000F
|
||||
#define IEEE80211_SCTL_SEQ 0xFFF0
|
||||
|
||||
/* QOS control */
|
||||
#define IEEE80211_QCTL_TID 0x000F
|
||||
|
||||
/* debug macros */
|
||||
|
||||
#ifdef CONFIG_IEEE80211_DEBUG
|
||||
@ -1073,6 +1076,7 @@ struct ieee80211_device {
|
||||
|
||||
int (*handle_management) (struct net_device * dev,
|
||||
struct ieee80211_network * network, u16 type);
|
||||
int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
|
||||
|
||||
/* Typical STA methods */
|
||||
int (*handle_auth) (struct net_device * dev,
|
||||
|
@ -91,4 +91,9 @@ ieee80211softmac_wx_get_genie(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu,
|
||||
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 */
|
||||
|
@ -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)
|
||||
{
|
||||
struct ieee80211_hdr_4addr *hdr11;
|
||||
u16 stype;
|
||||
|
||||
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) &
|
||||
(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
|
||||
case IEEE80211_FCTL_TODS:
|
||||
@ -523,7 +526,13 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* Rx paths. - Jean II */
|
||||
#ifdef CONFIG_WIRELESS_EXT
|
||||
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
|
||||
/* If spy monitoring on */
|
||||
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);
|
||||
}
|
||||
#endif /* IW_WIRELESS_SPY */
|
||||
#endif /* CONFIG_WIRELESS_EXT */
|
||||
|
||||
#ifdef NOT_YET
|
||||
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
|
||||
(header->frame_ctl)));
|
||||
|
||||
IEEE80211_WARNING("%s: IEEE80211_REASSOC_REQ received\n",
|
||||
ieee->dev->name);
|
||||
IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n",
|
||||
ieee->dev->name);
|
||||
if (ieee->handle_reassoc_request != NULL)
|
||||
ieee->handle_reassoc_request(ieee->dev,
|
||||
(struct ieee80211_reassoc_request *)
|
||||
@ -1705,8 +1703,8 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
|
||||
WLAN_FC_GET_STYPE(le16_to_cpu
|
||||
(header->frame_ctl)));
|
||||
|
||||
IEEE80211_WARNING("%s: IEEE80211_ASSOC_REQ received\n",
|
||||
ieee->dev->name);
|
||||
IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n",
|
||||
ieee->dev->name);
|
||||
if (ieee->handle_assoc_request != NULL)
|
||||
ieee->handle_assoc_request(ieee->dev);
|
||||
break;
|
||||
@ -1722,10 +1720,10 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
|
||||
IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
|
||||
WLAN_FC_GET_STYPE(le16_to_cpu
|
||||
(header->frame_ctl)));
|
||||
IEEE80211_WARNING("%s: Unknown management packet: %d\n",
|
||||
ieee->dev->name,
|
||||
WLAN_FC_GET_STYPE(le16_to_cpu
|
||||
(header->frame_ctl)));
|
||||
IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n",
|
||||
ieee->dev->name,
|
||||
WLAN_FC_GET_STYPE(le16_to_cpu
|
||||
(header->frame_ctl)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -220,13 +220,43 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
|
||||
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
|
||||
* a block of 802.11 fragment packets (stored as skbs) */
|
||||
int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_device *ieee = netdev_priv(dev);
|
||||
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,
|
||||
rts_required;
|
||||
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 bytes, fc, hdr_len;
|
||||
struct sk_buff *skb_frag;
|
||||
struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */
|
||||
struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */
|
||||
.duration_id = 0,
|
||||
.seq_ctl = 0
|
||||
.seq_ctl = 0,
|
||||
.qos_ctl = 0
|
||||
};
|
||||
u8 dest[ETH_ALEN], src[ETH_ALEN];
|
||||
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(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)
|
||||
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
|
||||
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.addr3, ieee->bssid, ETH_ALEN);
|
||||
}
|
||||
header.frame_ctl = cpu_to_le16(fc);
|
||||
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. */
|
||||
if ((host_encrypt || host_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) {
|
||||
skb_frag = txb->fragments[0];
|
||||
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.
|
||||
@ -433,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
crypt->ops->extra_mpdu_prefix_len);
|
||||
|
||||
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);
|
||||
|
||||
/* If this is not the last fragment, then add the MOREFRAGS
|
||||
|
@ -50,7 +50,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
||||
char *p;
|
||||
struct iw_event iwe;
|
||||
int i, j;
|
||||
u8 max_rate, rate;
|
||||
char *current_val; /* For rates */
|
||||
u8 rate;
|
||||
|
||||
/* First entry *MUST* be the AP MAC address */
|
||||
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);
|
||||
|
||||
/* Add basic and extended rates */
|
||||
max_rate = 0;
|
||||
p = custom;
|
||||
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
|
||||
/* Rate : stuffing multiple values in a single event require a bit
|
||||
* more of magic - Jean II */
|
||||
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;) {
|
||||
if (j < network->rates_ex_len &&
|
||||
((network->rates_ex[j] & 0x7F) <
|
||||
@ -117,28 +122,21 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
|
||||
rate = network->rates_ex[j++] & 0x7F;
|
||||
else
|
||||
rate = network->rates[i++] & 0x7F;
|
||||
if (rate > max_rate)
|
||||
max_rate = rate;
|
||||
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
|
||||
"%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
|
||||
/* Bit rate given in 500 kb/s units (+ 0x80) */
|
||||
iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
|
||||
/* Add new value to event */
|
||||
current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
for (; j < network->rates_ex_len; j++) {
|
||||
rate = network->rates_ex[j] & 0x7F;
|
||||
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
|
||||
"%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
|
||||
if (rate > max_rate)
|
||||
max_rate = rate;
|
||||
/* Bit rate given in 500 kb/s units (+ 0x80) */
|
||||
iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
|
||||
/* Add new value to event */
|
||||
current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
|
||||
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);
|
||||
/* Check if we added any rate */
|
||||
if((current_val - start) > IW_EV_LCP_LEN)
|
||||
start = current_val;
|
||||
|
||||
/* Add quality statistics */
|
||||
iwe.cmd = IWEVQUAL;
|
||||
|
@ -82,7 +82,7 @@ ieee80211softmac_assoc_timeout(void *d)
|
||||
}
|
||||
|
||||
/* Sends out a disassociation request to the desired AP */
|
||||
static void
|
||||
void
|
||||
ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -38,7 +38,8 @@
|
||||
* The event context is private and can only be used from
|
||||
* within this module. Its meaning varies with the event
|
||||
* type:
|
||||
* SCAN_FINISHED: no special meaning
|
||||
* SCAN_FINISHED,
|
||||
* DISASSOCIATED: NULL
|
||||
* ASSOCIATED,
|
||||
* ASSOCIATE_FAILED,
|
||||
* ASSOCIATE_TIMEOUT,
|
||||
@ -59,15 +60,15 @@
|
||||
*/
|
||||
|
||||
static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
|
||||
"scan finished",
|
||||
"associated",
|
||||
NULL, /* scan finished */
|
||||
NULL, /* associated */
|
||||
"associating failed",
|
||||
"associating timed out",
|
||||
"authenticated",
|
||||
"authenticating failed",
|
||||
"authenticating timed out",
|
||||
"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;
|
||||
char *msg = NULL;
|
||||
|
||||
memset(&wrqu, '\0', sizeof (union iwreq_data));
|
||||
|
||||
switch(event) {
|
||||
case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
|
||||
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);
|
||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
we_event = SIOCGIWAP;
|
||||
break;
|
||||
/* fall through */
|
||||
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;
|
||||
we_event = SIOCGIWAP;
|
||||
break;
|
||||
case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
|
||||
wrqu.data.length = 0;
|
||||
wrqu.data.flags = 0;
|
||||
memset(&wrqu, '\0', sizeof (union iwreq_data));
|
||||
we_event = SIOCGIWSCAN;
|
||||
break;
|
||||
default:
|
||||
msg = event_descriptions[event];
|
||||
if (!msg)
|
||||
msg = "SOFTMAC EVENT BUG";
|
||||
wrqu.data.length = strlen(msg);
|
||||
we_event = IWEVCUSTOM;
|
||||
break;
|
||||
|
@ -150,6 +150,7 @@ int ieee80211softmac_handle_disassoc(struct net_device * dev,
|
||||
int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
|
||||
struct ieee80211_reassoc_request * reassoc);
|
||||
void ieee80211softmac_assoc_timeout(void *d);
|
||||
void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason);
|
||||
|
||||
/* some helper functions */
|
||||
static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
|
||||
|
@ -431,3 +431,35 @@ ieee80211softmac_wx_get_genie(struct net_device *dev,
|
||||
}
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user