dect
/
linux-2.6
Archived
13
0
Fork 0

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

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

View File

@ -14,8 +14,8 @@ Copyright (C) 2004-2006, Intel Corporation
README.ipw2200
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:

View File

@ -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

View File

@ -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);

View File

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

View File

@ -92,7 +92,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n",
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");

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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)) \

View File

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

View File

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

View File

@ -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)) {

View File

@ -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:

View File

@ -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,

View File

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

View File

@ -3,7 +3,7 @@
* Driver for Prism II devices which would usually be driven by orinoco_cs,
* 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);

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

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

View File

@ -501,8 +501,11 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
{
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 */
}

View File

@ -369,7 +369,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* Put this code here so that we avoid duplicating it in all
* 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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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);