aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/prism54
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/wireless/prism54
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/net/wireless/prism54')
-rw-r--r--drivers/net/wireless/prism54/Makefile8
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.c260
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.h173
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c2750
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.h51
-rw-r--r--drivers/net/wireless/prism54/isl_oid.h507
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c956
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h216
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c519
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.h73
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c339
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c513
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.h145
-rw-r--r--drivers/net/wireless/prism54/oid_mgt.c907
-rw-r--r--drivers/net/wireless/prism54/oid_mgt.h59
-rw-r--r--drivers/net/wireless/prism54/prismcompat.h44
16 files changed, 7520 insertions, 0 deletions
diff --git a/drivers/net/wireless/prism54/Makefile b/drivers/net/wireless/prism54/Makefile
new file mode 100644
index 000000000000..fad305c76737
--- /dev/null
+++ b/drivers/net/wireless/prism54/Makefile
@@ -0,0 +1,8 @@
1# $Id: Makefile.k26,v 1.7 2004/01/30 16:24:00 ajfa Exp $
2
3prism54-objs := islpci_eth.o islpci_mgt.o \
4 isl_38xx.o isl_ioctl.o islpci_dev.o \
5 islpci_hotplug.o oid_mgt.o
6
7obj-$(CONFIG_PRISM54) += prism54.o
8
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
new file mode 100644
index 000000000000..4481ec18c5a0
--- /dev/null
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -0,0 +1,260 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <linux/version.h>
22#include <linux/module.h>
23#include <linux/types.h>
24#include <linux/delay.h>
25
26#include <asm/uaccess.h>
27#include <asm/io.h>
28
29#include "prismcompat.h"
30#include "isl_38xx.h"
31#include "islpci_dev.h"
32#include "islpci_mgt.h"
33
34/******************************************************************************
35 Device Interface & Control functions
36******************************************************************************/
37
38/**
39 * isl38xx_disable_interrupts - disable all interrupts
40 * @device: pci memory base address
41 *
42 * Instructs the device to disable all interrupt reporting by asserting
43 * the IRQ line. New events may still show up in the interrupt identification
44 * register located at offset %ISL38XX_INT_IDENT_REG.
45 */
46void
47isl38xx_disable_interrupts(void __iomem *device)
48{
49 isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
50 udelay(ISL38XX_WRITEIO_DELAY);
51}
52
53void
54isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
55 int *powerstate, void __iomem *device_base)
56{
57 /* device requests to go into sleep mode
58 * check whether the transmit queues for data and management are empty */
59 if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ))
60 /* data tx queue not empty */
61 return;
62
63 if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
64 /* management tx queue not empty */
65 return;
66
67 /* check also whether received frames are pending */
68 if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ))
69 /* data rx queue not empty */
70 return;
71
72 if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ))
73 /* management rx queue not empty */
74 return;
75
76#if VERBOSE > SHOW_ERROR_MESSAGES
77 DEBUG(SHOW_TRACING, "Device going to sleep mode\n");
78#endif
79
80 /* all queues are empty, allow the device to go into sleep mode */
81 *powerstate = ISL38XX_PSM_POWERSAVE_STATE;
82
83 /* assert the Sleep interrupt in the Device Interrupt Register */
84 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP,
85 ISL38XX_DEV_INT_REG);
86 udelay(ISL38XX_WRITEIO_DELAY);
87}
88
89void
90isl38xx_handle_wakeup(isl38xx_control_block *control_block,
91 int *powerstate, void __iomem *device_base)
92{
93 /* device is in active state, update the powerstate flag */
94 *powerstate = ISL38XX_PSM_ACTIVE_STATE;
95
96 /* now check whether there are frames pending for the card */
97 if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)
98 && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
99 return;
100
101#if VERBOSE > SHOW_ERROR_MESSAGES
102 DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n");
103#endif
104
105 /* either data or management transmit queue has a frame pending
106 * trigger the device by setting the Update bit in the Device Int reg */
107 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
108 ISL38XX_DEV_INT_REG);
109 udelay(ISL38XX_WRITEIO_DELAY);
110}
111
112void
113isl38xx_trigger_device(int asleep, void __iomem *device_base)
114{
115 struct timeval current_time;
116 u32 reg, counter = 0;
117
118#if VERBOSE > SHOW_ERROR_MESSAGES
119 DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
120#endif
121
122 /* check whether the device is in power save mode */
123 if (asleep) {
124 /* device is in powersave, trigger the device for wakeup */
125#if VERBOSE > SHOW_ERROR_MESSAGES
126 do_gettimeofday(&current_time);
127 DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
128 current_time.tv_sec, (long)current_time.tv_usec);
129#endif
130
131 DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
132 current_time.tv_sec, (long)current_time.tv_usec,
133 readl(device_base + ISL38XX_CTRL_STAT_REG));
134 udelay(ISL38XX_WRITEIO_DELAY);
135
136 reg = readl(device_base + ISL38XX_INT_IDENT_REG);
137 if (reg == 0xabadface) {
138#if VERBOSE > SHOW_ERROR_MESSAGES
139 do_gettimeofday(&current_time);
140 DEBUG(SHOW_TRACING,
141 "%08li.%08li Device register abadface\n",
142 current_time.tv_sec, (long)current_time.tv_usec);
143#endif
144 /* read the Device Status Register until Sleepmode bit is set */
145 while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
146 (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
147 udelay(ISL38XX_WRITEIO_DELAY);
148 counter++;
149 }
150
151 DEBUG(SHOW_TRACING,
152 "%08li.%08li Device register read %08x\n",
153 current_time.tv_sec, (long)current_time.tv_usec,
154 readl(device_base + ISL38XX_CTRL_STAT_REG));
155 udelay(ISL38XX_WRITEIO_DELAY);
156
157#if VERBOSE > SHOW_ERROR_MESSAGES
158 do_gettimeofday(&current_time);
159 DEBUG(SHOW_TRACING,
160 "%08li.%08li Device asleep counter %i\n",
161 current_time.tv_sec, (long)current_time.tv_usec,
162 counter);
163#endif
164 }
165 /* assert the Wakeup interrupt in the Device Interrupt Register */
166 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP,
167 ISL38XX_DEV_INT_REG);
168 udelay(ISL38XX_WRITEIO_DELAY);
169
170 /* perform another read on the Device Status Register */
171 reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
172 udelay(ISL38XX_WRITEIO_DELAY);
173
174#if VERBOSE > SHOW_ERROR_MESSAGES
175 do_gettimeofday(&current_time);
176 DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
177 current_time.tv_sec, (long)current_time.tv_usec, reg);
178#endif
179 } else {
180 /* device is (still) awake */
181#if VERBOSE > SHOW_ERROR_MESSAGES
182 DEBUG(SHOW_TRACING, "Device is in active state\n");
183#endif
184 /* trigger the device by setting the Update bit in the Device Int reg */
185
186 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
187 ISL38XX_DEV_INT_REG);
188 udelay(ISL38XX_WRITEIO_DELAY);
189 }
190}
191
192void
193isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
194{
195#if VERBOSE > SHOW_ERROR_MESSAGES
196 DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
197#endif
198
199 /* load the address of the control block in the device */
200 isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG);
201 udelay(ISL38XX_WRITEIO_DELAY);
202
203 /* set the reset bit in the Device Interrupt Register */
204 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
205 udelay(ISL38XX_WRITEIO_DELAY);
206
207 /* enable the interrupt for detecting initialization */
208
209 /* Note: Do not enable other interrupts here. We want the
210 * device to have come up first 100% before allowing any other
211 * interrupts. */
212 isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
213 udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */
214}
215
216void
217isl38xx_enable_common_interrupts(void __iomem *device_base) {
218 u32 reg;
219 reg = ( ISL38XX_INT_IDENT_UPDATE |
220 ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP);
221 isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
222 udelay(ISL38XX_WRITEIO_DELAY);
223}
224
225int
226isl38xx_in_queue(isl38xx_control_block *cb, int queue)
227{
228 const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) -
229 le32_to_cpu(cb->device_curr_frag[queue]));
230
231 /* determine the amount of fragments in the queue depending on the type
232 * of the queue, either transmit or receive */
233
234 BUG_ON(delta < 0); /* driver ptr must be ahead of device ptr */
235
236 switch (queue) {
237 /* send queues */
238 case ISL38XX_CB_TX_MGMTQ:
239 BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
240 case ISL38XX_CB_TX_DATA_LQ:
241 case ISL38XX_CB_TX_DATA_HQ:
242 BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
243 return delta;
244 break;
245
246 /* receive queues */
247 case ISL38XX_CB_RX_MGMTQ:
248 BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
249 return ISL38XX_CB_MGMT_QSIZE - delta;
250 break;
251
252 case ISL38XX_CB_RX_DATA_LQ:
253 case ISL38XX_CB_RX_DATA_HQ:
254 BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
255 return ISL38XX_CB_RX_QSIZE - delta;
256 break;
257 }
258 BUG();
259 return 0;
260}
diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h
new file mode 100644
index 000000000000..e83e4912ab66
--- /dev/null
+++ b/drivers/net/wireless/prism54/isl_38xx.h
@@ -0,0 +1,173 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20#ifndef _ISL_38XX_H
21#define _ISL_38XX_H
22
23#include <linux/version.h>
24#include <asm/io.h>
25#include <asm/byteorder.h>
26
27#define ISL38XX_CB_RX_QSIZE 8
28#define ISL38XX_CB_TX_QSIZE 32
29
30/* ISL38XX Access Point Specific definitions */
31#define ISL38XX_MAX_WDS_LINKS 8
32
33/* ISL38xx Client Specific definitions */
34#define ISL38XX_PSM_ACTIVE_STATE 0
35#define ISL38XX_PSM_POWERSAVE_STATE 1
36
37/* ISL38XX Host Interface Definitions */
38#define ISL38XX_PCI_MEM_SIZE 0x02000
39#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000
40#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000
41#define ISL38XX_WRITEIO_DELAY 10 /* in us */
42#define ISL38XX_RESET_DELAY 50 /* in ms */
43#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */
44#define ISL38XX_MAX_WAIT_CYCLES 10
45
46/* PCI Memory Area */
47#define ISL38XX_HARDWARE_REG 0x0000
48#define ISL38XX_CARDBUS_CIS 0x0800
49#define ISL38XX_DIRECT_MEM_WIN 0x1000
50
51/* Hardware registers */
52#define ISL38XX_DEV_INT_REG 0x0000
53#define ISL38XX_INT_IDENT_REG 0x0010
54#define ISL38XX_INT_ACK_REG 0x0014
55#define ISL38XX_INT_EN_REG 0x0018
56#define ISL38XX_GEN_PURP_COM_REG_1 0x0020
57#define ISL38XX_GEN_PURP_COM_REG_2 0x0024
58#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1
59#define ISL38XX_DIR_MEM_BASE_REG 0x0030
60#define ISL38XX_CTRL_STAT_REG 0x0078
61
62/* High end mobos queue up pci writes, the following
63 * is used to "read" from after a write to force flush */
64#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG
65
66/**
67 * isl38xx_w32_flush - PCI iomem write helper
68 * @base: (host) memory base address of the device
69 * @val: 32bit value (host order) to write
70 * @offset: byte offset into @base to write value to
71 *
72 * This helper takes care of writing a 32bit datum to the
73 * specified offset into the device's pci memory space, and making sure
74 * the pci memory buffers get flushed by performing one harmless read
75 * from the %ISL38XX_PCI_POSTING_FLUSH offset.
76 */
77static inline void
78isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
79{
80 writel(val, base + offset);
81 (void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
82}
83
84/* Device Interrupt register bits */
85#define ISL38XX_DEV_INT_RESET 0x0001
86#define ISL38XX_DEV_INT_UPDATE 0x0002
87#define ISL38XX_DEV_INT_WAKEUP 0x0008
88#define ISL38XX_DEV_INT_SLEEP 0x0010
89
90/* Interrupt Identification/Acknowledge/Enable register bits */
91#define ISL38XX_INT_IDENT_UPDATE 0x0002
92#define ISL38XX_INT_IDENT_INIT 0x0004
93#define ISL38XX_INT_IDENT_WAKEUP 0x0008
94#define ISL38XX_INT_IDENT_SLEEP 0x0010
95#define ISL38XX_INT_SOURCES 0x001E
96
97/* Control/Status register bits */
98/* Looks like there are other meaningful bits
99 0x20004400 seen in normal operation,
100 0x200044db at 'timeout waiting for mgmt response'
101*/
102#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200
103#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
104#define ISL38XX_CTRL_STAT_RESET 0x10000000
105#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000
106#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000
107#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000
108
109/* Control Block definitions */
110#define ISL38XX_CB_RX_DATA_LQ 0
111#define ISL38XX_CB_TX_DATA_LQ 1
112#define ISL38XX_CB_RX_DATA_HQ 2
113#define ISL38XX_CB_TX_DATA_HQ 3
114#define ISL38XX_CB_RX_MGMTQ 4
115#define ISL38XX_CB_TX_MGMTQ 5
116#define ISL38XX_CB_QCOUNT 6
117#define ISL38XX_CB_MGMT_QSIZE 4
118#define ISL38XX_MIN_QTHRESHOLD 4 /* fragments */
119
120/* Memory Manager definitions */
121#define MGMT_FRAME_SIZE 1500 /* >= size struct obj_bsslist */
122#define MGMT_TX_FRAME_COUNT 24 /* max 4 + spare 4 + 8 init */
123#define MGMT_RX_FRAME_COUNT 24 /* 4*4 + spare 8 */
124#define MGMT_FRAME_COUNT (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT)
125#define CONTROL_BLOCK_SIZE 1024 /* should be enough */
126#define PSM_FRAME_SIZE 1536
127#define PSM_MINIMAL_STATION_COUNT 64
128#define PSM_FRAME_COUNT PSM_MINIMAL_STATION_COUNT
129#define PSM_BUFFER_SIZE PSM_FRAME_SIZE * PSM_FRAME_COUNT
130#define MAX_TRAP_RX_QUEUE 4
131#define HOST_MEM_BLOCK CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE
132
133/* Fragment package definitions */
134#define FRAGMENT_FLAG_MF 0x0001
135#define MAX_FRAGMENT_SIZE 1536
136
137/* In monitor mode frames have a header. I don't know exactly how big those
138 * frame can be but I've never seen any frame bigger than 1584... :
139 */
140#define MAX_FRAGMENT_SIZE_RX 1600
141
142typedef struct {
143 u32 address; /* physical address on host */
144 u16 size; /* packet size */
145 u16 flags; /* set of bit-wise flags */
146} isl38xx_fragment;
147
148struct isl38xx_cb {
149 u32 driver_curr_frag[ISL38XX_CB_QCOUNT];
150 u32 device_curr_frag[ISL38XX_CB_QCOUNT];
151 isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE];
152 isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE];
153 isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE];
154 isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE];
155 isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE];
156 isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE];
157};
158
159typedef struct isl38xx_cb isl38xx_control_block;
160
161/* determine number of entries currently in queue */
162int isl38xx_in_queue(isl38xx_control_block *cb, int queue);
163
164void isl38xx_disable_interrupts(void __iomem *);
165void isl38xx_enable_common_interrupts(void __iomem *);
166
167void isl38xx_handle_sleep_request(isl38xx_control_block *, int *,
168 void __iomem *);
169void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void __iomem *);
170void isl38xx_trigger_device(int, void __iomem *);
171void isl38xx_interface_reset(void __iomem *, dma_addr_t);
172
173#endif /* _ISL_38XX_H */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
new file mode 100644
index 000000000000..0f29a9c7bc2c
--- /dev/null
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -0,0 +1,2750 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
5 * (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
6 * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <linux/version.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/if_arp.h>
27#include <linux/pci.h>
28
29#include <asm/uaccess.h>
30
31#include "prismcompat.h"
32#include "isl_ioctl.h"
33#include "islpci_mgt.h"
34#include "isl_oid.h" /* additional types and defs for isl38xx fw */
35#include "oid_mgt.h"
36
37#include <net/iw_handler.h> /* New driver API */
38
39
40static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
41 u8 *wpa_ie, size_t wpa_ie_len);
42static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
43static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
44 __u32 *, char *);
45
46
47/**
48 * prism54_mib_mode_helper - MIB change mode helper function
49 * @mib: the &struct islpci_mib object to modify
50 * @iw_mode: new mode (%IW_MODE_*)
51 *
52 * This is a helper function, hence it does not lock. Make sure
53 * caller deals with locking *if* necessary. This function sets the
54 * mode-dependent mib values and does the mapping of the Linux
55 * Wireless API modes to Device firmware modes. It also checks for
56 * correct valid Linux wireless modes.
57 */
58static int
59prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
60{
61 u32 config = INL_CONFIG_MANUALRUN;
62 u32 mode, bsstype;
63
64 /* For now, just catch early the Repeater and Secondary modes here */
65 if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
66 printk(KERN_DEBUG
67 "%s(): Sorry, Repeater mode and Secondary mode "
68 "are not yet supported by this driver.\n", __FUNCTION__);
69 return -EINVAL;
70 }
71
72 priv->iw_mode = iw_mode;
73
74 switch (iw_mode) {
75 case IW_MODE_AUTO:
76 mode = INL_MODE_CLIENT;
77 bsstype = DOT11_BSSTYPE_ANY;
78 break;
79 case IW_MODE_ADHOC:
80 mode = INL_MODE_CLIENT;
81 bsstype = DOT11_BSSTYPE_IBSS;
82 break;
83 case IW_MODE_INFRA:
84 mode = INL_MODE_CLIENT;
85 bsstype = DOT11_BSSTYPE_INFRA;
86 break;
87 case IW_MODE_MASTER:
88 mode = INL_MODE_AP;
89 bsstype = DOT11_BSSTYPE_INFRA;
90 break;
91 case IW_MODE_MONITOR:
92 mode = INL_MODE_PROMISCUOUS;
93 bsstype = DOT11_BSSTYPE_ANY;
94 config |= INL_CONFIG_RXANNEX;
95 break;
96 default:
97 return -EINVAL;
98 }
99
100 if (init_wds)
101 config |= INL_CONFIG_WDS;
102 mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype);
103 mgt_set(priv, OID_INL_CONFIG, &config);
104 mgt_set(priv, OID_INL_MODE, &mode);
105
106 return 0;
107}
108
109/**
110 * prism54_mib_init - fill MIB cache with defaults
111 *
112 * this function initializes the struct given as @mib with defaults,
113 * of which many are retrieved from the global module parameter
114 * variables.
115 */
116
117void
118prism54_mib_init(islpci_private *priv)
119{
120 u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
121 struct obj_buffer psm_buffer = {
122 .size = PSM_BUFFER_SIZE,
123 .addr = priv->device_psm_buffer
124 };
125
126 channel = CARD_DEFAULT_CHANNEL;
127 authen = CARD_DEFAULT_AUTHEN;
128 wep = CARD_DEFAULT_WEP;
129 filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
130 dot1x = CARD_DEFAULT_DOT1X;
131 mlme = CARD_DEFAULT_MLME_MODE;
132 conformance = CARD_DEFAULT_CONFORMANCE;
133 power = 127;
134 mode = CARD_DEFAULT_IW_MODE;
135
136 mgt_set(priv, DOT11_OID_CHANNEL, &channel);
137 mgt_set(priv, DOT11_OID_AUTHENABLE, &authen);
138 mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep);
139 mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
140 mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
141 mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
142 mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
143 mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
144 mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
145
146 /* This sets all of the mode-dependent values */
147 prism54_mib_mode_helper(priv, mode);
148}
149
150/* this will be executed outside of atomic context thanks to
151 * schedule_work(), thus we can as well use sleeping semaphore
152 * locking */
153void
154prism54_update_stats(islpci_private *priv)
155{
156 char *data;
157 int j;
158 struct obj_bss bss, *bss2;
159 union oid_res_t r;
160
161 if (down_interruptible(&priv->stats_sem))
162 return;
163
164/* Noise floor.
165 * I'm not sure if the unit is dBm.
166 * Note : If we are not connected, this value seems to be irrelevant. */
167
168 mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
169 priv->local_iwstatistics.qual.noise = r.u;
170
171/* Get the rssi of the link. To do this we need to retrieve a bss. */
172
173 /* First get the MAC address of the AP we are associated with. */
174 mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
175 data = r.ptr;
176
177 /* copy this MAC to the bss */
178 memcpy(bss.address, data, 6);
179 kfree(data);
180
181 /* now ask for the corresponding bss */
182 j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r);
183 bss2 = r.ptr;
184 /* report the rssi and use it to calculate
185 * link quality through a signal-noise
186 * ratio */
187 priv->local_iwstatistics.qual.level = bss2->rssi;
188 priv->local_iwstatistics.qual.qual =
189 bss2->rssi - priv->iwstatistics.qual.noise;
190
191 kfree(bss2);
192
193 /* report that the stats are new */
194 priv->local_iwstatistics.qual.updated = 0x7;
195
196/* Rx : unable to decrypt the MPDU */
197 mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r);
198 priv->local_iwstatistics.discard.code = r.u;
199
200/* Tx : Max MAC retries num reached */
201 mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r);
202 priv->local_iwstatistics.discard.retries = r.u;
203
204 up(&priv->stats_sem);
205
206 return;
207}
208
209struct iw_statistics *
210prism54_get_wireless_stats(struct net_device *ndev)
211{
212 islpci_private *priv = netdev_priv(ndev);
213
214 /* If the stats are being updated return old data */
215 if (down_trylock(&priv->stats_sem) == 0) {
216 memcpy(&priv->iwstatistics, &priv->local_iwstatistics,
217 sizeof (struct iw_statistics));
218 /* They won't be marked updated for the next time */
219 priv->local_iwstatistics.qual.updated = 0;
220 up(&priv->stats_sem);
221 } else
222 priv->iwstatistics.qual.updated = 0;
223
224 /* Update our wireless stats, but do not schedule to often
225 * (max 1 HZ) */
226 if ((priv->stats_timestamp == 0) ||
227 time_after(jiffies, priv->stats_timestamp + 1 * HZ)) {
228 schedule_work(&priv->stats_work);
229 priv->stats_timestamp = jiffies;
230 }
231
232 return &priv->iwstatistics;
233}
234
235static int
236prism54_commit(struct net_device *ndev, struct iw_request_info *info,
237 char *cwrq, char *extra)
238{
239 islpci_private *priv = netdev_priv(ndev);
240
241 /* simply re-set the last set SSID, this should commit most stuff */
242
243 /* Commit in Monitor mode is not necessary, also setting essid
244 * in Monitor mode does not make sense and isn't allowed for this
245 * device's firmware */
246 if (priv->iw_mode != IW_MODE_MONITOR)
247 return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL);
248 return 0;
249}
250
251static int
252prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
253 char *cwrq, char *extra)
254{
255 islpci_private *priv = netdev_priv(ndev);
256 char *capabilities;
257 union oid_res_t r;
258 int rvalue;
259
260 if (islpci_get_state(priv) < PRV_STATE_INIT) {
261 strncpy(cwrq, "NOT READY!", IFNAMSIZ);
262 return 0;
263 }
264 rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r);
265
266 switch (r.u) {
267 case INL_PHYCAP_5000MHZ:
268 capabilities = "IEEE 802.11a/b/g";
269 break;
270 case INL_PHYCAP_FAA:
271 capabilities = "IEEE 802.11b/g - FAA Support";
272 break;
273 case INL_PHYCAP_2400MHZ:
274 default:
275 capabilities = "IEEE 802.11b/g"; /* Default */
276 break;
277 }
278 strncpy(cwrq, capabilities, IFNAMSIZ);
279 return rvalue;
280}
281
282static int
283prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
284 struct iw_freq *fwrq, char *extra)
285{
286 islpci_private *priv = netdev_priv(ndev);
287 int rvalue;
288 u32 c;
289
290 if (fwrq->m < 1000)
291 /* we have a channel number */
292 c = fwrq->m;
293 else
294 c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0;
295
296 rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL;
297
298 /* Call commit handler */
299 return (rvalue ? rvalue : -EINPROGRESS);
300}
301
302static int
303prism54_get_freq(struct net_device *ndev, struct iw_request_info *info,
304 struct iw_freq *fwrq, char *extra)
305{
306 islpci_private *priv = netdev_priv(ndev);
307 union oid_res_t r;
308 int rvalue;
309
310 rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r);
311 fwrq->i = r.u;
312 rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r);
313 fwrq->m = r.u;
314 fwrq->e = 3;
315
316 return rvalue;
317}
318
319static int
320prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
321 __u32 * uwrq, char *extra)
322{
323 islpci_private *priv = netdev_priv(ndev);
324 u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
325
326 /* Let's see if the user passed a valid Linux Wireless mode */
327 if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) {
328 printk(KERN_DEBUG
329 "%s: %s() You passed a non-valid init_mode.\n",
330 priv->ndev->name, __FUNCTION__);
331 return -EINVAL;
332 }
333
334 down_write(&priv->mib_sem);
335
336 if (prism54_mib_mode_helper(priv, *uwrq)) {
337 up_write(&priv->mib_sem);
338 return -EOPNOTSUPP;
339 }
340
341 /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an
342 * extended one.
343 */
344 if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN))
345 mlmeautolevel = DOT11_MLME_INTERMEDIATE;
346 if (priv->wpa)
347 mlmeautolevel = DOT11_MLME_EXTENDED;
348
349 mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
350
351 if (mgt_commit(priv)) {
352 up_write(&priv->mib_sem);
353 return -EIO;
354 }
355 priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
356 ? priv->monitor_type : ARPHRD_ETHER;
357 up_write(&priv->mib_sem);
358
359 return 0;
360}
361
362/* Use mib cache */
363static int
364prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
365 __u32 * uwrq, char *extra)
366{
367 islpci_private *priv = netdev_priv(ndev);
368
369 BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode >
370 IW_MODE_MONITOR));
371 *uwrq = priv->iw_mode;
372
373 return 0;
374}
375
376/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to
377 * emit data if (sensitivity > rssi - noise) (in dBm).
378 * prism54_set_sens does not seem to work.
379 */
380
381static int
382prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
383 struct iw_param *vwrq, char *extra)
384{
385 islpci_private *priv = netdev_priv(ndev);
386 u32 sens;
387
388 /* by default the card sets this to 20. */
389 sens = vwrq->disabled ? 20 : vwrq->value;
390
391 return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
392}
393
394static int
395prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
396 struct iw_param *vwrq, char *extra)
397{
398 islpci_private *priv = netdev_priv(ndev);
399 union oid_res_t r;
400 int rvalue;
401
402 rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r);
403
404 vwrq->value = r.u;
405 vwrq->disabled = (vwrq->value == 0);
406 vwrq->fixed = 1;
407
408 return rvalue;
409}
410
411static int
412prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
413 struct iw_point *dwrq, char *extra)
414{
415 struct iw_range *range = (struct iw_range *) extra;
416 islpci_private *priv = netdev_priv(ndev);
417 u8 *data;
418 int i, m, rvalue;
419 struct obj_frequencies *freq;
420 union oid_res_t r;
421
422 memset(range, 0, sizeof (struct iw_range));
423 dwrq->length = sizeof (struct iw_range);
424
425 /* set the wireless extension version number */
426 range->we_version_source = SUPPORTED_WIRELESS_EXT;
427 range->we_version_compiled = WIRELESS_EXT;
428
429 /* Now the encoding capabilities */
430 range->num_encoding_sizes = 3;
431 /* 64(40) bits WEP */
432 range->encoding_size[0] = 5;
433 /* 128(104) bits WEP */
434 range->encoding_size[1] = 13;
435 /* 256 bits for WPA-PSK */
436 range->encoding_size[2] = 32;
437 /* 4 keys are allowed */
438 range->max_encoding_tokens = 4;
439
440 /* we don't know the quality range... */
441 range->max_qual.level = 0;
442 range->max_qual.noise = 0;
443 range->max_qual.qual = 0;
444 /* these value describe an average quality. Needs more tweaking... */
445 range->avg_qual.level = -80; /* -80 dBm */
446 range->avg_qual.noise = 0; /* don't know what to put here */
447 range->avg_qual.qual = 0;
448
449 range->sensitivity = 200;
450
451 /* retry limit capabilities */
452 range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
453 range->retry_flags = IW_RETRY_LIMIT;
454 range->r_time_flags = IW_RETRY_LIFETIME;
455
456 /* I don't know the range. Put stupid things here */
457 range->min_retry = 1;
458 range->max_retry = 65535;
459 range->min_r_time = 1024;
460 range->max_r_time = 65535 * 1024;
461
462 /* txpower is supported in dBm's */
463 range->txpower_capa = IW_TXPOW_DBM;
464
465#if WIRELESS_EXT > 16
466 /* Event capability (kernel + driver) */
467 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
468 IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
469 IW_EVENT_CAPA_MASK(SIOCGIWAP));
470 range->event_capa[1] = IW_EVENT_CAPA_K_1;
471 range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
472#endif /* WIRELESS_EXT > 16 */
473
474 if (islpci_get_state(priv) < PRV_STATE_INIT)
475 return 0;
476
477 /* Request the device for the supported frequencies
478 * not really relevant since some devices will report the 5 GHz band
479 * frequencies even if they don't support them.
480 */
481 rvalue =
482 mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r);
483 freq = r.ptr;
484
485 range->num_channels = freq->nr;
486 range->num_frequency = freq->nr;
487
488 m = min(IW_MAX_FREQUENCIES, (int) freq->nr);
489 for (i = 0; i < m; i++) {
490 range->freq[i].m = freq->mhz[i];
491 range->freq[i].e = 6;
492 range->freq[i].i = channel_of_freq(freq->mhz[i]);
493 }
494 kfree(freq);
495
496 rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
497 data = r.ptr;
498
499 /* We got an array of char. It is NULL terminated. */
500 i = 0;
501 while ((i < IW_MAX_BITRATES) && (*data != 0)) {
502 /* the result must be in bps. The card gives us 500Kbps */
503 range->bitrate[i] = *data * 500000;
504 i++;
505 data++;
506 }
507 range->num_bitrates = i;
508 kfree(r.ptr);
509
510 return rvalue;
511}
512
513/* Set AP address*/
514
515static int
516prism54_set_wap(struct net_device *ndev, struct iw_request_info *info,
517 struct sockaddr *awrq, char *extra)
518{
519 islpci_private *priv = netdev_priv(ndev);
520 char bssid[6];
521 int rvalue;
522
523 if (awrq->sa_family != ARPHRD_ETHER)
524 return -EINVAL;
525
526 /* prepare the structure for the set object */
527 memcpy(&bssid[0], awrq->sa_data, 6);
528
529 /* set the bssid -- does this make sense when in AP mode? */
530 rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid);
531
532 return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */
533}
534
535/* get AP address*/
536
537static int
538prism54_get_wap(struct net_device *ndev, struct iw_request_info *info,
539 struct sockaddr *awrq, char *extra)
540{
541 islpci_private *priv = netdev_priv(ndev);
542 union oid_res_t r;
543 int rvalue;
544
545 rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
546 memcpy(awrq->sa_data, r.ptr, 6);
547 awrq->sa_family = ARPHRD_ETHER;
548 kfree(r.ptr);
549
550 return rvalue;
551}
552
553static int
554prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
555 struct iw_param *vwrq, char *extra)
556{
557 /* hehe the device does this automagicaly */
558 return 0;
559}
560
561/* a little helper that will translate our data into a card independent
562 * format that the Wireless Tools will understand. This was inspired by
563 * the "Aironet driver for 4500 and 4800 series cards" (GPL)
564 */
565
566static char *
567prism54_translate_bss(struct net_device *ndev, char *current_ev,
568 char *end_buf, struct obj_bss *bss, char noise)
569{
570 struct iw_event iwe; /* Temporary buffer */
571 short cap;
572 islpci_private *priv = netdev_priv(ndev);
573
574 /* The first entry must be the MAC address */
575 memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
576 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
577 iwe.cmd = SIOCGIWAP;
578 current_ev =
579 iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
580
581 /* The following entries will be displayed in the same order we give them */
582
583 /* The ESSID. */
584 iwe.u.data.length = bss->ssid.length;
585 iwe.u.data.flags = 1;
586 iwe.cmd = SIOCGIWESSID;
587 current_ev = iwe_stream_add_point(current_ev, end_buf,
588 &iwe, bss->ssid.octets);
589
590 /* Capabilities */
591#define CAP_ESS 0x01
592#define CAP_IBSS 0x02
593#define CAP_CRYPT 0x10
594
595 /* Mode */
596 cap = bss->capinfo;
597 iwe.u.mode = 0;
598 if (cap & CAP_ESS)
599 iwe.u.mode = IW_MODE_MASTER;
600 else if (cap & CAP_IBSS)
601 iwe.u.mode = IW_MODE_ADHOC;
602 iwe.cmd = SIOCGIWMODE;
603 if (iwe.u.mode)
604 current_ev =
605 iwe_stream_add_event(current_ev, end_buf, &iwe,
606 IW_EV_UINT_LEN);
607
608 /* Encryption capability */
609 if (cap & CAP_CRYPT)
610 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
611 else
612 iwe.u.data.flags = IW_ENCODE_DISABLED;
613 iwe.u.data.length = 0;
614 iwe.cmd = SIOCGIWENCODE;
615 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
616
617 /* Add frequency. (short) bss->channel is the frequency in MHz */
618 iwe.u.freq.m = bss->channel;
619 iwe.u.freq.e = 6;
620 iwe.cmd = SIOCGIWFREQ;
621 current_ev =
622 iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
623
624 /* Add quality statistics */
625 iwe.u.qual.level = bss->rssi;
626 iwe.u.qual.noise = noise;
627 /* do a simple SNR for quality */
628 iwe.u.qual.qual = bss->rssi - noise;
629 iwe.cmd = IWEVQUAL;
630 current_ev =
631 iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
632
633 if (priv->wpa) {
634 u8 wpa_ie[MAX_WPA_IE_LEN];
635 char *buf, *p;
636 size_t wpa_ie_len;
637 int i;
638
639 wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
640 if (wpa_ie_len > 0 &&
641 (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
642 p = buf;
643 p += sprintf(p, "wpa_ie=");
644 for (i = 0; i < wpa_ie_len; i++) {
645 p += sprintf(p, "%02x", wpa_ie[i]);
646 }
647 memset(&iwe, 0, sizeof (iwe));
648 iwe.cmd = IWEVCUSTOM;
649 iwe.u.data.length = strlen(buf);
650 current_ev = iwe_stream_add_point(current_ev, end_buf,
651 &iwe, buf);
652 kfree(buf);
653 }
654 }
655 return current_ev;
656}
657
658static int
659prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
660 struct iw_point *dwrq, char *extra)
661{
662 islpci_private *priv = netdev_priv(ndev);
663 int i, rvalue;
664 struct obj_bsslist *bsslist;
665 u32 noise = 0;
666 char *current_ev = extra;
667 union oid_res_t r;
668
669 if (islpci_get_state(priv) < PRV_STATE_INIT) {
670 /* device is not ready, fail gently */
671 dwrq->length = 0;
672 return 0;
673 }
674
675 /* first get the noise value. We will use it to report the link quality */
676 rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
677 noise = r.u;
678
679 /* Ask the device for a list of known bss.
680 * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
681 * The new API, using SIOCGIWSCAN, is only limited by the buffer size.
682 * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes.
683 * Starting with WE-17, the buffer can be as big as needed.
684 * But the device won't repport anything if you change the value
685 * of IWMAX_BSS=24. */
686
687 rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
688 bsslist = r.ptr;
689
690 /* ok now, scan the list and translate its info */
691 for (i = 0; i < (int) bsslist->nr; i++) {
692 current_ev = prism54_translate_bss(ndev, current_ev,
693 extra + dwrq->length,
694 &(bsslist->bsslist[i]),
695 noise);
696#if WIRELESS_EXT > 16
697 /* Check if there is space for one more entry */
698 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
699 /* Ask user space to try again with a bigger buffer */
700 rvalue = -E2BIG;
701 break;
702 }
703#endif /* WIRELESS_EXT > 16 */
704 }
705
706 kfree(bsslist);
707 dwrq->length = (current_ev - extra);
708 dwrq->flags = 0; /* todo */
709
710 return rvalue;
711}
712
713static int
714prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
715 struct iw_point *dwrq, char *extra)
716{
717 islpci_private *priv = netdev_priv(ndev);
718 struct obj_ssid essid;
719
720 memset(essid.octets, 0, 33);
721
722 /* Check if we were asked for `any' */
723 if (dwrq->flags && dwrq->length) {
724 if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
725 return -E2BIG;
726 essid.length = dwrq->length - 1;
727 memcpy(essid.octets, extra, dwrq->length);
728 } else
729 essid.length = 0;
730
731 if (priv->iw_mode != IW_MODE_MONITOR)
732 return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
733
734 /* If in monitor mode, just save to mib */
735 mgt_set(priv, DOT11_OID_SSID, &essid);
736 return 0;
737
738}
739
740static int
741prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
742 struct iw_point *dwrq, char *extra)
743{
744 islpci_private *priv = netdev_priv(ndev);
745 struct obj_ssid *essid;
746 union oid_res_t r;
747 int rvalue;
748
749 rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r);
750 essid = r.ptr;
751
752 if (essid->length) {
753 dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */
754 /* if it is to big, trunk it */
755 dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1);
756 } else {
757 dwrq->flags = 0;
758 dwrq->length = 0;
759 }
760 essid->octets[essid->length] = '\0';
761 memcpy(extra, essid->octets, dwrq->length);
762 kfree(essid);
763
764 return rvalue;
765}
766
767/* Provides no functionality, just completes the ioctl. In essence this is a
768 * just a cosmetic ioctl.
769 */
770static int
771prism54_set_nick(struct net_device *ndev, struct iw_request_info *info,
772 struct iw_point *dwrq, char *extra)
773{
774 islpci_private *priv = netdev_priv(ndev);
775
776 if (dwrq->length > IW_ESSID_MAX_SIZE)
777 return -E2BIG;
778
779 down_write(&priv->mib_sem);
780 memset(priv->nickname, 0, sizeof (priv->nickname));
781 memcpy(priv->nickname, extra, dwrq->length);
782 up_write(&priv->mib_sem);
783
784 return 0;
785}
786
787static int
788prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
789 struct iw_point *dwrq, char *extra)
790{
791 islpci_private *priv = netdev_priv(ndev);
792
793 dwrq->length = 0;
794
795 down_read(&priv->mib_sem);
796 dwrq->length = strlen(priv->nickname) + 1;
797 memcpy(extra, priv->nickname, dwrq->length);
798 up_read(&priv->mib_sem);
799
800 return 0;
801}
802
803/* Set the allowed Bitrates */
804
805static int
806prism54_set_rate(struct net_device *ndev,
807 struct iw_request_info *info,
808 struct iw_param *vwrq, char *extra)
809{
810
811 islpci_private *priv = netdev_priv(ndev);
812 u32 rate, profile;
813 char *data;
814 int ret, i;
815 union oid_res_t r;
816
817 if (vwrq->value == -1) {
818 /* auto mode. No limit. */
819 profile = 1;
820 return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
821 }
822
823 ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
824 if (ret) {
825 kfree(r.ptr);
826 return ret;
827 }
828
829 rate = (u32) (vwrq->value / 500000);
830 data = r.ptr;
831 i = 0;
832
833 while (data[i]) {
834 if (rate && (data[i] == rate)) {
835 break;
836 }
837 if (vwrq->value == i) {
838 break;
839 }
840 data[i] |= 0x80;
841 i++;
842 }
843
844 if (!data[i]) {
845 kfree(r.ptr);
846 return -EINVAL;
847 }
848
849 data[i] |= 0x80;
850 data[i + 1] = 0;
851
852 /* Now, check if we want a fixed or auto value */
853 if (vwrq->fixed) {
854 data[0] = data[i];
855 data[1] = 0;
856 }
857
858/*
859 i = 0;
860 printk("prism54 rate: ");
861 while(data[i]) {
862 printk("%u ", data[i]);
863 i++;
864 }
865 printk("0\n");
866*/
867 profile = -1;
868 ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
869 ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
870 ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
871
872 kfree(r.ptr);
873
874 return ret;
875}
876
877/* Get the current bit rate */
878static int
879prism54_get_rate(struct net_device *ndev,
880 struct iw_request_info *info,
881 struct iw_param *vwrq, char *extra)
882{
883 islpci_private *priv = netdev_priv(ndev);
884 int rvalue;
885 char *data;
886 union oid_res_t r;
887
888 /* Get the current bit rate */
889 if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
890 return rvalue;
891 vwrq->value = r.u * 500000;
892
893 /* request the device for the enabled rates */
894 rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r);
895 if (rvalue) {
896 kfree(r.ptr);
897 return rvalue;
898 }
899 data = r.ptr;
900 vwrq->fixed = (data[0] != 0) && (data[1] == 0);
901 kfree(r.ptr);
902
903 return 0;
904}
905
906static int
907prism54_set_rts(struct net_device *ndev, struct iw_request_info *info,
908 struct iw_param *vwrq, char *extra)
909{
910 islpci_private *priv = netdev_priv(ndev);
911
912 return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value);
913}
914
915static int
916prism54_get_rts(struct net_device *ndev, struct iw_request_info *info,
917 struct iw_param *vwrq, char *extra)
918{
919 islpci_private *priv = netdev_priv(ndev);
920 union oid_res_t r;
921 int rvalue;
922
923 /* get the rts threshold */
924 rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r);
925 vwrq->value = r.u;
926
927 return rvalue;
928}
929
930static int
931prism54_set_frag(struct net_device *ndev, struct iw_request_info *info,
932 struct iw_param *vwrq, char *extra)
933{
934 islpci_private *priv = netdev_priv(ndev);
935
936 return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value);
937}
938
939static int
940prism54_get_frag(struct net_device *ndev, struct iw_request_info *info,
941 struct iw_param *vwrq, char *extra)
942{
943 islpci_private *priv = netdev_priv(ndev);
944 union oid_res_t r;
945 int rvalue;
946
947 rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r);
948 vwrq->value = r.u;
949
950 return rvalue;
951}
952
953/* Here we have (min,max) = max retries for (small frames, big frames). Where
954 * big frame <=> bigger than the rts threshold
955 * small frame <=> smaller than the rts threshold
956 * This is not really the behavior expected by the wireless tool but it seems
957 * to be a common behavior in other drivers.
958 */
959
960static int
961prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
962 struct iw_param *vwrq, char *extra)
963{
964 islpci_private *priv = netdev_priv(ndev);
965 u32 slimit = 0, llimit = 0; /* short and long limit */
966 u32 lifetime = 0;
967 int rvalue = 0;
968
969 if (vwrq->disabled)
970 /* we cannot disable this feature */
971 return -EINVAL;
972
973 if (vwrq->flags & IW_RETRY_LIMIT) {
974 if (vwrq->flags & IW_RETRY_MIN)
975 slimit = vwrq->value;
976 else if (vwrq->flags & IW_RETRY_MAX)
977 llimit = vwrq->value;
978 else {
979 /* we are asked to set both */
980 slimit = vwrq->value;
981 llimit = vwrq->value;
982 }
983 }
984 if (vwrq->flags & IW_RETRY_LIFETIME)
985 /* Wireless tools use us unit while the device uses 1024 us unit */
986 lifetime = vwrq->value / 1024;
987
988 /* now set what is requested */
989 if (slimit)
990 rvalue =
991 mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
992 if (llimit)
993 rvalue |=
994 mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
995 if (lifetime)
996 rvalue |=
997 mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
998 &lifetime);
999 return rvalue;
1000}
1001
1002static int
1003prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
1004 struct iw_param *vwrq, char *extra)
1005{
1006 islpci_private *priv = netdev_priv(ndev);
1007 union oid_res_t r;
1008 int rvalue = 0;
1009 vwrq->disabled = 0; /* It cannot be disabled */
1010
1011 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1012 /* we are asked for the life time */
1013 rvalue =
1014 mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
1015 vwrq->value = r.u * 1024;
1016 vwrq->flags = IW_RETRY_LIFETIME;
1017 } else if ((vwrq->flags & IW_RETRY_MAX)) {
1018 /* we are asked for the long retry limit */
1019 rvalue |=
1020 mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
1021 vwrq->value = r.u;
1022 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
1023 } else {
1024 /* default. get the short retry limit */
1025 rvalue |=
1026 mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
1027 vwrq->value = r.u;
1028 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
1029 }
1030
1031 return rvalue;
1032}
1033
1034static int
1035prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
1036 struct iw_point *dwrq, char *extra)
1037{
1038 islpci_private *priv = netdev_priv(ndev);
1039 int rvalue = 0, force = 0;
1040 int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
1041 union oid_res_t r;
1042
1043 /* with the new API, it's impossible to get a NULL pointer.
1044 * New version of iwconfig set the IW_ENCODE_NOKEY flag
1045 * when no key is given, but older versions don't. */
1046
1047 if (dwrq->length > 0) {
1048 /* we have a key to set */
1049 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1050 int current_index;
1051 struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
1052
1053 /* get the current key index */
1054 rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1055 current_index = r.u;
1056 /* Verify that the key is not marked as invalid */
1057 if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
1058 key.length = dwrq->length > sizeof (key.key) ?
1059 sizeof (key.key) : dwrq->length;
1060 memcpy(key.key, extra, key.length);
1061 if (key.length == 32)
1062 /* we want WPA-PSK */
1063 key.type = DOT11_PRIV_TKIP;
1064 if ((index < 0) || (index > 3))
1065 /* no index provided use the current one */
1066 index = current_index;
1067
1068 /* now send the key to the card */
1069 rvalue |=
1070 mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
1071 &key);
1072 }
1073 /*
1074 * If a valid key is set, encryption should be enabled
1075 * (user may turn it off later).
1076 * This is also how "iwconfig ethX key on" works
1077 */
1078 if ((index == current_index) && (key.length > 0))
1079 force = 1;
1080 } else {
1081 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1082 if ((index >= 0) && (index <= 3)) {
1083 /* we want to set the key index */
1084 rvalue |=
1085 mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
1086 &index);
1087 } else {
1088 if (!dwrq->flags & IW_ENCODE_MODE) {
1089 /* we cannot do anything. Complain. */
1090 return -EINVAL;
1091 }
1092 }
1093 }
1094 /* now read the flags */
1095 if (dwrq->flags & IW_ENCODE_DISABLED) {
1096 /* Encoding disabled,
1097 * authen = DOT11_AUTH_OS;
1098 * invoke = 0;
1099 * exunencrypt = 0; */
1100 }
1101 if (dwrq->flags & IW_ENCODE_OPEN)
1102 /* Encode but accept non-encoded packets. No auth */
1103 invoke = 1;
1104 if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) {
1105 /* Refuse non-encoded packets. Auth */
1106 authen = DOT11_AUTH_BOTH;
1107 invoke = 1;
1108 exunencrypt = 1;
1109 }
1110 /* do the change if requested */
1111 if ((dwrq->flags & IW_ENCODE_MODE) || force) {
1112 rvalue |=
1113 mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
1114 rvalue |=
1115 mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
1116 rvalue |=
1117 mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
1118 &exunencrypt);
1119 }
1120 return rvalue;
1121}
1122
1123static int
1124prism54_get_encode(struct net_device *ndev, struct iw_request_info *info,
1125 struct iw_point *dwrq, char *extra)
1126{
1127 islpci_private *priv = netdev_priv(ndev);
1128 struct obj_key *key;
1129 u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1130 u32 authen = 0, invoke = 0, exunencrypt = 0;
1131 int rvalue;
1132 union oid_res_t r;
1133
1134 /* first get the flags */
1135 rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1136 authen = r.u;
1137 rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1138 invoke = r.u;
1139 rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1140 exunencrypt = r.u;
1141
1142 if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt)
1143 dwrq->flags = IW_ENCODE_RESTRICTED;
1144 else if ((authen == DOT11_AUTH_OS) && !exunencrypt) {
1145 if (invoke)
1146 dwrq->flags = IW_ENCODE_OPEN;
1147 else
1148 dwrq->flags = IW_ENCODE_DISABLED;
1149 } else
1150 /* The card should not work in this state */
1151 dwrq->flags = 0;
1152
1153 /* get the current device key index */
1154 rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1155 devindex = r.u;
1156 /* Now get the key, return it */
1157 if ((index < 0) || (index > 3))
1158 /* no index provided, use the current one */
1159 index = devindex;
1160 rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r);
1161 key = r.ptr;
1162 dwrq->length = key->length;
1163 memcpy(extra, key->key, dwrq->length);
1164 kfree(key);
1165 /* return the used key index */
1166 dwrq->flags |= devindex + 1;
1167
1168 return rvalue;
1169}
1170
1171static int
1172prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info,
1173 struct iw_param *vwrq, char *extra)
1174{
1175 islpci_private *priv = netdev_priv(ndev);
1176 union oid_res_t r;
1177 int rvalue;
1178
1179 rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r);
1180 /* intersil firmware operates in 0.25 dBm (1/4 dBm) */
1181 vwrq->value = (s32) r.u / 4;
1182 vwrq->fixed = 1;
1183 /* radio is not turned of
1184 * btw: how is possible to turn off only the radio
1185 */
1186 vwrq->disabled = 0;
1187
1188 return rvalue;
1189}
1190
1191static int
1192prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
1193 struct iw_param *vwrq, char *extra)
1194{
1195 islpci_private *priv = netdev_priv(ndev);
1196 s32 u = vwrq->value;
1197
1198 /* intersil firmware operates in 0.25 dBm (1/4) */
1199 u *= 4;
1200 if (vwrq->disabled) {
1201 /* don't know how to disable radio */
1202 printk(KERN_DEBUG
1203 "%s: %s() disabling radio is not yet supported.\n",
1204 priv->ndev->name, __FUNCTION__);
1205 return -ENOTSUPP;
1206 } else if (vwrq->fixed)
1207 /* currently only fixed value is supported */
1208 return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u);
1209 else {
1210 printk(KERN_DEBUG
1211 "%s: %s() auto power will be implemented later.\n",
1212 priv->ndev->name, __FUNCTION__);
1213 return -ENOTSUPP;
1214 }
1215}
1216
1217static int
1218prism54_reset(struct net_device *ndev, struct iw_request_info *info,
1219 __u32 * uwrq, char *extra)
1220{
1221 islpci_reset(netdev_priv(ndev), 0);
1222
1223 return 0;
1224}
1225
1226static int
1227prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
1228 struct iw_point *dwrq, char *extra)
1229{
1230 union oid_res_t r;
1231 int rvalue;
1232 enum oid_num_t n = dwrq->flags;
1233
1234 rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r);
1235 dwrq->length = mgt_response_to_str(n, &r, extra);
1236 if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
1237 kfree(r.ptr);
1238 return rvalue;
1239}
1240
1241static int
1242prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
1243 __u32 * uwrq, char *extra)
1244{
1245 u32 oid = uwrq[0], u = uwrq[1];
1246
1247 return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
1248}
1249
1250static int
1251prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
1252 struct iw_point *dwrq, char *extra)
1253{
1254 u32 oid = dwrq->flags;
1255
1256 return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra);
1257}
1258
1259void
1260prism54_acl_init(struct islpci_acl *acl)
1261{
1262 sema_init(&acl->sem, 1);
1263 INIT_LIST_HEAD(&acl->mac_list);
1264 acl->size = 0;
1265 acl->policy = MAC_POLICY_OPEN;
1266}
1267
1268static void
1269prism54_clear_mac(struct islpci_acl *acl)
1270{
1271 struct list_head *ptr, *next;
1272 struct mac_entry *entry;
1273
1274 if (down_interruptible(&acl->sem))
1275 return;
1276
1277 if (acl->size == 0) {
1278 up(&acl->sem);
1279 return;
1280 }
1281
1282 for (ptr = acl->mac_list.next, next = ptr->next;
1283 ptr != &acl->mac_list; ptr = next, next = ptr->next) {
1284 entry = list_entry(ptr, struct mac_entry, _list);
1285 list_del(ptr);
1286 kfree(entry);
1287 }
1288 acl->size = 0;
1289 up(&acl->sem);
1290}
1291
1292void
1293prism54_acl_clean(struct islpci_acl *acl)
1294{
1295 prism54_clear_mac(acl);
1296}
1297
1298static int
1299prism54_add_mac(struct net_device *ndev, struct iw_request_info *info,
1300 struct sockaddr *awrq, char *extra)
1301{
1302 islpci_private *priv = netdev_priv(ndev);
1303 struct islpci_acl *acl = &priv->acl;
1304 struct mac_entry *entry;
1305 struct sockaddr *addr = (struct sockaddr *) extra;
1306
1307 if (addr->sa_family != ARPHRD_ETHER)
1308 return -EOPNOTSUPP;
1309
1310 entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL);
1311 if (entry == NULL)
1312 return -ENOMEM;
1313
1314 memcpy(entry->addr, addr->sa_data, ETH_ALEN);
1315
1316 if (down_interruptible(&acl->sem)) {
1317 kfree(entry);
1318 return -ERESTARTSYS;
1319 }
1320 list_add_tail(&entry->_list, &acl->mac_list);
1321 acl->size++;
1322 up(&acl->sem);
1323
1324 return 0;
1325}
1326
1327static int
1328prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
1329 struct sockaddr *awrq, char *extra)
1330{
1331 islpci_private *priv = netdev_priv(ndev);
1332 struct islpci_acl *acl = &priv->acl;
1333 struct mac_entry *entry;
1334 struct list_head *ptr;
1335 struct sockaddr *addr = (struct sockaddr *) extra;
1336
1337 if (addr->sa_family != ARPHRD_ETHER)
1338 return -EOPNOTSUPP;
1339
1340 if (down_interruptible(&acl->sem))
1341 return -ERESTARTSYS;
1342 for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
1343 entry = list_entry(ptr, struct mac_entry, _list);
1344
1345 if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
1346 list_del(ptr);
1347 acl->size--;
1348 kfree(entry);
1349 up(&acl->sem);
1350 return 0;
1351 }
1352 }
1353 up(&acl->sem);
1354 return -EINVAL;
1355}
1356
1357static int
1358prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
1359 struct iw_point *dwrq, char *extra)
1360{
1361 islpci_private *priv = netdev_priv(ndev);
1362 struct islpci_acl *acl = &priv->acl;
1363 struct mac_entry *entry;
1364 struct list_head *ptr;
1365 struct sockaddr *dst = (struct sockaddr *) extra;
1366
1367 dwrq->length = 0;
1368
1369 if (down_interruptible(&acl->sem))
1370 return -ERESTARTSYS;
1371
1372 for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
1373 entry = list_entry(ptr, struct mac_entry, _list);
1374
1375 memcpy(dst->sa_data, entry->addr, ETH_ALEN);
1376 dst->sa_family = ARPHRD_ETHER;
1377 dwrq->length++;
1378 dst++;
1379 }
1380 up(&acl->sem);
1381 return 0;
1382}
1383
1384/* Setting policy also clears the MAC acl, even if we don't change the defaut
1385 * policy
1386 */
1387
1388static int
1389prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
1390 __u32 * uwrq, char *extra)
1391{
1392 islpci_private *priv = netdev_priv(ndev);
1393 struct islpci_acl *acl = &priv->acl;
1394 u32 mlmeautolevel;
1395
1396 prism54_clear_mac(acl);
1397
1398 if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT))
1399 return -EINVAL;
1400
1401 down_write(&priv->mib_sem);
1402
1403 acl->policy = *uwrq;
1404
1405 /* the ACL code needs an intermediate mlmeautolevel */
1406 if ((priv->iw_mode == IW_MODE_MASTER) &&
1407 (acl->policy != MAC_POLICY_OPEN))
1408 mlmeautolevel = DOT11_MLME_INTERMEDIATE;
1409 else
1410 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
1411 if (priv->wpa)
1412 mlmeautolevel = DOT11_MLME_EXTENDED;
1413 mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
1414 /* restart the card with our new policy */
1415 if (mgt_commit(priv)) {
1416 up_write(&priv->mib_sem);
1417 return -EIO;
1418 }
1419 up_write(&priv->mib_sem);
1420
1421 return 0;
1422}
1423
1424static int
1425prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
1426 __u32 * uwrq, char *extra)
1427{
1428 islpci_private *priv = netdev_priv(ndev);
1429 struct islpci_acl *acl = &priv->acl;
1430
1431 *uwrq = acl->policy;
1432
1433 return 0;
1434}
1435
1436/* Return 1 only if client should be accepted. */
1437
1438static int
1439prism54_mac_accept(struct islpci_acl *acl, char *mac)
1440{
1441 struct list_head *ptr;
1442 struct mac_entry *entry;
1443 int res = 0;
1444
1445 if (down_interruptible(&acl->sem))
1446 return -ERESTARTSYS;
1447
1448 if (acl->policy == MAC_POLICY_OPEN) {
1449 up(&acl->sem);
1450 return 1;
1451 }
1452
1453 for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
1454 entry = list_entry(ptr, struct mac_entry, _list);
1455 if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
1456 res = 1;
1457 break;
1458 }
1459 }
1460 res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;
1461 up(&acl->sem);
1462
1463 return res;
1464}
1465
1466static int
1467prism54_kick_all(struct net_device *ndev, struct iw_request_info *info,
1468 struct iw_point *dwrq, char *extra)
1469{
1470 struct obj_mlme *mlme;
1471 int rvalue;
1472
1473 mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
1474 if (mlme == NULL)
1475 return -ENOMEM;
1476
1477 /* Tell the card to kick every client */
1478 mlme->id = 0;
1479 rvalue =
1480 mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
1481 kfree(mlme);
1482
1483 return rvalue;
1484}
1485
1486static int
1487prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,
1488 struct sockaddr *awrq, char *extra)
1489{
1490 struct obj_mlme *mlme;
1491 struct sockaddr *addr = (struct sockaddr *) extra;
1492 int rvalue;
1493
1494 if (addr->sa_family != ARPHRD_ETHER)
1495 return -EOPNOTSUPP;
1496
1497 mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
1498 if (mlme == NULL)
1499 return -ENOMEM;
1500
1501 /* Tell the card to only kick the corresponding bastard */
1502 memcpy(mlme->address, addr->sa_data, ETH_ALEN);
1503 mlme->id = -1;
1504 rvalue =
1505 mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
1506
1507 kfree(mlme);
1508
1509 return rvalue;
1510}
1511
1512/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */
1513
1514static void
1515format_event(islpci_private *priv, char *dest, const char *str,
1516 const struct obj_mlme *mlme, u16 *length, int error)
1517{
1518 const u8 *a = mlme->address;
1519 int n = snprintf(dest, IW_CUSTOM_MAX,
1520 "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",
1521 str,
1522 ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
1523 a[0], a[1], a[2], a[3], a[4], a[5],
1524 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
1525 : ""), mlme->code);
1526 BUG_ON(n > IW_CUSTOM_MAX);
1527 *length = n;
1528}
1529
1530static void
1531send_formatted_event(islpci_private *priv, const char *str,
1532 const struct obj_mlme *mlme, int error)
1533{
1534 union iwreq_data wrqu;
1535 char *memptr;
1536
1537 memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
1538 if (!memptr)
1539 return;
1540 wrqu.data.pointer = memptr;
1541 wrqu.data.length = 0;
1542 format_event(priv, memptr, str, mlme, &wrqu.data.length,
1543 error);
1544 wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
1545 kfree(memptr);
1546}
1547
1548static void
1549send_simple_event(islpci_private *priv, const char *str)
1550{
1551 union iwreq_data wrqu;
1552 char *memptr;
1553 int n = strlen(str);
1554
1555 memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
1556 if (!memptr)
1557 return;
1558 BUG_ON(n > IW_CUSTOM_MAX);
1559 wrqu.data.pointer = memptr;
1560 wrqu.data.length = n;
1561 strcpy(memptr, str);
1562 wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
1563 kfree(memptr);
1564}
1565
1566static void
1567link_changed(struct net_device *ndev, u32 bitrate)
1568{
1569 islpci_private *priv = netdev_priv(ndev);
1570
1571 if (bitrate) {
1572 if (priv->iw_mode == IW_MODE_INFRA) {
1573 union iwreq_data uwrq;
1574 prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
1575 NULL);
1576 wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
1577 } else
1578 send_simple_event(netdev_priv(ndev),
1579 "Link established");
1580 } else
1581 send_simple_event(netdev_priv(ndev), "Link lost");
1582}
1583
1584/* Beacon/ProbeResp payload header */
1585struct ieee80211_beacon_phdr {
1586 u8 timestamp[8];
1587 u16 beacon_int;
1588 u16 capab_info;
1589} __attribute__ ((packed));
1590
1591#define WLAN_EID_GENERIC 0xdd
1592static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
1593
1594#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
1595#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
1596
1597static void
1598prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
1599 u8 *wpa_ie, size_t wpa_ie_len)
1600{
1601 struct list_head *ptr;
1602 struct islpci_bss_wpa_ie *bss = NULL;
1603
1604 if (wpa_ie_len > MAX_WPA_IE_LEN)
1605 wpa_ie_len = MAX_WPA_IE_LEN;
1606
1607 if (down_interruptible(&priv->wpa_sem))
1608 return;
1609
1610 /* try to use existing entry */
1611 list_for_each(ptr, &priv->bss_wpa_list) {
1612 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
1613 if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
1614 list_move(&bss->list, &priv->bss_wpa_list);
1615 break;
1616 }
1617 bss = NULL;
1618 }
1619
1620 if (bss == NULL) {
1621 /* add a new BSS entry; if max number of entries is already
1622 * reached, replace the least recently updated */
1623 if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {
1624 bss = list_entry(priv->bss_wpa_list.prev,
1625 struct islpci_bss_wpa_ie, list);
1626 list_del(&bss->list);
1627 } else {
1628 bss = kmalloc(sizeof (*bss), GFP_ATOMIC);
1629 if (bss != NULL) {
1630 priv->num_bss_wpa++;
1631 memset(bss, 0, sizeof (*bss));
1632 }
1633 }
1634 if (bss != NULL) {
1635 memcpy(bss->bssid, bssid, ETH_ALEN);
1636 list_add(&bss->list, &priv->bss_wpa_list);
1637 }
1638 }
1639
1640 if (bss != NULL) {
1641 memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);
1642 bss->wpa_ie_len = wpa_ie_len;
1643 bss->last_update = jiffies;
1644 } else {
1645 printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
1646 "\n", MAC2STR(bssid));
1647 }
1648
1649 /* expire old entries from WPA list */
1650 while (priv->num_bss_wpa > 0) {
1651 bss = list_entry(priv->bss_wpa_list.prev,
1652 struct islpci_bss_wpa_ie, list);
1653 if (!time_after(jiffies, bss->last_update + 60 * HZ))
1654 break;
1655
1656 list_del(&bss->list);
1657 priv->num_bss_wpa--;
1658 kfree(bss);
1659 }
1660
1661 up(&priv->wpa_sem);
1662}
1663
1664static size_t
1665prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
1666{
1667 struct list_head *ptr;
1668 struct islpci_bss_wpa_ie *bss = NULL;
1669 size_t len = 0;
1670
1671 if (down_interruptible(&priv->wpa_sem))
1672 return 0;
1673
1674 list_for_each(ptr, &priv->bss_wpa_list) {
1675 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
1676 if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
1677 break;
1678 bss = NULL;
1679 }
1680 if (bss) {
1681 len = bss->wpa_ie_len;
1682 memcpy(wpa_ie, bss->wpa_ie, len);
1683 }
1684 up(&priv->wpa_sem);
1685
1686 return len;
1687}
1688
1689void
1690prism54_wpa_ie_init(islpci_private *priv)
1691{
1692 INIT_LIST_HEAD(&priv->bss_wpa_list);
1693 sema_init(&priv->wpa_sem, 1);
1694}
1695
1696void
1697prism54_wpa_ie_clean(islpci_private *priv)
1698{
1699 struct list_head *ptr, *n;
1700
1701 list_for_each_safe(ptr, n, &priv->bss_wpa_list) {
1702 struct islpci_bss_wpa_ie *bss;
1703 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
1704 kfree(bss);
1705 }
1706}
1707
1708static void
1709prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
1710 u8 *payload, size_t len)
1711{
1712 struct ieee80211_beacon_phdr *hdr;
1713 u8 *pos, *end;
1714
1715 if (!priv->wpa)
1716 return;
1717
1718 hdr = (struct ieee80211_beacon_phdr *) payload;
1719 pos = (u8 *) (hdr + 1);
1720 end = payload + len;
1721 while (pos < end) {
1722 if (pos + 2 + pos[1] > end) {
1723 printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
1724 "for " MACSTR "\n", MAC2STR(addr));
1725 return;
1726 }
1727 if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
1728 memcmp(pos + 2, wpa_oid, 4) == 0) {
1729 prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
1730 return;
1731 }
1732 pos += 2 + pos[1];
1733 }
1734}
1735
1736static void
1737handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
1738{
1739 if (((mlme->state == DOT11_STATE_AUTHING) ||
1740 (mlme->state == DOT11_STATE_ASSOCING))
1741 && mgt_mlme_answer(priv)) {
1742 /* Someone is requesting auth and we must respond. Just send back
1743 * the trap with error code set accordingly.
1744 */
1745 mlme->code = prism54_mac_accept(&priv->acl,
1746 mlme->address) ? 0 : 1;
1747 mgt_set_request(priv, oid, 0, mlme);
1748 }
1749}
1750
1751static int
1752prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
1753 char *data)
1754{
1755 struct obj_mlme *mlme = (struct obj_mlme *) data;
1756 struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
1757 struct obj_mlmeex *confirm;
1758 u8 wpa_ie[MAX_WPA_IE_LEN];
1759 int wpa_ie_len;
1760 size_t len = 0; /* u16, better? */
1761 u8 *payload = NULL, *pos = NULL;
1762 int ret;
1763
1764 /* I think all trapable objects are listed here.
1765 * Some oids have a EX version. The difference is that they are emitted
1766 * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)
1767 * with more info.
1768 * The few events already defined by the wireless tools are not really
1769 * suited. We use the more flexible custom event facility.
1770 */
1771
1772 if (oid >= DOT11_OID_BEACON) {
1773 len = mlmeex->size;
1774 payload = pos = mlmeex->data;
1775 }
1776
1777 /* I fear prism54_process_bss_data won't work with big endian data */
1778 if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
1779 prism54_process_bss_data(priv, oid, mlmeex->address,
1780 payload, len);
1781
1782 mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
1783
1784 switch (oid) {
1785
1786 case GEN_OID_LINKSTATE:
1787 link_changed(priv->ndev, (u32) *data);
1788 break;
1789
1790 case DOT11_OID_MICFAILURE:
1791 send_simple_event(priv, "Mic failure");
1792 break;
1793
1794 case DOT11_OID_DEAUTHENTICATE:
1795 send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
1796 break;
1797
1798 case DOT11_OID_AUTHENTICATE:
1799 handle_request(priv, mlme, oid);
1800 send_formatted_event(priv, "Authenticate request", mlme, 1);
1801 break;
1802
1803 case DOT11_OID_DISASSOCIATE:
1804 send_formatted_event(priv, "Disassociate request", mlme, 0);
1805 break;
1806
1807 case DOT11_OID_ASSOCIATE:
1808 handle_request(priv, mlme, oid);
1809 send_formatted_event(priv, "Associate request", mlme, 1);
1810 break;
1811
1812 case DOT11_OID_REASSOCIATE:
1813 handle_request(priv, mlme, oid);
1814 send_formatted_event(priv, "ReAssociate request", mlme, 1);
1815 break;
1816
1817 case DOT11_OID_BEACON:
1818 send_formatted_event(priv,
1819 "Received a beacon from an unkown AP",
1820 mlme, 0);
1821 break;
1822
1823 case DOT11_OID_PROBE:
1824 /* we received a probe from a client. */
1825 send_formatted_event(priv, "Received a probe from client", mlme,
1826 0);
1827 break;
1828
1829 /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
1830 * is backward compatible layout-wise with "struct obj_mlme".
1831 */
1832
1833 case DOT11_OID_DEAUTHENTICATEEX:
1834 send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
1835 break;
1836
1837 case DOT11_OID_AUTHENTICATEEX:
1838 handle_request(priv, mlme, oid);
1839 send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
1840
1841 if (priv->iw_mode != IW_MODE_MASTER
1842 && mlmeex->state != DOT11_STATE_AUTHING)
1843 break;
1844
1845 confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
1846
1847 if (!confirm)
1848 break;
1849
1850 memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
1851 printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
1852 mlmeex->address[0],
1853 mlmeex->address[1],
1854 mlmeex->address[2],
1855 mlmeex->address[3],
1856 mlmeex->address[4],
1857 mlmeex->address[5]
1858 );
1859 confirm->id = -1; /* or mlmeex->id ? */
1860 confirm->state = 0; /* not used */
1861 confirm->code = 0;
1862 confirm->size = 6;
1863 confirm->data[0] = 0x00;
1864 confirm->data[1] = 0x00;
1865 confirm->data[2] = 0x02;
1866 confirm->data[3] = 0x00;
1867 confirm->data[4] = 0x00;
1868 confirm->data[5] = 0x00;
1869
1870 ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
1871
1872 kfree(confirm);
1873 if (ret)
1874 return ret;
1875 break;
1876
1877 case DOT11_OID_DISASSOCIATEEX:
1878 send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
1879 break;
1880
1881 case DOT11_OID_ASSOCIATEEX:
1882 handle_request(priv, mlme, oid);
1883 send_formatted_event(priv, "Associate request (ex)", mlme, 1);
1884
1885 if (priv->iw_mode != IW_MODE_MASTER
1886 && mlmeex->state != DOT11_STATE_AUTHING)
1887 break;
1888
1889 confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
1890
1891 if (!confirm)
1892 break;
1893
1894 memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
1895
1896 confirm->id = ((struct obj_mlmeex *)mlme)->id;
1897 confirm->state = 0; /* not used */
1898 confirm->code = 0;
1899
1900 wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
1901
1902 if (!wpa_ie_len) {
1903 printk(KERN_DEBUG "No WPA IE found from "
1904 "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
1905 mlmeex->address[0],
1906 mlmeex->address[1],
1907 mlmeex->address[2],
1908 mlmeex->address[3],
1909 mlmeex->address[4],
1910 mlmeex->address[5]
1911 );
1912 kfree(confirm);
1913 break;
1914 }
1915
1916 confirm->size = wpa_ie_len;
1917 memcpy(&confirm->data, wpa_ie, wpa_ie_len);
1918
1919 mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
1920
1921 kfree(confirm);
1922
1923 break;
1924
1925 case DOT11_OID_REASSOCIATEEX:
1926 handle_request(priv, mlme, oid);
1927 send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
1928
1929 if (priv->iw_mode != IW_MODE_MASTER
1930 && mlmeex->state != DOT11_STATE_ASSOCING)
1931 break;
1932
1933 confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
1934
1935 if (!confirm)
1936 break;
1937
1938 memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
1939
1940 confirm->id = mlmeex->id;
1941 confirm->state = 0; /* not used */
1942 confirm->code = 0;
1943
1944 wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
1945
1946 if (!wpa_ie_len) {
1947 printk(KERN_DEBUG "No WPA IE found from "
1948 "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
1949 mlmeex->address[0],
1950 mlmeex->address[1],
1951 mlmeex->address[2],
1952 mlmeex->address[3],
1953 mlmeex->address[4],
1954 mlmeex->address[5]
1955 );
1956 kfree(confirm);
1957 break;
1958 }
1959
1960 confirm->size = wpa_ie_len;
1961 memcpy(&confirm->data, wpa_ie, wpa_ie_len);
1962
1963 mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
1964
1965 kfree(confirm);
1966
1967 break;
1968
1969 default:
1970 return -EINVAL;
1971 }
1972
1973 return 0;
1974}
1975
1976/*
1977 * Process a device trap. This is called via schedule_work(), outside of
1978 * interrupt context, no locks held.
1979 */
1980void
1981prism54_process_trap(void *data)
1982{
1983 struct islpci_mgmtframe *frame = data;
1984 struct net_device *ndev = frame->ndev;
1985 enum oid_num_t n = mgt_oidtonum(frame->header->oid);
1986
1987 if (n != OID_NUM_LAST)
1988 prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
1989 islpci_mgt_release(frame);
1990}
1991
1992int
1993prism54_set_mac_address(struct net_device *ndev, void *addr)
1994{
1995 islpci_private *priv = netdev_priv(ndev);
1996 int ret;
1997
1998 if (ndev->addr_len != 6)
1999 return -EINVAL;
2000 ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0,
2001 &((struct sockaddr *) addr)->sa_data);
2002 if (!ret)
2003 memcpy(priv->ndev->dev_addr,
2004 &((struct sockaddr *) addr)->sa_data, 6);
2005
2006 return ret;
2007}
2008
2009/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
2010 * support. This is to be replaced with Linux wireless extensions once they
2011 * get WPA support. */
2012
2013/* Note II: please leave all this together as it will be easier to remove later,
2014 * once wireless extensions add WPA support -mcgrof */
2015
2016/* PRISM54_HOSTAPD ioctl() cmd: */
2017enum {
2018 PRISM2_SET_ENCRYPTION = 6,
2019 PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
2020 PRISM2_HOSTAPD_MLME = 13,
2021 PRISM2_HOSTAPD_SCAN_REQ = 14,
2022};
2023
2024#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
2025#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
2026#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
2027
2028#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
2029#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
2030((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
2031
2032/* Maximum length for algorithm names (-1 for nul termination)
2033 * used in ioctl() */
2034#define HOSTAP_CRYPT_ALG_NAME_LEN 16
2035
2036struct prism2_hostapd_param {
2037 u32 cmd;
2038 u8 sta_addr[ETH_ALEN];
2039 union {
2040 struct {
2041 u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
2042 u32 flags;
2043 u32 err;
2044 u8 idx;
2045 u8 seq[8]; /* sequence counter (set: RX, get: TX) */
2046 u16 key_len;
2047 u8 key[0];
2048 } crypt;
2049 struct {
2050 u8 len;
2051 u8 data[0];
2052 } generic_elem;
2053 struct {
2054#define MLME_STA_DEAUTH 0
2055#define MLME_STA_DISASSOC 1
2056 u16 cmd;
2057 u16 reason_code;
2058 } mlme;
2059 struct {
2060 u8 ssid_len;
2061 u8 ssid[32];
2062 } scan_req;
2063 } u;
2064};
2065
2066
2067static int
2068prism2_ioctl_set_encryption(struct net_device *dev,
2069 struct prism2_hostapd_param *param,
2070 int param_len)
2071{
2072 islpci_private *priv = netdev_priv(dev);
2073 int rvalue = 0, force = 0;
2074 int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
2075 union oid_res_t r;
2076
2077 /* with the new API, it's impossible to get a NULL pointer.
2078 * New version of iwconfig set the IW_ENCODE_NOKEY flag
2079 * when no key is given, but older versions don't. */
2080
2081 if (param->u.crypt.key_len > 0) {
2082 /* we have a key to set */
2083 int index = param->u.crypt.idx;
2084 int current_index;
2085 struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
2086
2087 /* get the current key index */
2088 rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
2089 current_index = r.u;
2090 /* Verify that the key is not marked as invalid */
2091 if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
2092 key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
2093 sizeof (param->u.crypt.key) : param->u.crypt.key_len;
2094 memcpy(key.key, param->u.crypt.key, key.length);
2095 if (key.length == 32)
2096 /* we want WPA-PSK */
2097 key.type = DOT11_PRIV_TKIP;
2098 if ((index < 0) || (index > 3))
2099 /* no index provided use the current one */
2100 index = current_index;
2101
2102 /* now send the key to the card */
2103 rvalue |=
2104 mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
2105 &key);
2106 }
2107 /*
2108 * If a valid key is set, encryption should be enabled
2109 * (user may turn it off later).
2110 * This is also how "iwconfig ethX key on" works
2111 */
2112 if ((index == current_index) && (key.length > 0))
2113 force = 1;
2114 } else {
2115 int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
2116 if ((index >= 0) && (index <= 3)) {
2117 /* we want to set the key index */
2118 rvalue |=
2119 mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
2120 &index);
2121 } else {
2122 if (!param->u.crypt.flags & IW_ENCODE_MODE) {
2123 /* we cannot do anything. Complain. */
2124 return -EINVAL;
2125 }
2126 }
2127 }
2128 /* now read the flags */
2129 if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
2130 /* Encoding disabled,
2131 * authen = DOT11_AUTH_OS;
2132 * invoke = 0;
2133 * exunencrypt = 0; */
2134 }
2135 if (param->u.crypt.flags & IW_ENCODE_OPEN)
2136 /* Encode but accept non-encoded packets. No auth */
2137 invoke = 1;
2138 if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
2139 /* Refuse non-encoded packets. Auth */
2140 authen = DOT11_AUTH_BOTH;
2141 invoke = 1;
2142 exunencrypt = 1;
2143 }
2144 /* do the change if requested */
2145 if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
2146 rvalue |=
2147 mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
2148 rvalue |=
2149 mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
2150 rvalue |=
2151 mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
2152 &exunencrypt);
2153 }
2154 return rvalue;
2155}
2156
2157static int
2158prism2_ioctl_set_generic_element(struct net_device *ndev,
2159 struct prism2_hostapd_param *param,
2160 int param_len)
2161{
2162 islpci_private *priv = netdev_priv(ndev);
2163 int max_len, len, alen, ret=0;
2164 struct obj_attachment *attach;
2165
2166 len = param->u.generic_elem.len;
2167 max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
2168 if (max_len < 0 || max_len < len)
2169 return -EINVAL;
2170
2171 alen = sizeof(*attach) + len;
2172 attach = kmalloc(alen, GFP_KERNEL);
2173 if (attach == NULL)
2174 return -ENOMEM;
2175
2176 memset(attach, 0, alen);
2177#define WLAN_FC_TYPE_MGMT 0
2178#define WLAN_FC_STYPE_ASSOC_REQ 0
2179#define WLAN_FC_STYPE_REASSOC_REQ 2
2180
2181 /* Note: endianness is covered by mgt_set_varlen */
2182
2183 attach->type = (WLAN_FC_TYPE_MGMT << 2) |
2184 (WLAN_FC_STYPE_ASSOC_REQ << 4);
2185 attach->id = -1;
2186 attach->size = len;
2187 memcpy(attach->data, param->u.generic_elem.data, len);
2188
2189 ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
2190
2191 if (ret == 0) {
2192 attach->type = (WLAN_FC_TYPE_MGMT << 2) |
2193 (WLAN_FC_STYPE_REASSOC_REQ << 4);
2194
2195 ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
2196
2197 if (ret == 0)
2198 printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
2199 ndev->name);
2200 }
2201
2202 kfree(attach);
2203 return ret;
2204
2205}
2206
2207static int
2208prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
2209{
2210 return -EOPNOTSUPP;
2211}
2212
2213static int
2214prism2_ioctl_scan_req(struct net_device *ndev,
2215 struct prism2_hostapd_param *param)
2216{
2217 islpci_private *priv = netdev_priv(ndev);
2218 int i, rvalue;
2219 struct obj_bsslist *bsslist;
2220 u32 noise = 0;
2221 char *extra = "";
2222 char *current_ev = "foo";
2223 union oid_res_t r;
2224
2225 if (islpci_get_state(priv) < PRV_STATE_INIT) {
2226 /* device is not ready, fail gently */
2227 return 0;
2228 }
2229
2230 /* first get the noise value. We will use it to report the link quality */
2231 rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
2232 noise = r.u;
2233
2234 /* Ask the device for a list of known bss. We can report at most
2235 * IW_MAX_AP=64 to the range struct. But the device won't repport anything
2236 * if you change the value of IWMAX_BSS=24.
2237 */
2238 rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
2239 bsslist = r.ptr;
2240
2241 /* ok now, scan the list and translate its info */
2242 for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
2243 current_ev = prism54_translate_bss(ndev, current_ev,
2244 extra + IW_SCAN_MAX_DATA,
2245 &(bsslist->bsslist[i]),
2246 noise);
2247 kfree(bsslist);
2248
2249 return rvalue;
2250}
2251
2252static int
2253prism54_hostapd(struct net_device *ndev, struct iw_point *p)
2254{
2255 struct prism2_hostapd_param *param;
2256 int ret = 0;
2257 u32 uwrq;
2258
2259 printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
2260 if (p->length < sizeof(struct prism2_hostapd_param) ||
2261 p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
2262 return -EINVAL;
2263
2264 param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
2265 if (param == NULL)
2266 return -ENOMEM;
2267
2268 if (copy_from_user(param, p->pointer, p->length)) {
2269 kfree(param);
2270 return -EFAULT;
2271 }
2272
2273 switch (param->cmd) {
2274 case PRISM2_SET_ENCRYPTION:
2275 printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
2276 ndev->name);
2277 ret = prism2_ioctl_set_encryption(ndev, param, p->length);
2278 break;
2279 case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
2280 printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
2281 ndev->name);
2282 ret = prism2_ioctl_set_generic_element(ndev, param,
2283 p->length);
2284 break;
2285 case PRISM2_HOSTAPD_MLME:
2286 printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
2287 ndev->name);
2288 ret = prism2_ioctl_mlme(ndev, param);
2289 break;
2290 case PRISM2_HOSTAPD_SCAN_REQ:
2291 printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
2292 ndev->name);
2293 ret = prism2_ioctl_scan_req(ndev, param);
2294 break;
2295 case PRISM54_SET_WPA:
2296 printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
2297 ndev->name);
2298 uwrq = 1;
2299 ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
2300 break;
2301 case PRISM54_DROP_UNENCRYPTED:
2302 printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
2303 ndev->name);
2304#if 0
2305 uwrq = 0x01;
2306 mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
2307 down_write(&priv->mib_sem);
2308 mgt_commit(priv);
2309 up_write(&priv->mib_sem);
2310#endif
2311 /* Not necessary, as set_wpa does it, should we just do it here though? */
2312 ret = 0;
2313 break;
2314 default:
2315 printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
2316 ndev->name);
2317 ret = -EOPNOTSUPP;
2318 break;
2319 }
2320
2321 if (ret == 0 && copy_to_user(p->pointer, param, p->length))
2322 ret = -EFAULT;
2323
2324 kfree(param);
2325
2326 return ret;
2327}
2328
2329static int
2330prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
2331 __u32 * uwrq, char *extra)
2332{
2333 islpci_private *priv = netdev_priv(ndev);
2334 u32 mlme, authen, dot1x, filter, wep;
2335
2336 if (islpci_get_state(priv) < PRV_STATE_INIT)
2337 return 0;
2338
2339 wep = 1; /* For privacy invoked */
2340 filter = 1; /* Filter out all unencrypted frames */
2341 dot1x = 0x01; /* To enable eap filter */
2342 mlme = DOT11_MLME_EXTENDED;
2343 authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
2344
2345 down_write(&priv->mib_sem);
2346 priv->wpa = *uwrq;
2347
2348 switch (priv->wpa) {
2349 default:
2350 case 0: /* Clears/disables WPA and friends */
2351 wep = 0;
2352 filter = 0; /* Do not filter un-encrypted data */
2353 dot1x = 0;
2354 mlme = DOT11_MLME_AUTO;
2355 printk("%s: Disabling WPA\n", ndev->name);
2356 break;
2357 case 2:
2358 case 1: /* WPA */
2359 printk("%s: Enabling WPA\n", ndev->name);
2360 break;
2361 }
2362 up_write(&priv->mib_sem);
2363
2364 mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
2365 mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
2366 mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
2367 mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
2368 mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
2369
2370 return 0;
2371}
2372
2373static int
2374prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
2375 __u32 * uwrq, char *extra)
2376{
2377 islpci_private *priv = netdev_priv(ndev);
2378 *uwrq = priv->wpa;
2379 return 0;
2380}
2381
2382static int
2383prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2384 __u32 * uwrq, char *extra)
2385{
2386 islpci_private *priv = netdev_priv(ndev);
2387 priv->monitor_type =
2388 (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
2389 if (priv->iw_mode == IW_MODE_MONITOR)
2390 priv->ndev->type = priv->monitor_type;
2391
2392 return 0;
2393}
2394
2395static int
2396prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2397 __u32 * uwrq, char *extra)
2398{
2399 islpci_private *priv = netdev_priv(ndev);
2400 *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
2401 return 0;
2402}
2403
2404static int
2405prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
2406 __u32 * uwrq, char *extra)
2407{
2408 islpci_private *priv = netdev_priv(ndev);
2409
2410 priv->priv_oid = *uwrq;
2411 printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
2412
2413 return 0;
2414}
2415
2416static int
2417prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
2418 struct iw_point *data, char *extra)
2419{
2420 islpci_private *priv = netdev_priv(ndev);
2421 struct islpci_mgmtframe *response;
2422 int ret = -EIO;
2423
2424 printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
2425 data->length = 0;
2426
2427 if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2428 ret =
2429 islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
2430 priv->priv_oid, extra, 256,
2431 &response);
2432 printk("%s: ret: %i\n", ndev->name, ret);
2433 if (ret || !response
2434 || response->header->operation == PIMFOR_OP_ERROR) {
2435 if (response) {
2436 islpci_mgt_release(response);
2437 }
2438 printk("%s: EIO\n", ndev->name);
2439 ret = -EIO;
2440 }
2441 if (!ret) {
2442 data->length = response->header->length;
2443 memcpy(extra, response->data, data->length);
2444 islpci_mgt_release(response);
2445 printk("%s: len: %i\n", ndev->name, data->length);
2446 }
2447 }
2448
2449 return ret;
2450}
2451
2452static int
2453prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
2454 struct iw_point *data, char *extra)
2455{
2456 islpci_private *priv = netdev_priv(ndev);
2457 struct islpci_mgmtframe *response;
2458 int ret = 0, response_op = PIMFOR_OP_ERROR;
2459
2460 printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
2461 data->length);
2462
2463 if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2464 ret =
2465 islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
2466 priv->priv_oid, extra, data->length,
2467 &response);
2468 printk("%s: ret: %i\n", ndev->name, ret);
2469 if (ret || !response
2470 || response->header->operation == PIMFOR_OP_ERROR) {
2471 if (response) {
2472 islpci_mgt_release(response);
2473 }
2474 printk("%s: EIO\n", ndev->name);
2475 ret = -EIO;
2476 }
2477 if (!ret) {
2478 response_op = response->header->operation;
2479 printk("%s: response_op: %i\n", ndev->name,
2480 response_op);
2481 islpci_mgt_release(response);
2482 }
2483 }
2484
2485 return (ret ? ret : -EINPROGRESS);
2486}
2487
2488static int
2489prism54_set_spy(struct net_device *ndev,
2490 struct iw_request_info *info,
2491 union iwreq_data *uwrq, char *extra)
2492{
2493 islpci_private *priv = netdev_priv(ndev);
2494 u32 u, oid = OID_INL_CONFIG;
2495
2496 down_write(&priv->mib_sem);
2497 mgt_get(priv, OID_INL_CONFIG, &u);
2498
2499 if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0))
2500 /* disable spy */
2501 u &= ~INL_CONFIG_RXANNEX;
2502 else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0))
2503 /* enable spy */
2504 u |= INL_CONFIG_RXANNEX;
2505
2506 mgt_set(priv, OID_INL_CONFIG, &u);
2507 mgt_commit_list(priv, &oid, 1);
2508 up_write(&priv->mib_sem);
2509
2510 return iw_handler_set_spy(ndev, info, uwrq, extra);
2511}
2512
2513static const iw_handler prism54_handler[] = {
2514 (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */
2515 (iw_handler) prism54_get_name, /* SIOCGIWNAME */
2516 (iw_handler) NULL, /* SIOCSIWNWID */
2517 (iw_handler) NULL, /* SIOCGIWNWID */
2518 (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */
2519 (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */
2520 (iw_handler) prism54_set_mode, /* SIOCSIWMODE */
2521 (iw_handler) prism54_get_mode, /* SIOCGIWMODE */
2522 (iw_handler) prism54_set_sens, /* SIOCSIWSENS */
2523 (iw_handler) prism54_get_sens, /* SIOCGIWSENS */
2524 (iw_handler) NULL, /* SIOCSIWRANGE */
2525 (iw_handler) prism54_get_range, /* SIOCGIWRANGE */
2526 (iw_handler) NULL, /* SIOCSIWPRIV */
2527 (iw_handler) NULL, /* SIOCGIWPRIV */
2528 (iw_handler) NULL, /* SIOCSIWSTATS */
2529 (iw_handler) NULL, /* SIOCGIWSTATS */
2530 prism54_set_spy, /* SIOCSIWSPY */
2531 iw_handler_get_spy, /* SIOCGIWSPY */
2532 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2533 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2534 (iw_handler) prism54_set_wap, /* SIOCSIWAP */
2535 (iw_handler) prism54_get_wap, /* SIOCGIWAP */
2536 (iw_handler) NULL, /* -- hole -- */
2537 (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */
2538 (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */
2539 (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */
2540 (iw_handler) prism54_set_essid, /* SIOCSIWESSID */
2541 (iw_handler) prism54_get_essid, /* SIOCGIWESSID */
2542 (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */
2543 (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */
2544 (iw_handler) NULL, /* -- hole -- */
2545 (iw_handler) NULL, /* -- hole -- */
2546 (iw_handler) prism54_set_rate, /* SIOCSIWRATE */
2547 (iw_handler) prism54_get_rate, /* SIOCGIWRATE */
2548 (iw_handler) prism54_set_rts, /* SIOCSIWRTS */
2549 (iw_handler) prism54_get_rts, /* SIOCGIWRTS */
2550 (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */
2551 (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */
2552 (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */
2553 (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */
2554 (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */
2555 (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */
2556 (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */
2557 (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */
2558 (iw_handler) NULL, /* SIOCSIWPOWER */
2559 (iw_handler) NULL, /* SIOCGIWPOWER */
2560};
2561
2562/* The low order bit identify a SET (0) or a GET (1) ioctl. */
2563
2564#define PRISM54_RESET SIOCIWFIRSTPRIV
2565#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1
2566#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2
2567#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3
2568#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4
2569
2570#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6
2571
2572#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8
2573
2574#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10
2575
2576#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11
2577#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
2578
2579#define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14
2580#define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15
2581#define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16
2582
2583#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17
2584#define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18
2585#define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20
2586#define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22
2587
2588#define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23
2589#define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24
2590
2591#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2592#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2593#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2594#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
2595
2596#define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
2597#define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
2598#define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
2599
2600/* Note : limited to 128 private ioctls (wireless tools 26) */
2601
2602static const struct iw_priv_args prism54_private_args[] = {
2603/*{ cmd, set_args, get_args, name } */
2604 {PRISM54_RESET, 0, 0, "reset"},
2605 {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2606 "get_prismhdr"},
2607 {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2608 "set_prismhdr"},
2609 {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2610 "getPolicy"},
2611 {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2612 "setPolicy"},
2613 {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"},
2614 {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2615 "addMac"},
2616 {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2617 "delMac"},
2618 {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2619 "kickMac"},
2620 {PRISM54_KICK_ALL, 0, 0, "kickAll"},
2621 {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2622 "get_wpa"},
2623 {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2624 "set_wpa"},
2625 {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2626 "dbg_oid"},
2627 {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
2628 {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
2629 /* --- sub-ioctls handlers --- */
2630 {PRISM54_GET_OID,
2631 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
2632 {PRISM54_SET_OID_U32,
2633 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2634 {PRISM54_SET_OID_STR,
2635 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2636 {PRISM54_SET_OID_ADDR,
2637 IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2638 /* --- sub-ioctls definitions --- */
2639 IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"),
2640 IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"),
2641 IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"),
2642 IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"),
2643 IWPRIV_U32(DOT11_OID_STATE, "state"),
2644 IWPRIV_U32(DOT11_OID_AID, "aid"),
2645
2646 IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"),
2647
2648 IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"),
2649 IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"),
2650 IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"),
2651
2652 IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
2653 IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
2654 IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
2655
2656 IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
2657
2658 IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
2659 IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"),
2660 IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"),
2661 IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"),
2662 IWPRIV_U32(DOT11_OID_PSM, "psm"),
2663
2664 IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"),
2665 IWPRIV_U32(DOT11_OID_CLIENTS, "clients"),
2666 IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"),
2667 IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"),
2668 IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"),
2669 IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"),
2670 IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"),
2671 IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"),
2672 IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"),
2673 IWPRIV_GET(DOT11_OID_RATES, "rates"),
2674 IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"),
2675 IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"),
2676 IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"),
2677
2678 IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"),
2679 IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"),
2680 IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"),
2681 IWPRIV_U32(DOT11_OID_PROFILES, "profile"),
2682 IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"),
2683 IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"),
2684
2685 IWPRIV_GET(DOT11_OID_BSSS, "bsss"),
2686 IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"),
2687 IWPRIV_U32(OID_INL_MODE, "mode"),
2688 IWPRIV_U32(OID_INL_CONFIG, "config"),
2689 IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"),
2690 IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"),
2691 IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"),
2692};
2693
2694static const iw_handler prism54_private_handler[] = {
2695 (iw_handler) prism54_reset,
2696 (iw_handler) prism54_get_policy,
2697 (iw_handler) prism54_set_policy,
2698 (iw_handler) prism54_get_mac,
2699 (iw_handler) prism54_add_mac,
2700 (iw_handler) NULL,
2701 (iw_handler) prism54_del_mac,
2702 (iw_handler) NULL,
2703 (iw_handler) prism54_kick_mac,
2704 (iw_handler) NULL,
2705 (iw_handler) prism54_kick_all,
2706 (iw_handler) prism54_get_wpa,
2707 (iw_handler) prism54_set_wpa,
2708 (iw_handler) NULL,
2709 (iw_handler) prism54_debug_oid,
2710 (iw_handler) prism54_debug_get_oid,
2711 (iw_handler) prism54_debug_set_oid,
2712 (iw_handler) prism54_get_oid,
2713 (iw_handler) prism54_set_u32,
2714 (iw_handler) NULL,
2715 (iw_handler) prism54_set_raw,
2716 (iw_handler) NULL,
2717 (iw_handler) prism54_set_raw,
2718 (iw_handler) prism54_get_prismhdr,
2719 (iw_handler) prism54_set_prismhdr,
2720};
2721
2722const struct iw_handler_def prism54_handler_def = {
2723 .num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
2724 .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
2725 .num_private_args =
2726 sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
2727 .standard = (iw_handler *) prism54_handler,
2728 .private = (iw_handler *) prism54_private_handler,
2729 .private_args = (struct iw_priv_args *) prism54_private_args,
2730#if WIRELESS_EXT == 16
2731 .spy_offset = offsetof(islpci_private, spy_data),
2732#endif /* WIRELESS_EXT == 16 */
2733};
2734
2735/* For wpa_supplicant */
2736
2737int
2738prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
2739{
2740 struct iwreq *wrq = (struct iwreq *) rq;
2741 int ret = -1;
2742 switch (cmd) {
2743 case PRISM54_HOSTAPD:
2744 if (!capable(CAP_NET_ADMIN))
2745 return -EPERM;
2746 ret = prism54_hostapd(ndev, &wrq->u.data);
2747 return ret;
2748 }
2749 return -EOPNOTSUPP;
2750}
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
new file mode 100644
index 000000000000..46d5cde80c85
--- /dev/null
+++ b/drivers/net/wireless/prism54/isl_ioctl.h
@@ -0,0 +1,51 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * (C) 2003 Aurelien Alleaume <slts@free.fr>
5 * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#ifndef _ISL_IOCTL_H
23#define _ISL_IOCTL_H
24
25#include "islpci_mgt.h"
26#include "islpci_dev.h"
27
28#include <net/iw_handler.h> /* New driver API */
29
30#define SUPPORTED_WIRELESS_EXT 16
31
32void prism54_mib_init(islpci_private *);
33
34struct iw_statistics *prism54_get_wireless_stats(struct net_device *);
35void prism54_update_stats(islpci_private *);
36
37void prism54_acl_init(struct islpci_acl *);
38void prism54_acl_clean(struct islpci_acl *);
39
40void prism54_process_trap(void *);
41
42void prism54_wpa_ie_init(islpci_private *priv);
43void prism54_wpa_ie_clean(islpci_private *priv);
44
45int prism54_set_mac_address(struct net_device *, void *);
46
47int prism54_ioctl(struct net_device *, struct ifreq *, int);
48
49extern const struct iw_handler_def prism54_handler_def;
50
51#endif /* _ISL_IOCTL_H */
diff --git a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h
new file mode 100644
index 000000000000..419edf7ccf1a
--- /dev/null
+++ b/drivers/net/wireless/prism54/isl_oid.h
@@ -0,0 +1,507 @@
1/*
2 *
3 *
4 * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
5 * Copyright (C) 2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
6 * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#if !defined(_ISL_OID_H)
24#define _ISL_OID_H
25
26/*
27 * MIB related constant and structure definitions for communicating
28 * with the device firmware
29 */
30
31struct obj_ssid {
32 u8 length;
33 char octets[33];
34} __attribute__ ((packed));
35
36struct obj_key {
37 u8 type; /* dot11_priv_t */
38 u8 length;
39 char key[32];
40} __attribute__ ((packed));
41
42struct obj_mlme {
43 u8 address[6];
44 u16 id;
45 u16 state;
46 u16 code;
47} __attribute__ ((packed));
48
49struct obj_mlmeex {
50 u8 address[6];
51 u16 id;
52 u16 state;
53 u16 code;
54 u16 size;
55 u8 data[0];
56} __attribute__ ((packed));
57
58struct obj_buffer {
59 u32 size;
60 u32 addr; /* 32bit bus address */
61} __attribute__ ((packed));
62
63struct obj_bss {
64 u8 address[6];
65 int:16; /* padding */
66
67 char state;
68 char reserved;
69 short age;
70
71 char quality;
72 char rssi;
73
74 struct obj_ssid ssid;
75 short channel;
76 char beacon_period;
77 char dtim_period;
78 short capinfo;
79 short rates;
80 short basic_rates;
81 int:16; /* padding */
82} __attribute__ ((packed));
83
84struct obj_bsslist {
85 u32 nr;
86 struct obj_bss bsslist[0];
87} __attribute__ ((packed));
88
89struct obj_frequencies {
90 u16 nr;
91 u16 mhz[0];
92} __attribute__ ((packed));
93
94struct obj_attachment {
95 char type;
96 char reserved;
97 short id;
98 short size;
99 char data[0];
100} __attribute__((packed));
101
102/*
103 * in case everything's ok, the inlined function below will be
104 * optimized away by the compiler...
105 */
106static inline void
107__bug_on_wrong_struct_sizes(void)
108{
109 BUG_ON(sizeof (struct obj_ssid) != 34);
110 BUG_ON(sizeof (struct obj_key) != 34);
111 BUG_ON(sizeof (struct obj_mlme) != 12);
112 BUG_ON(sizeof (struct obj_mlmeex) != 14);
113 BUG_ON(sizeof (struct obj_buffer) != 8);
114 BUG_ON(sizeof (struct obj_bss) != 60);
115 BUG_ON(sizeof (struct obj_bsslist) != 4);
116 BUG_ON(sizeof (struct obj_frequencies) != 2);
117}
118
119enum dot11_state_t {
120 DOT11_STATE_NONE = 0,
121 DOT11_STATE_AUTHING = 1,
122 DOT11_STATE_AUTH = 2,
123 DOT11_STATE_ASSOCING = 3,
124
125 DOT11_STATE_ASSOC = 5,
126 DOT11_STATE_IBSS = 6,
127 DOT11_STATE_WDS = 7
128};
129
130enum dot11_bsstype_t {
131 DOT11_BSSTYPE_NONE = 0,
132 DOT11_BSSTYPE_INFRA = 1,
133 DOT11_BSSTYPE_IBSS = 2,
134 DOT11_BSSTYPE_ANY = 3
135};
136
137enum dot11_auth_t {
138 DOT11_AUTH_NONE = 0,
139 DOT11_AUTH_OS = 1,
140 DOT11_AUTH_SK = 2,
141 DOT11_AUTH_BOTH = 3
142};
143
144enum dot11_mlme_t {
145 DOT11_MLME_AUTO = 0,
146 DOT11_MLME_INTERMEDIATE = 1,
147 DOT11_MLME_EXTENDED = 2
148};
149
150enum dot11_priv_t {
151 DOT11_PRIV_WEP = 0,
152 DOT11_PRIV_TKIP = 1
153};
154
155/* Prism "Nitro" / Frameburst / "Packet Frame Grouping"
156 * Value is in microseconds. Represents the # microseconds
157 * the firmware will take to group frames before sending out then out
158 * together with a CSMA contention. Without this all frames are
159 * sent with a CSMA contention.
160 * Bibliography:
161 * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html
162 */
163enum dot11_maxframeburst_t {
164 /* Values for DOT11_OID_MAXFRAMEBURST */
165 DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */
166 DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */
167 DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */
168 DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max,
169 * Note: firmware allows for greater values. This is a
170 * recommended max. I'll update this as I find
171 * out what the real MAX is. Also note that you don't necessarily
172 * get better results with a greater value here.
173 */
174};
175
176/* Support for 802.11 long and short frame preambles.
177 * Long preamble uses 128-bit sync field, 8-bit CRC
178 * Short preamble uses 56-bit sync field, 16-bit CRC
179 *
180 * 802.11a -- not sure, both optionally ?
181 * 802.11b supports long and optionally short
182 * 802.11g supports both */
183enum dot11_preamblesettings_t {
184 DOT11_PREAMBLESETTING_LONG = 0,
185 /* Allows *only* long 802.11 preambles */
186 DOT11_PREAMBLESETTING_SHORT = 1,
187 /* Allows *only* short 802.11 preambles */
188 DOT11_PREAMBLESETTING_DYNAMIC = 2
189 /* AutomatiGically set */
190};
191
192/* Support for 802.11 slot timing (time between packets).
193 *
194 * Long uses 802.11a slot timing (9 usec ?)
195 * Short uses 802.11b slot timing (20 use ?) */
196enum dot11_slotsettings_t {
197 DOT11_SLOTSETTINGS_LONG = 0,
198 /* Allows *only* long 802.11b slot timing */
199 DOT11_SLOTSETTINGS_SHORT = 1,
200 /* Allows *only* long 802.11a slot timing */
201 DOT11_SLOTSETTINGS_DYNAMIC = 2
202 /* AutomatiGically set */
203};
204
205/* All you need to know, ERP is "Extended Rate PHY".
206 * An Extended Rate PHY (ERP) STA or AP shall support three different
207 * preamble and header formats:
208 * Long preamble (refer to above)
209 * Short preamble (refer to above)
210 * OFDM preamble ( ? )
211 *
212 * I'm assuming here Protection tells the AP
213 * to be careful, a STA which cannot handle the long pre-amble
214 * has joined.
215 */
216enum do11_nonerpstatus_t {
217 DOT11_ERPSTAT_NONEPRESENT = 0,
218 DOT11_ERPSTAT_USEPROTECTION = 1
219};
220
221/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-*
222 * The key here is DOT11 NON ERP NEVER protects against
223 * NON ERP STA's. You *don't* want this unless
224 * you know what you are doing. It means you will only
225 * get Extended Rate capabilities */
226enum dot11_nonerpprotection_t {
227 DOT11_NONERP_NEVER = 0,
228 DOT11_NONERP_ALWAYS = 1,
229 DOT11_NONERP_DYNAMIC = 2
230};
231
232/* Preset OID configuration for 802.11 modes
233 * Note: DOT11_OID_CW[MIN|MAX] hold the values of the
234 * DCS MIN|MAX backoff used */
235enum dot11_profile_t { /* And set/allowed values */
236 /* Allowed values for DOT11_OID_PROFILES */
237 DOT11_PROFILE_B_ONLY = 0,
238 /* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps
239 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
240 * DOT11_OID_CWMIN: 31
241 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
242 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG
243 */
244 DOT11_PROFILE_MIXED_G_WIFI = 1,
245 /* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs
246 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
247 * DOT11_OID_CWMIN: 15
248 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
249 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC
250 */
251 DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */
252 /* Same as Profile MIXED_G_WIFI */
253 DOT11_PROFILE_G_ONLY = 3,
254 /* Same as Profile MIXED_G_WIFI */
255 DOT11_PROFILE_TEST = 4,
256 /* Same as Profile MIXED_G_WIFI except:
257 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT
258 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER
259 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT
260 */
261 DOT11_PROFILE_B_WIFI = 5,
262 /* Same as Profile B_ONLY */
263 DOT11_PROFILE_A_ONLY = 6,
264 /* Same as Profile MIXED_G_WIFI except:
265 * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs
266 */
267 DOT11_PROFILE_MIXED_SHORT = 7
268 /* Same as MIXED_G_WIFI */
269};
270
271
272/* The dot11d conformance level configures the 802.11d conformance levels.
273 * The following conformance levels exist:*/
274enum oid_inl_conformance_t {
275 OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */
276 OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */
277 OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to
278 * determine channel AND/OR just make assumption that active
279 * channels are valid channels */
280};
281
282enum oid_inl_mode_t {
283 INL_MODE_NONE = -1,
284 INL_MODE_PROMISCUOUS = 0,
285 INL_MODE_CLIENT = 1,
286 INL_MODE_AP = 2,
287 INL_MODE_SNIFFER = 3
288};
289
290enum oid_inl_config_t {
291 INL_CONFIG_NOTHING = 0x00,
292 INL_CONFIG_MANUALRUN = 0x01,
293 INL_CONFIG_FRAMETRAP = 0x02,
294 INL_CONFIG_RXANNEX = 0x04,
295 INL_CONFIG_TXANNEX = 0x08,
296 INL_CONFIG_WDS = 0x10
297};
298
299enum oid_inl_phycap_t {
300 INL_PHYCAP_2400MHZ = 1,
301 INL_PHYCAP_5000MHZ = 2,
302 INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */
303};
304
305
306enum oid_num_t {
307 GEN_OID_MACADDRESS = 0,
308 GEN_OID_LINKSTATE,
309 GEN_OID_WATCHDOG,
310 GEN_OID_MIBOP,
311 GEN_OID_OPTIONS,
312 GEN_OID_LEDCONFIG,
313
314 /* 802.11 */
315 DOT11_OID_BSSTYPE,
316 DOT11_OID_BSSID,
317 DOT11_OID_SSID,
318 DOT11_OID_STATE,
319 DOT11_OID_AID,
320 DOT11_OID_COUNTRYSTRING,
321 DOT11_OID_SSIDOVERRIDE,
322
323 DOT11_OID_MEDIUMLIMIT,
324 DOT11_OID_BEACONPERIOD,
325 DOT11_OID_DTIMPERIOD,
326 DOT11_OID_ATIMWINDOW,
327 DOT11_OID_LISTENINTERVAL,
328 DOT11_OID_CFPPERIOD,
329 DOT11_OID_CFPDURATION,
330
331 DOT11_OID_AUTHENABLE,
332 DOT11_OID_PRIVACYINVOKED,
333 DOT11_OID_EXUNENCRYPTED,
334 DOT11_OID_DEFKEYID,
335 DOT11_OID_DEFKEYX, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
336 DOT11_OID_STAKEY,
337 DOT11_OID_REKEYTHRESHOLD,
338 DOT11_OID_STASC,
339
340 DOT11_OID_PRIVTXREJECTED,
341 DOT11_OID_PRIVRXPLAIN,
342 DOT11_OID_PRIVRXFAILED,
343 DOT11_OID_PRIVRXNOKEY,
344
345 DOT11_OID_RTSTHRESH,
346 DOT11_OID_FRAGTHRESH,
347 DOT11_OID_SHORTRETRIES,
348 DOT11_OID_LONGRETRIES,
349 DOT11_OID_MAXTXLIFETIME,
350 DOT11_OID_MAXRXLIFETIME,
351 DOT11_OID_AUTHRESPTIMEOUT,
352 DOT11_OID_ASSOCRESPTIMEOUT,
353
354 DOT11_OID_ALOFT_TABLE,
355 DOT11_OID_ALOFT_CTRL_TABLE,
356 DOT11_OID_ALOFT_RETREAT,
357 DOT11_OID_ALOFT_PROGRESS,
358 DOT11_OID_ALOFT_FIXEDRATE,
359 DOT11_OID_ALOFT_RSSIGRAPH,
360 DOT11_OID_ALOFT_CONFIG,
361
362 DOT11_OID_VDCFX,
363 DOT11_OID_MAXFRAMEBURST,
364
365 DOT11_OID_PSM,
366 DOT11_OID_CAMTIMEOUT,
367 DOT11_OID_RECEIVEDTIMS,
368 DOT11_OID_ROAMPREFERENCE,
369
370 DOT11_OID_BRIDGELOCAL,
371 DOT11_OID_CLIENTS,
372 DOT11_OID_CLIENTSASSOCIATED,
373 DOT11_OID_CLIENTX, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */
374
375 DOT11_OID_CLIENTFIND,
376 DOT11_OID_WDSLINKADD,
377 DOT11_OID_WDSLINKREMOVE,
378 DOT11_OID_EAPAUTHSTA,
379 DOT11_OID_EAPUNAUTHSTA,
380 DOT11_OID_DOT1XENABLE,
381 DOT11_OID_MICFAILURE,
382 DOT11_OID_REKEYINDICATE,
383
384 DOT11_OID_MPDUTXSUCCESSFUL,
385 DOT11_OID_MPDUTXONERETRY,
386 DOT11_OID_MPDUTXMULTIPLERETRIES,
387 DOT11_OID_MPDUTXFAILED,
388 DOT11_OID_MPDURXSUCCESSFUL,
389 DOT11_OID_MPDURXDUPS,
390 DOT11_OID_RTSSUCCESSFUL,
391 DOT11_OID_RTSFAILED,
392 DOT11_OID_ACKFAILED,
393 DOT11_OID_FRAMERECEIVES,
394 DOT11_OID_FRAMEERRORS,
395 DOT11_OID_FRAMEABORTS,
396 DOT11_OID_FRAMEABORTSPHY,
397
398 DOT11_OID_SLOTTIME,
399 DOT11_OID_CWMIN, /* MIN DCS backoff */
400 DOT11_OID_CWMAX, /* MAX DCS backoff */
401 DOT11_OID_ACKWINDOW,
402 DOT11_OID_ANTENNARX,
403 DOT11_OID_ANTENNATX,
404 DOT11_OID_ANTENNADIVERSITY,
405 DOT11_OID_CHANNEL,
406 DOT11_OID_EDTHRESHOLD,
407 DOT11_OID_PREAMBLESETTINGS,
408 DOT11_OID_RATES,
409 DOT11_OID_CCAMODESUPPORTED,
410 DOT11_OID_CCAMODE,
411 DOT11_OID_RSSIVECTOR,
412 DOT11_OID_OUTPUTPOWERTABLE,
413 DOT11_OID_OUTPUTPOWER,
414 DOT11_OID_SUPPORTEDRATES,
415 DOT11_OID_FREQUENCY,
416 DOT11_OID_SUPPORTEDFREQUENCIES,
417 DOT11_OID_NOISEFLOOR,
418 DOT11_OID_FREQUENCYACTIVITY,
419 DOT11_OID_IQCALIBRATIONTABLE,
420 DOT11_OID_NONERPPROTECTION,
421 DOT11_OID_SLOTSETTINGS,
422 DOT11_OID_NONERPTIMEOUT,
423 DOT11_OID_PROFILES,
424 DOT11_OID_EXTENDEDRATES,
425
426 DOT11_OID_DEAUTHENTICATE,
427 DOT11_OID_AUTHENTICATE,
428 DOT11_OID_DISASSOCIATE,
429 DOT11_OID_ASSOCIATE,
430 DOT11_OID_SCAN,
431 DOT11_OID_BEACON,
432 DOT11_OID_PROBE,
433 DOT11_OID_DEAUTHENTICATEEX,
434 DOT11_OID_AUTHENTICATEEX,
435 DOT11_OID_DISASSOCIATEEX,
436 DOT11_OID_ASSOCIATEEX,
437 DOT11_OID_REASSOCIATE,
438 DOT11_OID_REASSOCIATEEX,
439
440 DOT11_OID_NONERPSTATUS,
441
442 DOT11_OID_STATIMEOUT,
443 DOT11_OID_MLMEAUTOLEVEL,
444 DOT11_OID_BSSTIMEOUT,
445 DOT11_OID_ATTACHMENT,
446 DOT11_OID_PSMBUFFER,
447
448 DOT11_OID_BSSS,
449 DOT11_OID_BSSX, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
450 DOT11_OID_BSSFIND,
451 DOT11_OID_BSSLIST,
452
453 OID_INL_TUNNEL,
454 OID_INL_MEMADDR,
455 OID_INL_MEMORY,
456 OID_INL_MODE,
457 OID_INL_COMPONENT_NR,
458 OID_INL_VERSION,
459 OID_INL_INTERFACE_ID,
460 OID_INL_COMPONENT_ID,
461 OID_INL_CONFIG,
462 OID_INL_DOT11D_CONFORMANCE,
463 OID_INL_PHYCAPABILITIES,
464 OID_INL_OUTPUTPOWER,
465
466 OID_NUM_LAST
467};
468
469#define OID_FLAG_CACHED 0x80
470#define OID_FLAG_TYPE 0x7f
471
472#define OID_TYPE_U32 0x01
473#define OID_TYPE_SSID 0x02
474#define OID_TYPE_KEY 0x03
475#define OID_TYPE_BUFFER 0x04
476#define OID_TYPE_BSS 0x05
477#define OID_TYPE_BSSLIST 0x06
478#define OID_TYPE_FREQUENCIES 0x07
479#define OID_TYPE_MLME 0x08
480#define OID_TYPE_MLMEEX 0x09
481#define OID_TYPE_ADDR 0x0A
482#define OID_TYPE_RAW 0x0B
483#define OID_TYPE_ATTACH 0x0C
484
485/* OID_TYPE_MLMEEX is special because of a variable size field when sending.
486 * Not yet implemented (not used in driver anyway).
487 */
488
489struct oid_t {
490 enum oid_num_t oid;
491 short range; /* to define a range of oid */
492 short size; /* max size of the associated data */
493 char flags;
494};
495
496union oid_res_t {
497 void *ptr;
498 u32 u;
499};
500
501#define IWMAX_BITRATES 20
502#define IWMAX_BSS 24
503#define IWMAX_FREQ 30
504#define PRIV_STR_SIZE 1024
505
506#endif /* !defined(_ISL_OID_H) */
507/* EOF */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
new file mode 100644
index 000000000000..efab07e9e24e
--- /dev/null
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -0,0 +1,956 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
5 * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <linux/version.h>
23#include <linux/module.h>
24
25#include <linux/netdevice.h>
26#include <linux/pci.h>
27#include <linux/etherdevice.h>
28#include <linux/delay.h>
29#include <linux/if_arp.h>
30
31#include <asm/io.h>
32
33#include "prismcompat.h"
34#include "isl_38xx.h"
35#include "isl_ioctl.h"
36#include "islpci_dev.h"
37#include "islpci_mgt.h"
38#include "islpci_eth.h"
39#include "oid_mgt.h"
40
41#define ISL3877_IMAGE_FILE "isl3877"
42#define ISL3886_IMAGE_FILE "isl3886"
43#define ISL3890_IMAGE_FILE "isl3890"
44
45static int prism54_bring_down(islpci_private *);
46static int islpci_alloc_memory(islpci_private *);
47static struct net_device_stats *islpci_statistics(struct net_device *);
48
49/* Temporary dummy MAC address to use until firmware is loaded.
50 * The idea there is that some tools (such as nameif) may query
51 * the MAC address before the netdev is 'open'. By using a valid
52 * OUI prefix, they can process the netdev properly.
53 * Of course, this is not the final/real MAC address. It doesn't
54 * matter, as you are suppose to be able to change it anytime via
55 * ndev->set_mac_address. Jean II */
56static const unsigned char dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 };
57
58static int
59isl_upload_firmware(islpci_private *priv)
60{
61 u32 reg, rc;
62 void __iomem *device_base = priv->device_base;
63
64 /* clear the RAMBoot and the Reset bit */
65 reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
66 reg &= ~ISL38XX_CTRL_STAT_RESET;
67 reg &= ~ISL38XX_CTRL_STAT_RAMBOOT;
68 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
69 wmb();
70 udelay(ISL38XX_WRITEIO_DELAY);
71
72 /* set the Reset bit without reading the register ! */
73 reg |= ISL38XX_CTRL_STAT_RESET;
74 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
75 wmb();
76 udelay(ISL38XX_WRITEIO_DELAY);
77
78 /* clear the Reset bit */
79 reg &= ~ISL38XX_CTRL_STAT_RESET;
80 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
81 wmb();
82
83 /* wait a while for the device to reboot */
84 mdelay(50);
85
86 {
87 const struct firmware *fw_entry = NULL;
88 long fw_len;
89 const u32 *fw_ptr;
90
91 rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV);
92 if (rc) {
93 printk(KERN_ERR
94 "%s: request_firmware() failed for '%s'\n",
95 "prism54", priv->firmware);
96 return rc;
97 }
98 /* prepare the Direct Memory Base register */
99 reg = ISL38XX_DEV_FIRMWARE_ADDRES;
100
101 fw_ptr = (u32 *) fw_entry->data;
102 fw_len = fw_entry->size;
103
104 if (fw_len % 4) {
105 printk(KERN_ERR
106 "%s: firmware '%s' size is not multiple of 32bit, aborting!\n",
107 "prism54", priv->firmware);
108 release_firmware(fw_entry);
109 return -EILSEQ; /* Illegal byte sequence */;
110 }
111
112 while (fw_len > 0) {
113 long _fw_len =
114 (fw_len >
115 ISL38XX_MEMORY_WINDOW_SIZE) ?
116 ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
117 u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
118
119 /* set the cards base address for writting the data */
120 isl38xx_w32_flush(device_base, reg,
121 ISL38XX_DIR_MEM_BASE_REG);
122 wmb(); /* be paranoid */
123
124 /* increment the write address for next iteration */
125 reg += _fw_len;
126 fw_len -= _fw_len;
127
128 /* write the data to the Direct Memory Window 32bit-wise */
129 /* memcpy_toio() doesn't guarantee 32bit writes :-| */
130 while (_fw_len > 0) {
131 /* use non-swapping writel() */
132 __raw_writel(*fw_ptr, dev_fw_ptr);
133 fw_ptr++, dev_fw_ptr++;
134 _fw_len -= 4;
135 }
136
137 /* flush PCI posting */
138 (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH);
139 wmb(); /* be paranoid again */
140
141 BUG_ON(_fw_len != 0);
142 }
143
144 BUG_ON(fw_len != 0);
145
146 /* Firmware version is at offset 40 (also for "newmac") */
147 printk(KERN_DEBUG "%s: firmware version: %.8s\n",
148 priv->ndev->name, fw_entry->data + 40);
149
150 release_firmware(fw_entry);
151 }
152
153 /* now reset the device
154 * clear the Reset & ClkRun bit, set the RAMBoot bit */
155 reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
156 reg &= ~ISL38XX_CTRL_STAT_CLKRUN;
157 reg &= ~ISL38XX_CTRL_STAT_RESET;
158 reg |= ISL38XX_CTRL_STAT_RAMBOOT;
159 isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG);
160 wmb();
161 udelay(ISL38XX_WRITEIO_DELAY);
162
163 /* set the reset bit latches the host override and RAMBoot bits
164 * into the device for operation when the reset bit is reset */
165 reg |= ISL38XX_CTRL_STAT_RESET;
166 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
167 /* don't do flush PCI posting here! */
168 wmb();
169 udelay(ISL38XX_WRITEIO_DELAY);
170
171 /* clear the reset bit should start the whole circus */
172 reg &= ~ISL38XX_CTRL_STAT_RESET;
173 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
174 /* don't do flush PCI posting here! */
175 wmb();
176 udelay(ISL38XX_WRITEIO_DELAY);
177
178 return 0;
179}
180
181/******************************************************************************
182 Device Interrupt Handler
183******************************************************************************/
184
185irqreturn_t
186islpci_interrupt(int irq, void *config, struct pt_regs *regs)
187{
188 u32 reg;
189 islpci_private *priv = config;
190 struct net_device *ndev = priv->ndev;
191 void __iomem *device = priv->device_base;
192 int powerstate = ISL38XX_PSM_POWERSAVE_STATE;
193
194 /* lock the interrupt handler */
195 spin_lock(&priv->slock);
196
197 /* received an interrupt request on a shared IRQ line
198 * first check whether the device is in sleep mode */
199 reg = readl(device + ISL38XX_CTRL_STAT_REG);
200 if (reg & ISL38XX_CTRL_STAT_SLEEPMODE)
201 /* device is in sleep mode, IRQ was generated by someone else */
202 {
203#if VERBOSE > SHOW_ERROR_MESSAGES
204 DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");
205#endif
206 spin_unlock(&priv->slock);
207 return IRQ_NONE;
208 }
209
210
211 /* check whether there is any source of interrupt on the device */
212 reg = readl(device + ISL38XX_INT_IDENT_REG);
213
214 /* also check the contents of the Interrupt Enable Register, because this
215 * will filter out interrupt sources from other devices on the same irq ! */
216 reg &= readl(device + ISL38XX_INT_EN_REG);
217 reg &= ISL38XX_INT_SOURCES;
218
219 if (reg != 0) {
220 if (islpci_get_state(priv) != PRV_STATE_SLEEP)
221 powerstate = ISL38XX_PSM_ACTIVE_STATE;
222
223 /* reset the request bits in the Identification register */
224 isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG);
225
226#if VERBOSE > SHOW_ERROR_MESSAGES
227 DEBUG(SHOW_FUNCTION_CALLS,
228 "IRQ: Identification register 0x%p 0x%x \n", device, reg);
229#endif
230
231 /* check for each bit in the register separately */
232 if (reg & ISL38XX_INT_IDENT_UPDATE) {
233#if VERBOSE > SHOW_ERROR_MESSAGES
234 /* Queue has been updated */
235 DEBUG(SHOW_TRACING, "IRQ: Update flag \n");
236
237 DEBUG(SHOW_QUEUE_INDEXES,
238 "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n",
239 le32_to_cpu(priv->control_block->
240 driver_curr_frag[0]),
241 le32_to_cpu(priv->control_block->
242 driver_curr_frag[1]),
243 le32_to_cpu(priv->control_block->
244 driver_curr_frag[2]),
245 le32_to_cpu(priv->control_block->
246 driver_curr_frag[3]),
247 le32_to_cpu(priv->control_block->
248 driver_curr_frag[4]),
249 le32_to_cpu(priv->control_block->
250 driver_curr_frag[5])
251 );
252
253 DEBUG(SHOW_QUEUE_INDEXES,
254 "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n",
255 le32_to_cpu(priv->control_block->
256 device_curr_frag[0]),
257 le32_to_cpu(priv->control_block->
258 device_curr_frag[1]),
259 le32_to_cpu(priv->control_block->
260 device_curr_frag[2]),
261 le32_to_cpu(priv->control_block->
262 device_curr_frag[3]),
263 le32_to_cpu(priv->control_block->
264 device_curr_frag[4]),
265 le32_to_cpu(priv->control_block->
266 device_curr_frag[5])
267 );
268#endif
269
270 /* cleanup the data low transmit queue */
271 islpci_eth_cleanup_transmit(priv, priv->control_block);
272
273 /* device is in active state, update the
274 * powerstate flag if necessary */
275 powerstate = ISL38XX_PSM_ACTIVE_STATE;
276
277 /* check all three queues in priority order
278 * call the PIMFOR receive function until the
279 * queue is empty */
280 if (isl38xx_in_queue(priv->control_block,
281 ISL38XX_CB_RX_MGMTQ) != 0) {
282#if VERBOSE > SHOW_ERROR_MESSAGES
283 DEBUG(SHOW_TRACING,
284 "Received frame in Management Queue\n");
285#endif
286 islpci_mgt_receive(ndev);
287
288 islpci_mgt_cleanup_transmit(ndev);
289
290 /* Refill slots in receive queue */
291 islpci_mgmt_rx_fill(ndev);
292
293 /* no need to trigger the device, next
294 islpci_mgt_transaction does it */
295 }
296
297 while (isl38xx_in_queue(priv->control_block,
298 ISL38XX_CB_RX_DATA_LQ) != 0) {
299#if VERBOSE > SHOW_ERROR_MESSAGES
300 DEBUG(SHOW_TRACING,
301 "Received frame in Data Low Queue \n");
302#endif
303 islpci_eth_receive(priv);
304 }
305
306 /* check whether the data transmit queues were full */
307 if (priv->data_low_tx_full) {
308 /* check whether the transmit is not full anymore */
309 if (ISL38XX_CB_TX_QSIZE -
310 isl38xx_in_queue(priv->control_block,
311 ISL38XX_CB_TX_DATA_LQ) >=
312 ISL38XX_MIN_QTHRESHOLD) {
313 /* nope, the driver is ready for more network frames */
314 netif_wake_queue(priv->ndev);
315
316 /* reset the full flag */
317 priv->data_low_tx_full = 0;
318 }
319 }
320 }
321
322 if (reg & ISL38XX_INT_IDENT_INIT) {
323 /* Device has been initialized */
324#if VERBOSE > SHOW_ERROR_MESSAGES
325 DEBUG(SHOW_TRACING,
326 "IRQ: Init flag, device initialized \n");
327#endif
328 wake_up(&priv->reset_done);
329 }
330
331 if (reg & ISL38XX_INT_IDENT_SLEEP) {
332 /* Device intends to move to powersave state */
333#if VERBOSE > SHOW_ERROR_MESSAGES
334 DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");
335#endif
336 isl38xx_handle_sleep_request(priv->control_block,
337 &powerstate,
338 priv->device_base);
339 }
340
341 if (reg & ISL38XX_INT_IDENT_WAKEUP) {
342 /* Device has been woken up to active state */
343#if VERBOSE > SHOW_ERROR_MESSAGES
344 DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");
345#endif
346
347 isl38xx_handle_wakeup(priv->control_block,
348 &powerstate, priv->device_base);
349 }
350 } else {
351#if VERBOSE > SHOW_ERROR_MESSAGES
352 DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");
353#endif
354 spin_unlock(&priv->slock);
355 return IRQ_NONE;
356 }
357
358 /* sleep -> ready */
359 if (islpci_get_state(priv) == PRV_STATE_SLEEP
360 && powerstate == ISL38XX_PSM_ACTIVE_STATE)
361 islpci_set_state(priv, PRV_STATE_READY);
362
363 /* !sleep -> sleep */
364 if (islpci_get_state(priv) != PRV_STATE_SLEEP
365 && powerstate == ISL38XX_PSM_POWERSAVE_STATE)
366 islpci_set_state(priv, PRV_STATE_SLEEP);
367
368 /* unlock the interrupt handler */
369 spin_unlock(&priv->slock);
370
371 return IRQ_HANDLED;
372}
373
374/******************************************************************************
375 Network Interface Control & Statistical functions
376******************************************************************************/
377static int
378islpci_open(struct net_device *ndev)
379{
380 u32 rc;
381 islpci_private *priv = netdev_priv(ndev);
382
383 /* reset data structures, upload firmware and reset device */
384 rc = islpci_reset(priv,1);
385 if (rc) {
386 prism54_bring_down(priv);
387 return rc; /* Returns informative message */
388 }
389
390 netif_start_queue(ndev);
391/* netif_mark_up( ndev ); */
392
393 return 0;
394}
395
396static int
397islpci_close(struct net_device *ndev)
398{
399 islpci_private *priv = netdev_priv(ndev);
400
401 printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name);
402
403 netif_stop_queue(ndev);
404
405 return prism54_bring_down(priv);
406}
407
408static int
409prism54_bring_down(islpci_private *priv)
410{
411 void __iomem *device_base = priv->device_base;
412 u32 reg;
413 /* we are going to shutdown the device */
414 islpci_set_state(priv, PRV_STATE_PREBOOT);
415
416 /* disable all device interrupts in case they weren't */
417 isl38xx_disable_interrupts(priv->device_base);
418
419 /* For safety reasons, we may want to ensure that no DMA transfer is
420 * currently in progress by emptying the TX and RX queues. */
421
422 /* wait until interrupts have finished executing on other CPUs */
423 synchronize_irq(priv->pdev->irq);
424
425 reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
426 reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT);
427 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
428 wmb();
429 udelay(ISL38XX_WRITEIO_DELAY);
430
431 reg |= ISL38XX_CTRL_STAT_RESET;
432 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
433 wmb();
434 udelay(ISL38XX_WRITEIO_DELAY);
435
436 /* clear the Reset bit */
437 reg &= ~ISL38XX_CTRL_STAT_RESET;
438 writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
439 wmb();
440
441 /* wait a while for the device to reset */
442 set_current_state(TASK_UNINTERRUPTIBLE);
443 schedule_timeout(50*HZ/1000);
444
445 return 0;
446}
447
448static int
449islpci_upload_fw(islpci_private *priv)
450{
451 islpci_state_t old_state;
452 u32 rc;
453
454 old_state = islpci_set_state(priv, PRV_STATE_BOOT);
455
456 printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name);
457
458 rc = isl_upload_firmware(priv);
459 if (rc) {
460 /* error uploading the firmware */
461 printk(KERN_ERR "%s: could not upload firmware ('%s')\n",
462 priv->ndev->name, priv->firmware);
463
464 islpci_set_state(priv, old_state);
465 return rc;
466 }
467
468 printk(KERN_DEBUG "%s: firmware upload complete\n",
469 priv->ndev->name);
470
471 islpci_set_state(priv, PRV_STATE_POSTBOOT);
472
473 return 0;
474}
475
476static int
477islpci_reset_if(islpci_private *priv)
478{
479 long remaining;
480 int result = -ETIME;
481 int count;
482
483 DEFINE_WAIT(wait);
484 prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE);
485
486 /* now the last step is to reset the interface */
487 isl38xx_interface_reset(priv->device_base, priv->device_host_address);
488 islpci_set_state(priv, PRV_STATE_PREINIT);
489
490 for(count = 0; count < 2 && result; count++) {
491 /* The software reset acknowledge needs about 220 msec here.
492 * Be conservative and wait for up to one second. */
493
494 set_current_state(TASK_UNINTERRUPTIBLE);
495 remaining = schedule_timeout(HZ);
496
497 if(remaining > 0) {
498 result = 0;
499 break;
500 }
501
502 /* If we're here it's because our IRQ hasn't yet gone through.
503 * Retry a bit more...
504 */
505 printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n",
506 priv->ndev->name);
507 }
508
509 finish_wait(&priv->reset_done, &wait);
510
511 if (result) {
512 printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name);
513 return result;
514 }
515
516 islpci_set_state(priv, PRV_STATE_INIT);
517
518 /* Now that the device is 100% up, let's allow
519 * for the other interrupts --
520 * NOTE: this is not *yet* true since we've only allowed the
521 * INIT interrupt on the IRQ line. We can perhaps poll
522 * the IRQ line until we know for sure the reset went through */
523 isl38xx_enable_common_interrupts(priv->device_base);
524
525 down_write(&priv->mib_sem);
526 result = mgt_commit(priv);
527 if (result) {
528 printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name);
529 up_write(&priv->mib_sem);
530 return result;
531 }
532 up_write(&priv->mib_sem);
533
534 islpci_set_state(priv, PRV_STATE_READY);
535
536 printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name);
537 return 0;
538}
539
540int
541islpci_reset(islpci_private *priv, int reload_firmware)
542{
543 isl38xx_control_block *cb = /* volatile not needed */
544 (isl38xx_control_block *) priv->control_block;
545 unsigned counter;
546 int rc;
547
548 if (reload_firmware)
549 islpci_set_state(priv, PRV_STATE_PREBOOT);
550 else
551 islpci_set_state(priv, PRV_STATE_POSTBOOT);
552
553 printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name);
554
555 /* disable all device interrupts in case they weren't */
556 isl38xx_disable_interrupts(priv->device_base);
557
558 /* flush all management queues */
559 priv->index_mgmt_tx = 0;
560 priv->index_mgmt_rx = 0;
561
562 /* clear the indexes in the frame pointer */
563 for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) {
564 cb->driver_curr_frag[counter] = cpu_to_le32(0);
565 cb->device_curr_frag[counter] = cpu_to_le32(0);
566 }
567
568 /* reset the mgmt receive queue */
569 for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) {
570 isl38xx_fragment *frag = &cb->rx_data_mgmt[counter];
571 frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
572 frag->flags = 0;
573 frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr);
574 }
575
576 for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
577 cb->rx_data_low[counter].address =
578 cpu_to_le32((u32) priv->pci_map_rx_address[counter]);
579 }
580
581 /* since the receive queues are filled with empty fragments, now we can
582 * set the corresponding indexes in the Control Block */
583 priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] =
584 cpu_to_le32(ISL38XX_CB_RX_QSIZE);
585 priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] =
586 cpu_to_le32(ISL38XX_CB_MGMT_QSIZE);
587
588 /* reset the remaining real index registers and full flags */
589 priv->free_data_rx = 0;
590 priv->free_data_tx = 0;
591 priv->data_low_tx_full = 0;
592
593 if (reload_firmware) { /* Should we load the firmware ? */
594 /* now that the data structures are cleaned up, upload
595 * firmware and reset interface */
596 rc = islpci_upload_fw(priv);
597 if (rc) {
598 printk(KERN_ERR "%s: islpci_reset: failure\n",
599 priv->ndev->name);
600 return rc;
601 }
602 }
603
604 /* finally reset interface */
605 rc = islpci_reset_if(priv);
606 if (rc)
607 printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
608 return rc;
609}
610
611static struct net_device_stats *
612islpci_statistics(struct net_device *ndev)
613{
614 islpci_private *priv = netdev_priv(ndev);
615
616#if VERBOSE > SHOW_ERROR_MESSAGES
617 DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n");
618#endif
619
620 return &priv->statistics;
621}
622
623/******************************************************************************
624 Network device configuration functions
625******************************************************************************/
626static int
627islpci_alloc_memory(islpci_private *priv)
628{
629 int counter;
630
631#if VERBOSE > SHOW_ERROR_MESSAGES
632 printk(KERN_DEBUG "islpci_alloc_memory\n");
633#endif
634
635 /* remap the PCI device base address to accessable */
636 if (!(priv->device_base =
637 ioremap(pci_resource_start(priv->pdev, 0),
638 ISL38XX_PCI_MEM_SIZE))) {
639 /* error in remapping the PCI device memory address range */
640 printk(KERN_ERR "PCI memory remapping failed \n");
641 return -1;
642 }
643
644 /* memory layout for consistent DMA region:
645 *
646 * Area 1: Control Block for the device interface
647 * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that
648 * the number of supported stations in the AP determines the minimal
649 * size of the buffer !
650 */
651
652 /* perform the allocation */
653 priv->driver_mem_address = pci_alloc_consistent(priv->pdev,
654 HOST_MEM_BLOCK,
655 &priv->
656 device_host_address);
657
658 if (!priv->driver_mem_address) {
659 /* error allocating the block of PCI memory */
660 printk(KERN_ERR "%s: could not allocate DMA memory, aborting!",
661 "prism54");
662 return -1;
663 }
664
665 /* assign the Control Block to the first address of the allocated area */
666 priv->control_block =
667 (isl38xx_control_block *) priv->driver_mem_address;
668
669 /* set the Power Save Buffer pointer directly behind the CB */
670 priv->device_psm_buffer =
671 priv->device_host_address + CONTROL_BLOCK_SIZE;
672
673 /* make sure all buffer pointers are initialized */
674 for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) {
675 priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0);
676 priv->control_block->device_curr_frag[counter] = cpu_to_le32(0);
677 }
678
679 priv->index_mgmt_rx = 0;
680 memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx));
681 memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx));
682
683 /* allocate rx queue for management frames */
684 if (islpci_mgmt_rx_fill(priv->ndev) < 0)
685 goto out_free;
686
687 /* now get the data rx skb's */
688 memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx));
689 memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address));
690
691 for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
692 struct sk_buff *skb;
693
694 /* allocate an sk_buff for received data frames storage
695 * each frame on receive size consists of 1 fragment
696 * include any required allignment operations */
697 if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) {
698 /* error allocating an sk_buff structure elements */
699 printk(KERN_ERR "Error allocating skb.\n");
700 skb = NULL;
701 goto out_free;
702 }
703 skb_reserve(skb, (4 - (long) skb->data) & 0x03);
704 /* add the new allocated sk_buff to the buffer array */
705 priv->data_low_rx[counter] = skb;
706
707 /* map the allocated skb data area to pci */
708 priv->pci_map_rx_address[counter] =
709 pci_map_single(priv->pdev, (void *) skb->data,
710 MAX_FRAGMENT_SIZE_RX + 2,
711 PCI_DMA_FROMDEVICE);
712 if (!priv->pci_map_rx_address[counter]) {
713 /* error mapping the buffer to device
714 accessable memory address */
715 printk(KERN_ERR "failed to map skb DMA'able\n");
716 goto out_free;
717 }
718 }
719
720 prism54_acl_init(&priv->acl);
721 prism54_wpa_ie_init(priv);
722 if (mgt_init(priv))
723 goto out_free;
724
725 return 0;
726 out_free:
727 islpci_free_memory(priv);
728 return -1;
729}
730
731int
732islpci_free_memory(islpci_private *priv)
733{
734 int counter;
735
736 if (priv->device_base)
737 iounmap(priv->device_base);
738 priv->device_base = NULL;
739
740 /* free consistent DMA area... */
741 if (priv->driver_mem_address)
742 pci_free_consistent(priv->pdev, HOST_MEM_BLOCK,
743 priv->driver_mem_address,
744 priv->device_host_address);
745
746 /* clear some dangling pointers */
747 priv->driver_mem_address = NULL;
748 priv->device_host_address = 0;
749 priv->device_psm_buffer = 0;
750 priv->control_block = NULL;
751
752 /* clean up mgmt rx buffers */
753 for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) {
754 struct islpci_membuf *buf = &priv->mgmt_rx[counter];
755 if (buf->pci_addr)
756 pci_unmap_single(priv->pdev, buf->pci_addr,
757 buf->size, PCI_DMA_FROMDEVICE);
758 buf->pci_addr = 0;
759 if (buf->mem)
760 kfree(buf->mem);
761 buf->size = 0;
762 buf->mem = NULL;
763 }
764
765 /* clean up data rx buffers */
766 for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
767 if (priv->pci_map_rx_address[counter])
768 pci_unmap_single(priv->pdev,
769 priv->pci_map_rx_address[counter],
770 MAX_FRAGMENT_SIZE_RX + 2,
771 PCI_DMA_FROMDEVICE);
772 priv->pci_map_rx_address[counter] = 0;
773
774 if (priv->data_low_rx[counter])
775 dev_kfree_skb(priv->data_low_rx[counter]);
776 priv->data_low_rx[counter] = NULL;
777 }
778
779 /* Free the acces control list and the WPA list */
780 prism54_acl_clean(&priv->acl);
781 prism54_wpa_ie_clean(priv);
782 mgt_clean(priv);
783
784 return 0;
785}
786
787#if 0
788static void
789islpci_set_multicast_list(struct net_device *dev)
790{
791 /* put device into promisc mode and let network layer handle it */
792}
793#endif
794
795struct net_device *
796islpci_setup(struct pci_dev *pdev)
797{
798 islpci_private *priv;
799 struct net_device *ndev = alloc_etherdev(sizeof (islpci_private));
800
801 if (!ndev)
802 return ndev;
803
804 SET_MODULE_OWNER(ndev);
805 pci_set_drvdata(pdev, ndev);
806#if defined(SET_NETDEV_DEV)
807 SET_NETDEV_DEV(ndev, &pdev->dev);
808#endif
809
810 /* setup the structure members */
811 ndev->base_addr = pci_resource_start(pdev, 0);
812 ndev->irq = pdev->irq;
813
814 /* initialize the function pointers */
815 ndev->open = &islpci_open;
816 ndev->stop = &islpci_close;
817 ndev->get_stats = &islpci_statistics;
818 ndev->get_wireless_stats = &prism54_get_wireless_stats;
819 ndev->do_ioctl = &prism54_ioctl;
820 ndev->wireless_handlers =
821 (struct iw_handler_def *) &prism54_handler_def;
822
823 ndev->hard_start_xmit = &islpci_eth_transmit;
824 /* ndev->set_multicast_list = &islpci_set_multicast_list; */
825 ndev->addr_len = ETH_ALEN;
826 ndev->set_mac_address = &prism54_set_mac_address;
827 /* Get a non-zero dummy MAC address for nameif. Jean II */
828 memcpy(ndev->dev_addr, dummy_mac, 6);
829
830#ifdef HAVE_TX_TIMEOUT
831 ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT;
832 ndev->tx_timeout = &islpci_eth_tx_timeout;
833#endif
834
835 /* allocate a private device structure to the network device */
836 priv = netdev_priv(ndev);
837 priv->ndev = ndev;
838 priv->pdev = pdev;
839 priv->monitor_type = ARPHRD_IEEE80211;
840 priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
841 priv->monitor_type : ARPHRD_ETHER;
842
843#if WIRELESS_EXT > 16
844 /* Add pointers to enable iwspy support. */
845 priv->wireless_data.spy_data = &priv->spy_data;
846 ndev->wireless_data = &priv->wireless_data;
847#endif /* WIRELESS_EXT > 16 */
848
849 /* save the start and end address of the PCI memory area */
850 ndev->mem_start = (unsigned long) priv->device_base;
851 ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE;
852
853#if VERBOSE > SHOW_ERROR_MESSAGES
854 DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base);
855#endif
856
857 init_waitqueue_head(&priv->reset_done);
858
859 /* init the queue read locks, process wait counter */
860 sema_init(&priv->mgmt_sem, 1);
861 priv->mgmt_received = NULL;
862 init_waitqueue_head(&priv->mgmt_wqueue);
863 sema_init(&priv->stats_sem, 1);
864 spin_lock_init(&priv->slock);
865
866 /* init state machine with off#1 state */
867 priv->state = PRV_STATE_OFF;
868 priv->state_off = 1;
869
870 /* initialize workqueue's */
871 INIT_WORK(&priv->stats_work,
872 (void (*)(void *)) prism54_update_stats, priv);
873 priv->stats_timestamp = 0;
874
875 INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv);
876 priv->reset_task_pending = 0;
877
878 /* allocate various memory areas */
879 if (islpci_alloc_memory(priv))
880 goto do_free_netdev;
881
882 /* select the firmware file depending on the device id */
883 switch (pdev->device) {
884 case 0x3877:
885 strcpy(priv->firmware, ISL3877_IMAGE_FILE);
886 break;
887
888 case 0x3886:
889 strcpy(priv->firmware, ISL3886_IMAGE_FILE);
890 break;
891
892 default:
893 strcpy(priv->firmware, ISL3890_IMAGE_FILE);
894 break;
895 }
896
897 if (register_netdev(ndev)) {
898 DEBUG(SHOW_ERROR_MESSAGES,
899 "ERROR: register_netdev() failed \n");
900 goto do_islpci_free_memory;
901 }
902
903 return ndev;
904
905 do_islpci_free_memory:
906 islpci_free_memory(priv);
907 do_free_netdev:
908 pci_set_drvdata(pdev, NULL);
909 free_netdev(ndev);
910 priv = NULL;
911 return NULL;
912}
913
914islpci_state_t
915islpci_set_state(islpci_private *priv, islpci_state_t new_state)
916{
917 islpci_state_t old_state;
918
919 /* lock */
920 old_state = priv->state;
921
922 /* this means either a race condition or some serious error in
923 * the driver code */
924 switch (new_state) {
925 case PRV_STATE_OFF:
926 priv->state_off++;
927 default:
928 priv->state = new_state;
929 break;
930
931 case PRV_STATE_PREBOOT:
932 /* there are actually many off-states, enumerated by
933 * state_off */
934 if (old_state == PRV_STATE_OFF)
935 priv->state_off--;
936
937 /* only if hw_unavailable is zero now it means we either
938 * were in off#1 state, or came here from
939 * somewhere else */
940 if (!priv->state_off)
941 priv->state = new_state;
942 break;
943 };
944#if 0
945 printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n",
946 priv->ndev->name, old_state, new_state, priv->state_off);
947#endif
948
949 /* invariants */
950 BUG_ON(priv->state_off < 0);
951 BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF));
952 BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF));
953
954 /* unlock */
955 return old_state;
956}
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
new file mode 100644
index 000000000000..32a1019f1b36
--- /dev/null
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -0,0 +1,216 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
5 * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
6 * Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#ifndef _ISLPCI_DEV_H
24#define _ISLPCI_DEV_H
25
26#include <linux/version.h>
27#include <linux/netdevice.h>
28#include <linux/wireless.h>
29#include <net/iw_handler.h>
30#include <linux/list.h>
31
32#include "isl_38xx.h"
33#include "isl_oid.h"
34#include "islpci_mgt.h"
35
36/* some states might not be superflous and may be removed when
37 design is finalized (hvr) */
38typedef enum {
39 PRV_STATE_OFF = 0, /* this means hw_unavailable is != 0 */
40 PRV_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */
41 PRV_STATE_BOOT, /* boot state (fw upload, run fw) */
42 PRV_STATE_POSTBOOT, /* after boot state, need reset now */
43 PRV_STATE_PREINIT, /* pre-init state */
44 PRV_STATE_INIT, /* init state (restore MIB backup to device) */
45 PRV_STATE_READY, /* driver&device are in operational state */
46 PRV_STATE_SLEEP /* device in sleep mode */
47} islpci_state_t;
48
49/* ACL using MAC address */
50struct mac_entry {
51 struct list_head _list;
52 char addr[ETH_ALEN];
53};
54
55struct islpci_acl {
56 enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy;
57 struct list_head mac_list; /* a list of mac_entry */
58 int size; /* size of queue */
59 struct semaphore sem; /* accessed in ioctls and trap_work */
60};
61
62struct islpci_membuf {
63 int size; /* size of memory */
64 void *mem; /* address of memory as seen by CPU */
65 dma_addr_t pci_addr; /* address of memory as seen by device */
66};
67
68#define MAX_BSS_WPA_IE_COUNT 64
69#define MAX_WPA_IE_LEN 64
70struct islpci_bss_wpa_ie {
71 struct list_head list;
72 unsigned long last_update;
73 u8 bssid[ETH_ALEN];
74 u8 wpa_ie[MAX_WPA_IE_LEN];
75 size_t wpa_ie_len;
76
77};
78
79typedef struct {
80 spinlock_t slock; /* generic spinlock; */
81
82 u32 priv_oid;
83
84 /* our mib cache */
85 u32 iw_mode;
86 struct rw_semaphore mib_sem;
87 void **mib;
88 char nickname[IW_ESSID_MAX_SIZE+1];
89
90 /* Take care of the wireless stats */
91 struct work_struct stats_work;
92 struct semaphore stats_sem;
93 /* remember when we last updated the stats */
94 unsigned long stats_timestamp;
95 /* The first is accessed under semaphore locking.
96 * The second is the clean one we return to iwconfig.
97 */
98 struct iw_statistics local_iwstatistics;
99 struct iw_statistics iwstatistics;
100
101 struct iw_spy_data spy_data; /* iwspy support */
102
103#if WIRELESS_EXT > 16
104 struct iw_public_data wireless_data;
105#endif /* WIRELESS_EXT > 16 */
106
107 int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
108
109 struct islpci_acl acl;
110
111 /* PCI bus allocation & configuration members */
112 struct pci_dev *pdev; /* PCI structure information */
113 char firmware[33];
114
115 void __iomem *device_base; /* ioremapped device base address */
116
117 /* consistent DMA region */
118 void *driver_mem_address; /* base DMA address */
119 dma_addr_t device_host_address; /* base DMA address (bus address) */
120 dma_addr_t device_psm_buffer; /* host memory for PSM buffering (bus address) */
121
122 /* our network_device structure */
123 struct net_device *ndev;
124
125 /* device queue interface members */
126 struct isl38xx_cb *control_block; /* device control block
127 (== driver_mem_address!) */
128
129 /* Each queue has three indexes:
130 * free/index_mgmt/data_rx/tx (called index, see below),
131 * driver_curr_frag, and device_curr_frag (in the control block)
132 * All indexes are ever-increasing, but interpreted modulo the
133 * device queue size when used.
134 * index <= device_curr_frag <= driver_curr_frag at all times
135 * For rx queues, [index, device_curr_frag) contains fragments
136 * that the interrupt processing needs to handle (owned by driver).
137 * [device_curr_frag, driver_curr_frag) is the free space in the
138 * rx queue, waiting for data (owned by device). The driver
139 * increments driver_curr_frag to indicate to the device that more
140 * buffers are available.
141 * If device_curr_frag == driver_curr_frag, no more rx buffers are
142 * available, and the rx DMA engine of the device is halted.
143 * For tx queues, [index, device_curr_frag) contains fragments
144 * where tx is done; they need to be freed (owned by driver).
145 * [device_curr_frag, driver_curr_frag) contains the frames
146 * that are being transferred (owned by device). The driver
147 * increments driver_curr_frag to indicate that more tx work
148 * needs to be done.
149 */
150 u32 index_mgmt_rx; /* real index mgmt rx queue */
151 u32 index_mgmt_tx; /* read index mgmt tx queue */
152 u32 free_data_rx; /* free pointer data rx queue */
153 u32 free_data_tx; /* free pointer data tx queue */
154 u32 data_low_tx_full; /* full detected flag */
155
156 /* frame memory buffers for the device queues */
157 struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE];
158 struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE];
159 struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE];
160 struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE];
161 dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE];
162 dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE];
163
164 /* driver network interface members */
165 struct net_device_stats statistics;
166
167 /* wait for a reset interrupt */
168 wait_queue_head_t reset_done;
169
170 /* used by islpci_mgt_transaction */
171 struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */
172 struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */
173 wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */
174
175 /* state machine */
176 islpci_state_t state;
177 int state_off; /* enumeration of off-state, if 0 then
178 * we're not in any off-state */
179
180 /* WPA stuff */
181 int wpa; /* WPA mode enabled */
182 struct list_head bss_wpa_list;
183 int num_bss_wpa;
184 struct semaphore wpa_sem;
185
186 struct work_struct reset_task;
187 int reset_task_pending;
188} islpci_private;
189
190static inline islpci_state_t
191islpci_get_state(islpci_private *priv)
192{
193 /* lock */
194 return priv->state;
195 /* unlock */
196}
197
198islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state);
199
200#define ISLPCI_TX_TIMEOUT (2*HZ)
201
202irqreturn_t islpci_interrupt(int, void *, struct pt_regs *);
203
204int prism54_post_setup(islpci_private *, int);
205int islpci_reset(islpci_private *, int);
206
207static inline void
208islpci_trigger(islpci_private *priv)
209{
210 isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP,
211 priv->device_base);
212}
213
214int islpci_free_memory(islpci_private *);
215struct net_device *islpci_setup(struct pci_dev *);
216#endif /* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
new file mode 100644
index 000000000000..5952e9960499
--- /dev/null
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -0,0 +1,519 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20#include <linux/version.h>
21#include <linux/module.h>
22
23#include <linux/pci.h>
24#include <linux/delay.h>
25#include <linux/netdevice.h>
26#include <linux/etherdevice.h>
27#include <linux/if_arp.h>
28
29#include "prismcompat.h"
30#include "isl_38xx.h"
31#include "islpci_eth.h"
32#include "islpci_mgt.h"
33#include "oid_mgt.h"
34
35/******************************************************************************
36 Network Interface functions
37******************************************************************************/
38void
39islpci_eth_cleanup_transmit(islpci_private *priv,
40 isl38xx_control_block *control_block)
41{
42 struct sk_buff *skb;
43 u32 index;
44
45 /* compare the control block read pointer with the free pointer */
46 while (priv->free_data_tx !=
47 le32_to_cpu(control_block->
48 device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) {
49 /* read the index of the first fragment to be freed */
50 index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE;
51
52 /* check for holes in the arrays caused by multi fragment frames
53 * searching for the last fragment of a frame */
54 if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {
55 /* entry is the last fragment of a frame
56 * free the skb structure and unmap pci memory */
57 skb = priv->data_low_tx[index];
58
59#if VERBOSE > SHOW_ERROR_MESSAGES
60 DEBUG(SHOW_TRACING,
61 "cleanup skb %p skb->data %p skb->len %u truesize %u\n ",
62 skb, skb->data, skb->len, skb->truesize);
63#endif
64
65 pci_unmap_single(priv->pdev,
66 priv->pci_map_tx_address[index],
67 skb->len, PCI_DMA_TODEVICE);
68 dev_kfree_skb_irq(skb);
69 skb = NULL;
70 }
71 /* increment the free data low queue pointer */
72 priv->free_data_tx++;
73 }
74}
75
76int
77islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
78{
79 islpci_private *priv = netdev_priv(ndev);
80 isl38xx_control_block *cb = priv->control_block;
81 u32 index;
82 dma_addr_t pci_map_address;
83 int frame_size;
84 isl38xx_fragment *fragment;
85 int offset;
86 struct sk_buff *newskb;
87 int newskb_offset;
88 unsigned long flags;
89 unsigned char wds_mac[6];
90 u32 curr_frag;
91 int err = 0;
92
93#if VERBOSE > SHOW_ERROR_MESSAGES
94 DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");
95#endif
96
97 /* lock the driver code */
98 spin_lock_irqsave(&priv->slock, flags);
99
100 /* determine the amount of fragments needed to store the frame */
101
102 frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
103 if (init_wds)
104 frame_size += 6;
105
106 /* check whether the destination queue has enough fragments for the frame */
107 curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);
108 if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) {
109 printk(KERN_ERR "%s: transmit device queue full when awake\n",
110 ndev->name);
111 netif_stop_queue(ndev);
112
113 /* trigger the device */
114 isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE,
115 ISL38XX_DEV_INT_REG);
116 udelay(ISL38XX_WRITEIO_DELAY);
117
118 err = -EBUSY;
119 goto drop_free;
120 }
121 /* Check alignment and WDS frame formatting. The start of the packet should
122 * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes
123 * and add WDS address information */
124 if (likely(((long) skb->data & 0x03) | init_wds)) {
125 /* get the number of bytes to add and re-allign */
126 offset = (4 - (long) skb->data) & 0x03;
127 offset += init_wds ? 6 : 0;
128
129 /* check whether the current skb can be used */
130 if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
131 unsigned char *src = skb->data;
132
133#if VERBOSE > SHOW_ERROR_MESSAGES
134 DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset,
135 init_wds);
136#endif
137
138 /* align the buffer on 4-byte boundary */
139 skb_reserve(skb, (4 - (long) skb->data) & 0x03);
140 if (init_wds) {
141 /* wds requires an additional address field of 6 bytes */
142 skb_put(skb, 6);
143#ifdef ISLPCI_ETH_DEBUG
144 printk("islpci_eth_transmit:wds_mac\n");
145#endif
146 memmove(skb->data + 6, src, skb->len);
147 memcpy(skb->data, wds_mac, 6);
148 } else {
149 memmove(skb->data, src, skb->len);
150 }
151
152#if VERBOSE > SHOW_ERROR_MESSAGES
153 DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,
154 src, skb->len);
155#endif
156 } else {
157 newskb =
158 dev_alloc_skb(init_wds ? skb->len + 6 : skb->len);
159 if (unlikely(newskb == NULL)) {
160 printk(KERN_ERR "%s: Cannot allocate skb\n",
161 ndev->name);
162 err = -ENOMEM;
163 goto drop_free;
164 }
165 newskb_offset = (4 - (long) newskb->data) & 0x03;
166
167 /* Check if newskb->data is aligned */
168 if (newskb_offset)
169 skb_reserve(newskb, newskb_offset);
170
171 skb_put(newskb, init_wds ? skb->len + 6 : skb->len);
172 if (init_wds) {
173 memcpy(newskb->data + 6, skb->data, skb->len);
174 memcpy(newskb->data, wds_mac, 6);
175#ifdef ISLPCI_ETH_DEBUG
176 printk("islpci_eth_transmit:wds_mac\n");
177#endif
178 } else
179 memcpy(newskb->data, skb->data, skb->len);
180
181#if VERBOSE > SHOW_ERROR_MESSAGES
182 DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n",
183 newskb->data, skb->data, skb->len, init_wds);
184#endif
185
186 newskb->dev = skb->dev;
187 dev_kfree_skb(skb);
188 skb = newskb;
189 }
190 }
191 /* display the buffer contents for debugging */
192#if VERBOSE > SHOW_ERROR_MESSAGES
193 DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data);
194 display_buffer((char *) skb->data, skb->len);
195#endif
196
197 /* map the skb buffer to pci memory for DMA operation */
198 pci_map_address = pci_map_single(priv->pdev,
199 (void *) skb->data, skb->len,
200 PCI_DMA_TODEVICE);
201 if (unlikely(pci_map_address == 0)) {
202 printk(KERN_WARNING "%s: cannot map buffer to PCI\n",
203 ndev->name);
204
205 err = -EIO;
206 goto drop_free;
207 }
208 /* Place the fragment in the control block structure. */
209 index = curr_frag % ISL38XX_CB_TX_QSIZE;
210 fragment = &cb->tx_data_low[index];
211
212 priv->pci_map_tx_address[index] = pci_map_address;
213 /* store the skb address for future freeing */
214 priv->data_low_tx[index] = skb;
215 /* set the proper fragment start address and size information */
216 fragment->size = cpu_to_le16(frame_size);
217 fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */
218 fragment->address = cpu_to_le32(pci_map_address);
219 curr_frag++;
220
221 /* The fragment address in the control block must have been
222 * written before announcing the frame buffer to device. */
223 wmb();
224 cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag);
225
226 if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD
227 > ISL38XX_CB_TX_QSIZE) {
228 /* stop sends from upper layers */
229 netif_stop_queue(ndev);
230
231 /* set the full flag for the transmission queue */
232 priv->data_low_tx_full = 1;
233 }
234
235 /* trigger the device */
236 islpci_trigger(priv);
237
238 /* unlock the driver code */
239 spin_unlock_irqrestore(&priv->slock, flags);
240
241 /* set the transmission time */
242 ndev->trans_start = jiffies;
243 priv->statistics.tx_packets++;
244 priv->statistics.tx_bytes += skb->len;
245
246 return 0;
247
248 drop_free:
249 /* free the skbuf structure before aborting */
250 dev_kfree_skb(skb);
251 skb = NULL;
252
253 priv->statistics.tx_dropped++;
254 spin_unlock_irqrestore(&priv->slock, flags);
255 return err;
256}
257
258static inline int
259islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
260{
261 /* The card reports full 802.11 packets but with a 20 bytes
262 * header and without the FCS. But there a is a bit that
263 * indicates if the packet is corrupted :-) */
264 struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data;
265 if (hdr->flags & 0x01)
266 /* This one is bad. Drop it ! */
267 return -1;
268 if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) {
269 struct avs_80211_1_header *avs;
270 /* extract the relevant data from the header */
271 u32 clock = le32_to_cpu(hdr->clock);
272 u8 rate = hdr->rate;
273 u16 freq = le16_to_cpu(hdr->freq);
274 u8 rssi = hdr->rssi;
275
276 skb_pull(*skb, sizeof (struct rfmon_header));
277
278 if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) {
279 struct sk_buff *newskb = skb_copy_expand(*skb,
280 sizeof (struct
281 avs_80211_1_header),
282 0, GFP_ATOMIC);
283 if (newskb) {
284 dev_kfree_skb_irq(*skb);
285 *skb = newskb;
286 } else
287 return -1;
288 /* This behavior is not very subtile... */
289 }
290
291 /* make room for the new header and fill it. */
292 avs =
293 (struct avs_80211_1_header *) skb_push(*skb,
294 sizeof (struct
295 avs_80211_1_header));
296
297 avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
298 avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
299 avs->mactime = cpu_to_be64(le64_to_cpu(clock));
300 avs->hosttime = cpu_to_be64(jiffies);
301 avs->phytype = cpu_to_be32(6); /*OFDM: 6 for (g), 8 for (a) */
302 avs->channel = cpu_to_be32(channel_of_freq(freq));
303 avs->datarate = cpu_to_be32(rate * 5);
304 avs->antenna = cpu_to_be32(0); /*unknown */
305 avs->priority = cpu_to_be32(0); /*unknown */
306 avs->ssi_type = cpu_to_be32(3); /*2: dBm, 3: raw RSSI */
307 avs->ssi_signal = cpu_to_be32(rssi & 0x7f);
308 avs->ssi_noise = cpu_to_be32(priv->local_iwstatistics.qual.noise); /*better than 'undefined', I assume */
309 avs->preamble = cpu_to_be32(0); /*unknown */
310 avs->encoding = cpu_to_be32(0); /*unknown */
311 } else
312 skb_pull(*skb, sizeof (struct rfmon_header));
313
314 (*skb)->protocol = htons(ETH_P_802_2);
315 (*skb)->mac.raw = (*skb)->data;
316 (*skb)->pkt_type = PACKET_OTHERHOST;
317
318 return 0;
319}
320
321int
322islpci_eth_receive(islpci_private *priv)
323{
324 struct net_device *ndev = priv->ndev;
325 isl38xx_control_block *control_block = priv->control_block;
326 struct sk_buff *skb;
327 u16 size;
328 u32 index, offset;
329 unsigned char *src;
330 int discard = 0;
331
332#if VERBOSE > SHOW_ERROR_MESSAGES
333 DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n");
334#endif
335
336 /* the device has written an Ethernet frame in the data area
337 * of the sk_buff without updating the structure, do it now */
338 index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE;
339 size = le16_to_cpu(control_block->rx_data_low[index].size);
340 skb = priv->data_low_rx[index];
341 offset = ((unsigned long)
342 le32_to_cpu(control_block->rx_data_low[index].address) -
343 (unsigned long) skb->data) & 3;
344
345#if VERBOSE > SHOW_ERROR_MESSAGES
346 DEBUG(SHOW_TRACING,
347 "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ",
348 control_block->rx_data_low[priv->free_data_rx].address, skb->data,
349 skb->len, offset, skb->truesize);
350#endif
351
352 /* delete the streaming DMA mapping before processing the skb */
353 pci_unmap_single(priv->pdev,
354 priv->pci_map_rx_address[index],
355 MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE);
356
357 /* update the skb structure and allign the buffer */
358 skb_put(skb, size);
359 if (offset) {
360 /* shift the buffer allocation offset bytes to get the right frame */
361 skb_pull(skb, 2);
362 skb_put(skb, 2);
363 }
364#if VERBOSE > SHOW_ERROR_MESSAGES
365 /* display the buffer contents for debugging */
366 DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
367 display_buffer((char *) skb->data, skb->len);
368#endif
369
370 /* check whether WDS is enabled and whether the data frame is a WDS frame */
371
372 if (init_wds) {
373 /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */
374 src = skb->data + 6;
375 memmove(skb->data, src, skb->len - 6);
376 skb_trim(skb, skb->len - 6);
377 }
378#if VERBOSE > SHOW_ERROR_MESSAGES
379 DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb);
380 DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len);
381
382 /* display the buffer contents for debugging */
383 DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
384 display_buffer((char *) skb->data, skb->len);
385#endif
386
387 /* do some additional sk_buff and network layer parameters */
388 skb->dev = ndev;
389
390 /* take care of monitor mode and spy monitoring. */
391 if (unlikely(priv->iw_mode == IW_MODE_MONITOR))
392 discard = islpci_monitor_rx(priv, &skb);
393 else {
394 if (unlikely(skb->data[2 * ETH_ALEN] == 0)) {
395 /* The packet has a rx_annex. Read it for spy monitoring, Then
396 * remove it, while keeping the 2 leading MAC addr.
397 */
398 struct iw_quality wstats;
399 struct rx_annex_header *annex =
400 (struct rx_annex_header *) skb->data;
401 wstats.level = annex->rfmon.rssi;
402 /* The noise value can be a bit outdated if nobody's
403 * reading wireless stats... */
404 wstats.noise = priv->local_iwstatistics.qual.noise;
405 wstats.qual = wstats.level - wstats.noise;
406 wstats.updated = 0x07;
407 /* Update spy records */
408 wireless_spy_update(ndev, annex->addr2, &wstats);
409
410 memcpy(skb->data + sizeof (struct rfmon_header),
411 skb->data, 2 * ETH_ALEN);
412 skb_pull(skb, sizeof (struct rfmon_header));
413 }
414 skb->protocol = eth_type_trans(skb, ndev);
415 }
416 skb->ip_summed = CHECKSUM_NONE;
417 priv->statistics.rx_packets++;
418 priv->statistics.rx_bytes += size;
419
420 /* deliver the skb to the network layer */
421#ifdef ISLPCI_ETH_DEBUG
422 printk
423 ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
424 skb->data[0], skb->data[1], skb->data[2], skb->data[3],
425 skb->data[4], skb->data[5]);
426#endif
427 if (unlikely(discard)) {
428 dev_kfree_skb_irq(skb);
429 skb = NULL;
430 } else
431 netif_rx(skb);
432
433 /* increment the read index for the rx data low queue */
434 priv->free_data_rx++;
435
436 /* add one or more sk_buff structures */
437 while (index =
438 le32_to_cpu(control_block->
439 driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]),
440 index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) {
441 /* allocate an sk_buff for received data frames storage
442 * include any required allignment operations */
443 skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2);
444 if (unlikely(skb == NULL)) {
445 /* error allocating an sk_buff structure elements */
446 DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n");
447 break;
448 }
449 skb_reserve(skb, (4 - (long) skb->data) & 0x03);
450 /* store the new skb structure pointer */
451 index = index % ISL38XX_CB_RX_QSIZE;
452 priv->data_low_rx[index] = skb;
453
454#if VERBOSE > SHOW_ERROR_MESSAGES
455 DEBUG(SHOW_TRACING,
456 "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ",
457 skb, skb->data, skb->len, index, skb->truesize);
458#endif
459
460 /* set the streaming DMA mapping for proper PCI bus operation */
461 priv->pci_map_rx_address[index] =
462 pci_map_single(priv->pdev, (void *) skb->data,
463 MAX_FRAGMENT_SIZE_RX + 2,
464 PCI_DMA_FROMDEVICE);
465 if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) {
466 /* error mapping the buffer to device accessable memory address */
467 DEBUG(SHOW_ERROR_MESSAGES,
468 "Error mapping DMA address\n");
469
470 /* free the skbuf structure before aborting */
471 dev_kfree_skb_irq((struct sk_buff *) skb);
472 skb = NULL;
473 break;
474 }
475 /* update the fragment address */
476 control_block->rx_data_low[index].address = cpu_to_le32((u32)
477 priv->
478 pci_map_rx_address
479 [index]);
480 wmb();
481
482 /* increment the driver read pointer */
483 add_le32p((u32 *) &control_block->
484 driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1);
485 }
486
487 /* trigger the device */
488 islpci_trigger(priv);
489
490 return 0;
491}
492
493void
494islpci_do_reset_and_wake(void *data)
495{
496 islpci_private *priv = (islpci_private *) data;
497 islpci_reset(priv, 1);
498 netif_wake_queue(priv->ndev);
499 priv->reset_task_pending = 0;
500}
501
502void
503islpci_eth_tx_timeout(struct net_device *ndev)
504{
505 islpci_private *priv = netdev_priv(ndev);
506 struct net_device_stats *statistics = &priv->statistics;
507
508 /* increment the transmit error counter */
509 statistics->tx_errors++;
510
511 printk(KERN_WARNING "%s: tx_timeout", ndev->name);
512 if (!priv->reset_task_pending) {
513 priv->reset_task_pending = 1;
514 printk(", scheduling a reset");
515 netif_stop_queue(ndev);
516 schedule_work(&priv->reset_task);
517 }
518 printk("\n");
519}
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
new file mode 100644
index 000000000000..bc9d7a60b8d6
--- /dev/null
+++ b/drivers/net/wireless/prism54/islpci_eth.h
@@ -0,0 +1,73 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20#ifndef _ISLPCI_ETH_H
21#define _ISLPCI_ETH_H
22
23#include "isl_38xx.h"
24#include "islpci_dev.h"
25
26struct rfmon_header {
27 u16 unk0; /* = 0x0000 */
28 u16 length; /* = 0x1400 */
29 u32 clock; /* 1MHz clock */
30 u8 flags;
31 u8 unk1;
32 u8 rate;
33 u8 unk2;
34 u16 freq;
35 u16 unk3;
36 u8 rssi;
37 u8 padding[3];
38} __attribute__ ((packed));
39
40struct rx_annex_header {
41 u8 addr1[ETH_ALEN];
42 u8 addr2[ETH_ALEN];
43 struct rfmon_header rfmon;
44} __attribute__ ((packed));
45
46/* wlan-ng (and hopefully others) AVS header, version one. Fields in
47 * network byte order. */
48#define P80211CAPTURE_VERSION 0x80211001
49
50struct avs_80211_1_header {
51 uint32_t version;
52 uint32_t length;
53 uint64_t mactime;
54 uint64_t hosttime;
55 uint32_t phytype;
56 uint32_t channel;
57 uint32_t datarate;
58 uint32_t antenna;
59 uint32_t priority;
60 uint32_t ssi_type;
61 int32_t ssi_signal;
62 int32_t ssi_noise;
63 uint32_t preamble;
64 uint32_t encoding;
65};
66
67void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *);
68int islpci_eth_transmit(struct sk_buff *, struct net_device *);
69int islpci_eth_receive(islpci_private *);
70void islpci_eth_tx_timeout(struct net_device *);
71void islpci_do_reset_and_wake(void *data);
72
73#endif /* _ISL_GEN_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
new file mode 100644
index 000000000000..efd4d213ac3d
--- /dev/null
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -0,0 +1,339 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <linux/version.h>
22#include <linux/module.h>
23#include <linux/pci.h>
24#include <linux/delay.h>
25#include <linux/init.h> /* For __init, __exit */
26
27#include "prismcompat.h"
28#include "islpci_dev.h"
29#include "islpci_mgt.h" /* for pc_debug */
30#include "isl_oid.h"
31
32#define DRV_NAME "prism54"
33#define DRV_VERSION "1.2"
34
35MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
36MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
37MODULE_LICENSE("GPL");
38
39static int init_pcitm = 0;
40module_param(init_pcitm, int, 0);
41
42/* In this order: vendor, device, subvendor, subdevice, class, class_mask,
43 * driver_data
44 * If you have an update for this please contact prism54-devel@prism54.org
45 * The latest list can be found at http://prism54.org/supported_cards.php */
46static const struct pci_device_id prism54_id_tbl[] = {
47 /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
48 {
49 0x1260, 0x3890,
50 PCI_ANY_ID, PCI_ANY_ID,
51 0, 0, 0
52 },
53
54 /* 3COM 3CRWE154G72 Wireless LAN adapter */
55 {
56 0x10b7, 0x6001,
57 PCI_ANY_ID, PCI_ANY_ID,
58 0, 0, 0
59 },
60
61 /* Intersil PRISM Indigo Wireless LAN adapter */
62 {
63 0x1260, 0x3877,
64 PCI_ANY_ID, PCI_ANY_ID,
65 0, 0, 0
66 },
67
68 /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */
69 {
70 0x1260, 0x3886,
71 PCI_ANY_ID, PCI_ANY_ID,
72 0, 0, 0
73 },
74
75 /* End of list */
76 {0,0,0,0,0,0,0}
77};
78
79/* register the device with the Hotplug facilities of the kernel */
80MODULE_DEVICE_TABLE(pci, prism54_id_tbl);
81
82static int prism54_probe(struct pci_dev *, const struct pci_device_id *);
83static void prism54_remove(struct pci_dev *);
84static int prism54_suspend(struct pci_dev *, u32 state);
85static int prism54_resume(struct pci_dev *);
86
87static struct pci_driver prism54_driver = {
88 .name = DRV_NAME,
89 .id_table = prism54_id_tbl,
90 .probe = prism54_probe,
91 .remove = prism54_remove,
92 .suspend = prism54_suspend,
93 .resume = prism54_resume,
94 /* .enable_wake ; we don't support this yet */
95};
96
97/******************************************************************************
98 Module initialization functions
99******************************************************************************/
100
101int
102prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
103{
104 struct net_device *ndev;
105 u8 latency_tmr;
106 u32 mem_addr;
107 islpci_private *priv;
108 int rvalue;
109
110 /* Enable the pci device */
111 if (pci_enable_device(pdev)) {
112 printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME);
113 return -ENODEV;
114 }
115
116 /* check whether the latency timer is set correctly */
117 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr);
118#if VERBOSE > SHOW_ERROR_MESSAGES
119 DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr);
120#endif
121 if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) {
122 /* set the latency timer */
123 pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
124 PCIDEVICE_LATENCY_TIMER_VAL);
125 }
126
127 /* enable PCI DMA */
128 if (pci_set_dma_mask(pdev, 0xffffffff)) {
129 printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME);
130 goto do_pci_disable_device;
131 }
132
133 /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT)
134 * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT)
135 * The RETRY_TIMEOUT is used to set the number of retries that the core, as a
136 * Master, will perform before abandoning a cycle. The default value for
137 * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new
138 * devices. A write of zero to the RETRY_TIMEOUT register disables this
139 * function to allow use with any non-compliant legacy devices that may
140 * execute more retries.
141 *
142 * Writing zero to both these two registers will disable both timeouts and
143 * *can* solve problems caused by devices that are slow to respond.
144 * Make this configurable - MSW
145 */
146 if ( init_pcitm >= 0 ) {
147 pci_write_config_byte(pdev, 0x40, (u8)init_pcitm);
148 pci_write_config_byte(pdev, 0x41, (u8)init_pcitm);
149 } else {
150 printk(KERN_INFO "PCI TRDY/RETRY unchanged\n");
151 }
152
153 /* request the pci device I/O regions */
154 rvalue = pci_request_regions(pdev, DRV_NAME);
155 if (rvalue) {
156 printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n",
157 DRV_NAME, rvalue);
158 goto do_pci_disable_device;
159 }
160
161 /* check if the memory window is indeed set */
162 rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr);
163 if (rvalue || !mem_addr) {
164 printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n",
165 DRV_NAME);
166 goto do_pci_release_regions;
167 }
168
169 /* enable PCI bus-mastering */
170 DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME);
171 pci_set_master(pdev);
172
173 /* enable MWI */
174 pci_set_mwi(pdev);
175
176 /* setup the network device interface and its structure */
177 if (!(ndev = islpci_setup(pdev))) {
178 /* error configuring the driver as a network device */
179 printk(KERN_ERR "%s: could not configure network device\n",
180 DRV_NAME);
181 goto do_pci_release_regions;
182 }
183
184 priv = netdev_priv(ndev);
185 islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */
186
187 /* card is in unknown state yet, might have some interrupts pending */
188 isl38xx_disable_interrupts(priv->device_base);
189
190 /* request for the interrupt before uploading the firmware */
191 rvalue = request_irq(pdev->irq, &islpci_interrupt,
192 SA_SHIRQ, ndev->name, priv);
193
194 if (rvalue) {
195 /* error, could not hook the handler to the irq */
196 printk(KERN_ERR "%s: could not install IRQ handler\n",
197 ndev->name);
198 goto do_unregister_netdev;
199 }
200
201 /* firmware upload is triggered in islpci_open */
202
203 return 0;
204
205 do_unregister_netdev:
206 unregister_netdev(ndev);
207 islpci_free_memory(priv);
208 pci_set_drvdata(pdev, NULL);
209 free_netdev(ndev);
210 priv = NULL;
211 do_pci_release_regions:
212 pci_release_regions(pdev);
213 do_pci_disable_device:
214 pci_disable_device(pdev);
215 return -EIO;
216}
217
218/* set by cleanup_module */
219static volatile int __in_cleanup_module = 0;
220
221/* this one removes one(!!) instance only */
222void
223prism54_remove(struct pci_dev *pdev)
224{
225 struct net_device *ndev = pci_get_drvdata(pdev);
226 islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
227 BUG_ON(!priv);
228
229 if (!__in_cleanup_module) {
230 printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name);
231 islpci_set_state(priv, PRV_STATE_OFF);
232 }
233
234 printk(KERN_DEBUG "%s: removing device\n", ndev->name);
235
236 unregister_netdev(ndev);
237
238 /* free the interrupt request */
239
240 if (islpci_get_state(priv) != PRV_STATE_OFF) {
241 isl38xx_disable_interrupts(priv->device_base);
242 islpci_set_state(priv, PRV_STATE_OFF);
243 /* This bellow causes a lockup at rmmod time. It might be
244 * because some interrupts still linger after rmmod time,
245 * see bug #17 */
246 /* pci_set_power_state(pdev, 3);*/ /* try to power-off */
247 }
248
249 free_irq(pdev->irq, priv);
250
251 /* free the PCI memory and unmap the remapped page */
252 islpci_free_memory(priv);
253
254 pci_set_drvdata(pdev, NULL);
255 free_netdev(ndev);
256 priv = NULL;
257
258 pci_release_regions(pdev);
259
260 pci_disable_device(pdev);
261}
262
263int
264prism54_suspend(struct pci_dev *pdev, u32 state)
265{
266 struct net_device *ndev = pci_get_drvdata(pdev);
267 islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
268 BUG_ON(!priv);
269
270 printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
271 ndev->name, state);
272
273 pci_save_state(pdev);
274
275 /* tell the device not to trigger interrupts for now... */
276 isl38xx_disable_interrupts(priv->device_base);
277
278 /* from now on assume the hardware was already powered down
279 and don't touch it anymore */
280 islpci_set_state(priv, PRV_STATE_OFF);
281
282 netif_stop_queue(ndev);
283 netif_device_detach(ndev);
284
285 return 0;
286}
287
288int
289prism54_resume(struct pci_dev *pdev)
290{
291 struct net_device *ndev = pci_get_drvdata(pdev);
292 islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
293 BUG_ON(!priv);
294
295 pci_enable_device(pdev);
296
297 printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
298
299 pci_restore_state(pdev);
300
301 /* alright let's go into the PREBOOT state */
302 islpci_reset(priv, 1);
303
304 netif_device_attach(ndev);
305 netif_start_queue(ndev);
306
307 return 0;
308}
309
310static int __init
311prism54_module_init(void)
312{
313 printk(KERN_INFO "Loaded %s driver, version %s\n",
314 DRV_NAME, DRV_VERSION);
315
316 __bug_on_wrong_struct_sizes ();
317
318 return pci_module_init(&prism54_driver);
319}
320
321/* by the time prism54_module_exit() terminates, as a postcondition
322 * all instances will have been destroyed by calls to
323 * prism54_remove() */
324static void __exit
325prism54_module_exit(void)
326{
327 __in_cleanup_module = 1;
328
329 pci_unregister_driver(&prism54_driver);
330
331 printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME);
332
333 __in_cleanup_module = 0;
334}
335
336/* register entry points */
337module_init(prism54_module_init);
338module_exit(prism54_module_exit);
339/* EOF */
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
new file mode 100644
index 000000000000..b6f2e5a223be
--- /dev/null
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -0,0 +1,513 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * Copyright 2004 Jens Maurer <Jens.Maurer@gmx.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <linux/config.h>
22#include <linux/netdevice.h>
23#include <linux/module.h>
24#include <linux/pci.h>
25
26#include <asm/io.h>
27#include <asm/system.h>
28#include <linux/if_arp.h>
29
30#include "prismcompat.h"
31#include "isl_38xx.h"
32#include "islpci_mgt.h"
33#include "isl_oid.h" /* additional types and defs for isl38xx fw */
34#include "isl_ioctl.h"
35
36#include <net/iw_handler.h>
37
38/******************************************************************************
39 Global variable definition section
40******************************************************************************/
41int pc_debug = VERBOSE;
42module_param(pc_debug, int, 0);
43
44/******************************************************************************
45 Driver general functions
46******************************************************************************/
47#if VERBOSE > SHOW_ERROR_MESSAGES
48void
49display_buffer(char *buffer, int length)
50{
51 if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0)
52 return;
53
54 while (length > 0) {
55 printk("[%02x]", *buffer & 255);
56 length--;
57 buffer++;
58 }
59
60 printk("\n");
61}
62#endif
63
64/*****************************************************************************
65 Queue handling for management frames
66******************************************************************************/
67
68/*
69 * Helper function to create a PIMFOR management frame header.
70 */
71static void
72pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h)
73{
74 h->version = PIMFOR_VERSION;
75 h->operation = operation;
76 h->device_id = PIMFOR_DEV_ID_MHLI_MIB;
77 h->flags = 0;
78 h->oid = cpu_to_be32(oid);
79 h->length = cpu_to_be32(length);
80}
81
82/*
83 * Helper function to analyze a PIMFOR management frame header.
84 */
85static pimfor_header_t *
86pimfor_decode_header(void *data, int len)
87{
88 pimfor_header_t *h = data;
89
90 while ((void *) h < data + len) {
91 if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) {
92 le32_to_cpus(&h->oid);
93 le32_to_cpus(&h->length);
94 } else {
95 be32_to_cpus(&h->oid);
96 be32_to_cpus(&h->length);
97 }
98 if (h->oid != OID_INL_TUNNEL)
99 return h;
100 h++;
101 }
102 return NULL;
103}
104
105/*
106 * Fill the receive queue for management frames with fresh buffers.
107 */
108int
109islpci_mgmt_rx_fill(struct net_device *ndev)
110{
111 islpci_private *priv = netdev_priv(ndev);
112 isl38xx_control_block *cb = /* volatile not needed */
113 (isl38xx_control_block *) priv->control_block;
114 u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
115
116#if VERBOSE > SHOW_ERROR_MESSAGES
117 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n");
118#endif
119
120 while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) {
121 u32 index = curr % ISL38XX_CB_MGMT_QSIZE;
122 struct islpci_membuf *buf = &priv->mgmt_rx[index];
123 isl38xx_fragment *frag = &cb->rx_data_mgmt[index];
124
125 if (buf->mem == NULL) {
126 buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC);
127 if (!buf->mem) {
128 printk(KERN_WARNING
129 "Error allocating management frame.\n");
130 return -ENOMEM;
131 }
132 buf->size = MGMT_FRAME_SIZE;
133 }
134 if (buf->pci_addr == 0) {
135 buf->pci_addr = pci_map_single(priv->pdev, buf->mem,
136 MGMT_FRAME_SIZE,
137 PCI_DMA_FROMDEVICE);
138 if (!buf->pci_addr) {
139 printk(KERN_WARNING
140 "Failed to make memory DMA'able\n.");
141 return -ENOMEM;
142 }
143 }
144
145 /* be safe: always reset control block information */
146 frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
147 frag->flags = 0;
148 frag->address = cpu_to_le32(buf->pci_addr);
149 curr++;
150
151 /* The fragment address in the control block must have
152 * been written before announcing the frame buffer to
153 * device */
154 wmb();
155 cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr);
156 }
157 return 0;
158}
159
160/*
161 * Create and transmit a management frame using "operation" and "oid",
162 * with arguments data/length.
163 * We either return an error and free the frame, or we return 0 and
164 * islpci_mgt_cleanup_transmit() frees the frame in the tx-done
165 * interrupt.
166 */
167static int
168islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
169 void *data, int length)
170{
171 islpci_private *priv = netdev_priv(ndev);
172 isl38xx_control_block *cb =
173 (isl38xx_control_block *) priv->control_block;
174 void *p;
175 int err = -EINVAL;
176 unsigned long flags;
177 isl38xx_fragment *frag;
178 struct islpci_membuf buf;
179 u32 curr_frag;
180 int index;
181 int frag_len = length + PIMFOR_HEADER_SIZE;
182
183#if VERBOSE > SHOW_ERROR_MESSAGES
184 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n");
185#endif
186
187 if (frag_len > MGMT_FRAME_SIZE) {
188 printk(KERN_DEBUG "%s: mgmt frame too large %d\n",
189 ndev->name, frag_len);
190 goto error;
191 }
192
193 err = -ENOMEM;
194 p = buf.mem = kmalloc(frag_len, GFP_KERNEL);
195 if (!buf.mem) {
196 printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n",
197 ndev->name);
198 goto error;
199 }
200 buf.size = frag_len;
201
202 /* create the header directly in the fragment data area */
203 pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p);
204 p += PIMFOR_HEADER_SIZE;
205
206 if (data)
207 memcpy(p, data, length);
208 else
209 memset(p, 0, length);
210
211#if VERBOSE > SHOW_ERROR_MESSAGES
212 {
213 pimfor_header_t *h = buf.mem;
214 DEBUG(SHOW_PIMFOR_FRAMES,
215 "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n",
216 h->operation, oid, h->device_id, h->flags, length);
217
218 /* display the buffer contents for debugging */
219 display_buffer((char *) h, sizeof (pimfor_header_t));
220 display_buffer(p, length);
221 }
222#endif
223
224 err = -ENOMEM;
225 buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len,
226 PCI_DMA_TODEVICE);
227 if (!buf.pci_addr) {
228 printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n",
229 ndev->name);
230 goto error_free;
231 }
232
233 /* Protect the control block modifications against interrupts. */
234 spin_lock_irqsave(&priv->slock, flags);
235 curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]);
236 if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) {
237 printk(KERN_WARNING "%s: mgmt tx queue is still full\n",
238 ndev->name);
239 goto error_unlock;
240 }
241
242 /* commit the frame to the tx device queue */
243 index = curr_frag % ISL38XX_CB_MGMT_QSIZE;
244 priv->mgmt_tx[index] = buf;
245 frag = &cb->tx_data_mgmt[index];
246 frag->size = cpu_to_le16(frag_len);
247 frag->flags = 0; /* for any other than the last fragment, set to 1 */
248 frag->address = cpu_to_le32(buf.pci_addr);
249
250 /* The fragment address in the control block must have
251 * been written before announcing the frame buffer to
252 * device */
253 wmb();
254 cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1);
255 spin_unlock_irqrestore(&priv->slock, flags);
256
257 /* trigger the device */
258 islpci_trigger(priv);
259 return 0;
260
261 error_unlock:
262 spin_unlock_irqrestore(&priv->slock, flags);
263 error_free:
264 kfree(buf.mem);
265 error:
266 return err;
267}
268
269/*
270 * Receive a management frame from the device.
271 * This can be an arbitrary number of traps, and at most one response
272 * frame for a previous request sent via islpci_mgt_transmit().
273 */
274int
275islpci_mgt_receive(struct net_device *ndev)
276{
277 islpci_private *priv = netdev_priv(ndev);
278 isl38xx_control_block *cb =
279 (isl38xx_control_block *) priv->control_block;
280 u32 curr_frag;
281
282#if VERBOSE > SHOW_ERROR_MESSAGES
283 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n");
284#endif
285
286 /* Only once per interrupt, determine fragment range to
287 * process. This avoids an endless loop (i.e. lockup) if
288 * frames come in faster than we can process them. */
289 curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]);
290 barrier();
291
292 for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) {
293 pimfor_header_t *header;
294 u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE;
295 struct islpci_membuf *buf = &priv->mgmt_rx[index];
296 u16 frag_len;
297 int size;
298 struct islpci_mgmtframe *frame;
299
300 /* I have no idea (and no documentation) if flags != 0
301 * is possible. Drop the frame, reuse the buffer. */
302 if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) {
303 printk(KERN_WARNING "%s: unknown flags 0x%04x\n",
304 ndev->name,
305 le16_to_cpu(cb->rx_data_mgmt[index].flags));
306 continue;
307 }
308
309 /* The device only returns the size of the header(s) here. */
310 frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size);
311
312 /*
313 * We appear to have no way to tell the device the
314 * size of a receive buffer. Thus, if this check
315 * triggers, we likely have kernel heap corruption. */
316 if (frag_len > MGMT_FRAME_SIZE) {
317 printk(KERN_WARNING
318 "%s: Bogus packet size of %d (%#x).\n",
319 ndev->name, frag_len, frag_len);
320 frag_len = MGMT_FRAME_SIZE;
321 }
322
323 /* Ensure the results of device DMA are visible to the CPU. */
324 pci_dma_sync_single_for_cpu(priv->pdev, buf->pci_addr,
325 buf->size, PCI_DMA_FROMDEVICE);
326
327 /* Perform endianess conversion for PIMFOR header in-place. */
328 header = pimfor_decode_header(buf->mem, frag_len);
329 if (!header) {
330 printk(KERN_WARNING "%s: no PIMFOR header found\n",
331 ndev->name);
332 continue;
333 }
334
335 /* The device ID from the PIMFOR packet received from
336 * the MVC is always 0. We forward a sensible device_id.
337 * Not that anyone upstream would care... */
338 header->device_id = priv->ndev->ifindex;
339
340#if VERBOSE > SHOW_ERROR_MESSAGES
341 DEBUG(SHOW_PIMFOR_FRAMES,
342 "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n",
343 header->operation, header->oid, header->device_id,
344 header->flags, header->length);
345
346 /* display the buffer contents for debugging */
347 display_buffer((char *) header, PIMFOR_HEADER_SIZE);
348 display_buffer((char *) header + PIMFOR_HEADER_SIZE,
349 header->length);
350#endif
351
352 /* nobody sends these */
353 if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) {
354 printk(KERN_DEBUG
355 "%s: errant PIMFOR application frame\n",
356 ndev->name);
357 continue;
358 }
359
360 /* Determine frame size, skipping OID_INL_TUNNEL headers. */
361 size = PIMFOR_HEADER_SIZE + header->length;
362 frame = kmalloc(sizeof (struct islpci_mgmtframe) + size,
363 GFP_ATOMIC);
364 if (!frame) {
365 printk(KERN_WARNING
366 "%s: Out of memory, cannot handle oid 0x%08x\n",
367 ndev->name, header->oid);
368 continue;
369 }
370 frame->ndev = ndev;
371 memcpy(&frame->buf, header, size);
372 frame->header = (pimfor_header_t *) frame->buf;
373 frame->data = frame->buf + PIMFOR_HEADER_SIZE;
374
375#if VERBOSE > SHOW_ERROR_MESSAGES
376 DEBUG(SHOW_PIMFOR_FRAMES,
377 "frame: header: %p, data: %p, size: %d\n",
378 frame->header, frame->data, size);
379#endif
380
381 if (header->operation == PIMFOR_OP_TRAP) {
382#if VERBOSE > SHOW_ERROR_MESSAGES
383 printk(KERN_DEBUG
384 "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n",
385 header->oid, header->device_id, header->flags,
386 header->length);
387#endif
388
389 /* Create work to handle trap out of interrupt
390 * context. */
391 INIT_WORK(&frame->ws, prism54_process_trap, frame);
392 schedule_work(&frame->ws);
393
394 } else {
395 /* Signal the one waiting process that a response
396 * has been received. */
397 if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) {
398 printk(KERN_WARNING
399 "%s: mgmt response not collected\n",
400 ndev->name);
401 kfree(frame);
402 }
403#if VERBOSE > SHOW_ERROR_MESSAGES
404 DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n");
405#endif
406 wake_up(&priv->mgmt_wqueue);
407 }
408
409 }
410
411 return 0;
412}
413
414/*
415 * Cleanup the transmit queue by freeing all frames handled by the device.
416 */
417void
418islpci_mgt_cleanup_transmit(struct net_device *ndev)
419{
420 islpci_private *priv = netdev_priv(ndev);
421 isl38xx_control_block *cb = /* volatile not needed */
422 (isl38xx_control_block *) priv->control_block;
423 u32 curr_frag;
424
425#if VERBOSE > SHOW_ERROR_MESSAGES
426 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n");
427#endif
428
429 /* Only once per cleanup, determine fragment range to
430 * process. This avoids an endless loop (i.e. lockup) if
431 * the device became confused, incrementing device_curr_frag
432 * rapidly. */
433 curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]);
434 barrier();
435
436 for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) {
437 int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE;
438 struct islpci_membuf *buf = &priv->mgmt_tx[index];
439 pci_unmap_single(priv->pdev, buf->pci_addr, buf->size,
440 PCI_DMA_TODEVICE);
441 buf->pci_addr = 0;
442 kfree(buf->mem);
443 buf->mem = NULL;
444 buf->size = 0;
445 }
446}
447
448/*
449 * Perform one request-response transaction to the device.
450 */
451int
452islpci_mgt_transaction(struct net_device *ndev,
453 int operation, unsigned long oid,
454 void *senddata, int sendlen,
455 struct islpci_mgmtframe **recvframe)
456{
457 islpci_private *priv = netdev_priv(ndev);
458 const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000;
459 long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies;
460 int err;
461 DEFINE_WAIT(wait);
462
463 *recvframe = NULL;
464
465 if (down_interruptible(&priv->mgmt_sem))
466 return -ERESTARTSYS;
467
468 prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE);
469 err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen);
470 if (err)
471 goto out;
472
473 err = -ETIMEDOUT;
474 while (timeout_left > 0) {
475 int timeleft;
476 struct islpci_mgmtframe *frame;
477
478 set_current_state(TASK_UNINTERRUPTIBLE);
479 timeleft = schedule_timeout(wait_cycle_jiffies);
480 frame = xchg(&priv->mgmt_received, NULL);
481 if (frame) {
482 if (frame->header->oid == oid) {
483 *recvframe = frame;
484 err = 0;
485 goto out;
486 } else {
487 printk(KERN_DEBUG
488 "%s: expecting oid 0x%x, received 0x%x.\n",
489 ndev->name, (unsigned int) oid,
490 frame->header->oid);
491 kfree(frame);
492 frame = NULL;
493 }
494 }
495 if (timeleft == 0) {
496 printk(KERN_DEBUG
497 "%s: timeout waiting for mgmt response %lu, "
498 "triggering device\n",
499 ndev->name, timeout_left);
500 islpci_trigger(priv);
501 }
502 timeout_left += timeleft - wait_cycle_jiffies;
503 }
504 printk(KERN_WARNING "%s: timeout waiting for mgmt response\n",
505 ndev->name);
506
507 /* TODO: we should reset the device here */
508 out:
509 finish_wait(&priv->mgmt_wqueue, &wait);
510 up(&priv->mgmt_sem);
511 return err;
512}
513
diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
new file mode 100644
index 000000000000..2982be3363ef
--- /dev/null
+++ b/drivers/net/wireless/prism54/islpci_mgt.h
@@ -0,0 +1,145 @@
1/*
2 *
3 * Copyright (C) 2002 Intersil Americas Inc.
4 * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#ifndef _ISLPCI_MGT_H
22#define _ISLPCI_MGT_H
23
24#include <linux/wireless.h>
25#include <linux/skbuff.h>
26
27/*
28 * Function definitions
29 */
30
31#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0)
32#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args)
33
34extern int pc_debug;
35#define init_wds 0 /* help compiler optimize away dead code */
36
37
38/* General driver definitions */
39#define PCIDEVICE_LATENCY_TIMER_MIN 0x40
40#define PCIDEVICE_LATENCY_TIMER_VAL 0x50
41
42/* Debugging verbose definitions */
43#define SHOW_NOTHING 0x00 /* overrules everything */
44#define SHOW_ANYTHING 0xFF
45#define SHOW_ERROR_MESSAGES 0x01
46#define SHOW_TRAPS 0x02
47#define SHOW_FUNCTION_CALLS 0x04
48#define SHOW_TRACING 0x08
49#define SHOW_QUEUE_INDEXES 0x10
50#define SHOW_PIMFOR_FRAMES 0x20
51#define SHOW_BUFFER_CONTENTS 0x40
52#define VERBOSE 0x01
53
54/* Default card definitions */
55#define CARD_DEFAULT_CHANNEL 6
56#define CARD_DEFAULT_MODE INL_MODE_CLIENT
57#define CARD_DEFAULT_IW_MODE IW_MODE_INFRA
58#define CARD_DEFAULT_BSSTYPE DOT11_BSSTYPE_INFRA
59#define CARD_DEFAULT_CLIENT_SSID ""
60#define CARD_DEFAULT_AP_SSID "default"
61#define CARD_DEFAULT_KEY1 "default_key_1"
62#define CARD_DEFAULT_KEY2 "default_key_2"
63#define CARD_DEFAULT_KEY3 "default_key_3"
64#define CARD_DEFAULT_KEY4 "default_key_4"
65#define CARD_DEFAULT_WEP 0
66#define CARD_DEFAULT_FILTER 0
67#define CARD_DEFAULT_WDS 0
68#define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS
69#define CARD_DEFAULT_DOT1X 0
70#define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO
71#define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE
72#define CARD_DEFAULT_PROFILE DOT11_PROFILE_MIXED_G_WIFI
73#define CARD_DEFAULT_MAXFRAMEBURST DOT11_MAXFRAMEBURST_MIXED_SAFE
74
75/* PIMFOR package definitions */
76#define PIMFOR_ETHERTYPE 0x8828
77#define PIMFOR_HEADER_SIZE 12
78#define PIMFOR_VERSION 1
79#define PIMFOR_OP_GET 0
80#define PIMFOR_OP_SET 1
81#define PIMFOR_OP_RESPONSE 2
82#define PIMFOR_OP_ERROR 3
83#define PIMFOR_OP_TRAP 4
84#define PIMFOR_OP_RESERVED 5 /* till 255 */
85#define PIMFOR_DEV_ID_MHLI_MIB 0
86#define PIMFOR_FLAG_APPLIC_ORIGIN 0x01
87#define PIMFOR_FLAG_LITTLE_ENDIAN 0x02
88
89static inline void
90add_le32p(u32 * le_number, u32 add)
91{
92 *le_number = cpu_to_le32(le32_to_cpup(le_number) + add);
93}
94
95void display_buffer(char *, int);
96
97/*
98 * Type definition section
99 *
100 * the structure defines only the header allowing copyless
101 * frame handling
102 */
103typedef struct {
104 u8 version;
105 u8 operation;
106 u32 oid;
107 u8 device_id;
108 u8 flags;
109 u32 length;
110} __attribute__ ((packed))
111pimfor_header_t;
112
113/* A received and interrupt-processed management frame, either for
114 * schedule_work(prism54_process_trap) or for priv->mgmt_received,
115 * processed by islpci_mgt_transaction(). */
116struct islpci_mgmtframe {
117 struct net_device *ndev; /* pointer to network device */
118 pimfor_header_t *header; /* payload header, points into buf */
119 void *data; /* payload ex header, points into buf */
120 struct work_struct ws; /* argument for schedule_work() */
121 char buf[0]; /* fragment buffer */
122};
123
124int
125islpci_mgt_receive(struct net_device *ndev);
126
127int
128islpci_mgmt_rx_fill(struct net_device *ndev);
129
130void
131islpci_mgt_cleanup_transmit(struct net_device *ndev);
132
133int
134islpci_mgt_transaction(struct net_device *ndev,
135 int operation, unsigned long oid,
136 void *senddata, int sendlen,
137 struct islpci_mgmtframe **recvframe);
138
139static inline void
140islpci_mgt_release(struct islpci_mgmtframe *frame)
141{
142 kfree(frame);
143}
144
145#endif /* _ISLPCI_MGT_H */
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
new file mode 100644
index 000000000000..12123e24b113
--- /dev/null
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -0,0 +1,907 @@
1/*
2 * Copyright (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
18
19#include "prismcompat.h"
20#include "islpci_dev.h"
21#include "islpci_mgt.h"
22#include "isl_oid.h"
23#include "oid_mgt.h"
24#include "isl_ioctl.h"
25
26/* to convert between channel and freq */
27static const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432,
28 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484
29};
30
31int
32channel_of_freq(int f)
33{
34 int c = 0;
35
36 if ((f >= 2412) && (f <= 2484)) {
37 while ((c < 14) && (f != frequency_list_bg[c]))
38 c++;
39 return (c >= 14) ? 0 : ++c;
40 } else if ((f >= (int) 5000) && (f <= (int) 6000)) {
41 return ( (f - 5000) / 5 );
42 } else
43 return 0;
44}
45
46#define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t}
47#define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED)
48#define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32)
49#define OID_U32_C(name,oid) OID_STRUCT_C(name,oid,u32,OID_TYPE_U32)
50#define OID_STRUCT_MLME(name,oid) OID_STRUCT(name,oid,struct obj_mlme,OID_TYPE_MLME)
51#define OID_STRUCT_MLMEEX(name,oid) OID_STRUCT(name,oid,struct obj_mlmeex,OID_TYPE_MLMEEX)
52
53#define OID_UNKNOWN(name,oid) OID_STRUCT(name,oid,0,0)
54
55struct oid_t isl_oid[] = {
56 OID_STRUCT(GEN_OID_MACADDRESS, 0x00000000, u8[6], OID_TYPE_ADDR),
57 OID_U32(GEN_OID_LINKSTATE, 0x00000001),
58 OID_UNKNOWN(GEN_OID_WATCHDOG, 0x00000002),
59 OID_UNKNOWN(GEN_OID_MIBOP, 0x00000003),
60 OID_UNKNOWN(GEN_OID_OPTIONS, 0x00000004),
61 OID_UNKNOWN(GEN_OID_LEDCONFIG, 0x00000005),
62
63 /* 802.11 */
64 OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000),
65 OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_RAW),
66 OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid,
67 OID_TYPE_SSID),
68 OID_U32(DOT11_OID_STATE, 0x10000003),
69 OID_U32(DOT11_OID_AID, 0x10000004),
70 OID_STRUCT(DOT11_OID_COUNTRYSTRING, 0x10000005, u8[4], OID_TYPE_RAW),
71 OID_STRUCT_C(DOT11_OID_SSIDOVERRIDE, 0x10000006, struct obj_ssid,
72 OID_TYPE_SSID),
73
74 OID_U32(DOT11_OID_MEDIUMLIMIT, 0x11000000),
75 OID_U32_C(DOT11_OID_BEACONPERIOD, 0x11000001),
76 OID_U32(DOT11_OID_DTIMPERIOD, 0x11000002),
77 OID_U32(DOT11_OID_ATIMWINDOW, 0x11000003),
78 OID_U32(DOT11_OID_LISTENINTERVAL, 0x11000004),
79 OID_U32(DOT11_OID_CFPPERIOD, 0x11000005),
80 OID_U32(DOT11_OID_CFPDURATION, 0x11000006),
81
82 OID_U32_C(DOT11_OID_AUTHENABLE, 0x12000000),
83 OID_U32_C(DOT11_OID_PRIVACYINVOKED, 0x12000001),
84 OID_U32_C(DOT11_OID_EXUNENCRYPTED, 0x12000002),
85 OID_U32_C(DOT11_OID_DEFKEYID, 0x12000003),
86 [DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key),
87 OID_FLAG_CACHED | OID_TYPE_KEY}, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
88 OID_UNKNOWN(DOT11_OID_STAKEY, 0x12000008),
89 OID_U32(DOT11_OID_REKEYTHRESHOLD, 0x12000009),
90 OID_UNKNOWN(DOT11_OID_STASC, 0x1200000a),
91
92 OID_U32(DOT11_OID_PRIVTXREJECTED, 0x1a000000),
93 OID_U32(DOT11_OID_PRIVRXPLAIN, 0x1a000001),
94 OID_U32(DOT11_OID_PRIVRXFAILED, 0x1a000002),
95 OID_U32(DOT11_OID_PRIVRXNOKEY, 0x1a000003),
96
97 OID_U32_C(DOT11_OID_RTSTHRESH, 0x13000000),
98 OID_U32_C(DOT11_OID_FRAGTHRESH, 0x13000001),
99 OID_U32_C(DOT11_OID_SHORTRETRIES, 0x13000002),
100 OID_U32_C(DOT11_OID_LONGRETRIES, 0x13000003),
101 OID_U32_C(DOT11_OID_MAXTXLIFETIME, 0x13000004),
102 OID_U32(DOT11_OID_MAXRXLIFETIME, 0x13000005),
103 OID_U32(DOT11_OID_AUTHRESPTIMEOUT, 0x13000006),
104 OID_U32(DOT11_OID_ASSOCRESPTIMEOUT, 0x13000007),
105
106 OID_UNKNOWN(DOT11_OID_ALOFT_TABLE, 0x1d000000),
107 OID_UNKNOWN(DOT11_OID_ALOFT_CTRL_TABLE, 0x1d000001),
108 OID_UNKNOWN(DOT11_OID_ALOFT_RETREAT, 0x1d000002),
109 OID_UNKNOWN(DOT11_OID_ALOFT_PROGRESS, 0x1d000003),
110 OID_U32(DOT11_OID_ALOFT_FIXEDRATE, 0x1d000004),
111 OID_UNKNOWN(DOT11_OID_ALOFT_RSSIGRAPH, 0x1d000005),
112 OID_UNKNOWN(DOT11_OID_ALOFT_CONFIG, 0x1d000006),
113
114 [DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0},
115 OID_U32(DOT11_OID_MAXFRAMEBURST, 0x1b000008),
116
117 OID_U32(DOT11_OID_PSM, 0x14000000),
118 OID_U32(DOT11_OID_CAMTIMEOUT, 0x14000001),
119 OID_U32(DOT11_OID_RECEIVEDTIMS, 0x14000002),
120 OID_U32(DOT11_OID_ROAMPREFERENCE, 0x14000003),
121
122 OID_U32(DOT11_OID_BRIDGELOCAL, 0x15000000),
123 OID_U32(DOT11_OID_CLIENTS, 0x15000001),
124 OID_U32(DOT11_OID_CLIENTSASSOCIATED, 0x15000002),
125 [DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0}, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */
126
127 OID_STRUCT(DOT11_OID_CLIENTFIND, 0x150007DB, u8[6], OID_TYPE_ADDR),
128 OID_STRUCT(DOT11_OID_WDSLINKADD, 0x150007DC, u8[6], OID_TYPE_ADDR),
129 OID_STRUCT(DOT11_OID_WDSLINKREMOVE, 0x150007DD, u8[6], OID_TYPE_ADDR),
130 OID_STRUCT(DOT11_OID_EAPAUTHSTA, 0x150007DE, u8[6], OID_TYPE_ADDR),
131 OID_STRUCT(DOT11_OID_EAPUNAUTHSTA, 0x150007DF, u8[6], OID_TYPE_ADDR),
132 OID_U32_C(DOT11_OID_DOT1XENABLE, 0x150007E0),
133 OID_UNKNOWN(DOT11_OID_MICFAILURE, 0x150007E1),
134 OID_UNKNOWN(DOT11_OID_REKEYINDICATE, 0x150007E2),
135
136 OID_U32(DOT11_OID_MPDUTXSUCCESSFUL, 0x16000000),
137 OID_U32(DOT11_OID_MPDUTXONERETRY, 0x16000001),
138 OID_U32(DOT11_OID_MPDUTXMULTIPLERETRIES, 0x16000002),
139 OID_U32(DOT11_OID_MPDUTXFAILED, 0x16000003),
140 OID_U32(DOT11_OID_MPDURXSUCCESSFUL, 0x16000004),
141 OID_U32(DOT11_OID_MPDURXDUPS, 0x16000005),
142 OID_U32(DOT11_OID_RTSSUCCESSFUL, 0x16000006),
143 OID_U32(DOT11_OID_RTSFAILED, 0x16000007),
144 OID_U32(DOT11_OID_ACKFAILED, 0x16000008),
145 OID_U32(DOT11_OID_FRAMERECEIVES, 0x16000009),
146 OID_U32(DOT11_OID_FRAMEERRORS, 0x1600000A),
147 OID_U32(DOT11_OID_FRAMEABORTS, 0x1600000B),
148 OID_U32(DOT11_OID_FRAMEABORTSPHY, 0x1600000C),
149
150 OID_U32(DOT11_OID_SLOTTIME, 0x17000000),
151 OID_U32(DOT11_OID_CWMIN, 0x17000001),
152 OID_U32(DOT11_OID_CWMAX, 0x17000002),
153 OID_U32(DOT11_OID_ACKWINDOW, 0x17000003),
154 OID_U32(DOT11_OID_ANTENNARX, 0x17000004),
155 OID_U32(DOT11_OID_ANTENNATX, 0x17000005),
156 OID_U32(DOT11_OID_ANTENNADIVERSITY, 0x17000006),
157 OID_U32_C(DOT11_OID_CHANNEL, 0x17000007),
158 OID_U32_C(DOT11_OID_EDTHRESHOLD, 0x17000008),
159 OID_U32(DOT11_OID_PREAMBLESETTINGS, 0x17000009),
160 OID_STRUCT(DOT11_OID_RATES, 0x1700000A, u8[IWMAX_BITRATES + 1],
161 OID_TYPE_RAW),
162 OID_U32(DOT11_OID_CCAMODESUPPORTED, 0x1700000B),
163 OID_U32(DOT11_OID_CCAMODE, 0x1700000C),
164 OID_UNKNOWN(DOT11_OID_RSSIVECTOR, 0x1700000D),
165 OID_UNKNOWN(DOT11_OID_OUTPUTPOWERTABLE, 0x1700000E),
166 OID_U32(DOT11_OID_OUTPUTPOWER, 0x1700000F),
167 OID_STRUCT(DOT11_OID_SUPPORTEDRATES, 0x17000010,
168 u8[IWMAX_BITRATES + 1], OID_TYPE_RAW),
169 OID_U32_C(DOT11_OID_FREQUENCY, 0x17000011),
170 [DOT11_OID_SUPPORTEDFREQUENCIES] =
171 {0x17000012, 0, sizeof (struct obj_frequencies)
172 + sizeof (u16) * IWMAX_FREQ, OID_TYPE_FREQUENCIES},
173
174 OID_U32(DOT11_OID_NOISEFLOOR, 0x17000013),
175 OID_STRUCT(DOT11_OID_FREQUENCYACTIVITY, 0x17000014, u8[IWMAX_FREQ + 1],
176 OID_TYPE_RAW),
177 OID_UNKNOWN(DOT11_OID_IQCALIBRATIONTABLE, 0x17000015),
178 OID_U32(DOT11_OID_NONERPPROTECTION, 0x17000016),
179 OID_U32(DOT11_OID_SLOTSETTINGS, 0x17000017),
180 OID_U32(DOT11_OID_NONERPTIMEOUT, 0x17000018),
181 OID_U32(DOT11_OID_PROFILES, 0x17000019),
182 OID_STRUCT(DOT11_OID_EXTENDEDRATES, 0x17000020,
183 u8[IWMAX_BITRATES + 1], OID_TYPE_RAW),
184
185 OID_STRUCT_MLME(DOT11_OID_DEAUTHENTICATE, 0x18000000),
186 OID_STRUCT_MLME(DOT11_OID_AUTHENTICATE, 0x18000001),
187 OID_STRUCT_MLME(DOT11_OID_DISASSOCIATE, 0x18000002),
188 OID_STRUCT_MLME(DOT11_OID_ASSOCIATE, 0x18000003),
189 OID_UNKNOWN(DOT11_OID_SCAN, 0x18000004),
190 OID_STRUCT_MLMEEX(DOT11_OID_BEACON, 0x18000005),
191 OID_STRUCT_MLMEEX(DOT11_OID_PROBE, 0x18000006),
192 OID_STRUCT_MLMEEX(DOT11_OID_DEAUTHENTICATEEX, 0x18000007),
193 OID_STRUCT_MLMEEX(DOT11_OID_AUTHENTICATEEX, 0x18000008),
194 OID_STRUCT_MLMEEX(DOT11_OID_DISASSOCIATEEX, 0x18000009),
195 OID_STRUCT_MLMEEX(DOT11_OID_ASSOCIATEEX, 0x1800000A),
196 OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATE, 0x1800000B),
197 OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATEEX, 0x1800000C),
198
199 OID_U32(DOT11_OID_NONERPSTATUS, 0x1E000000),
200
201 OID_U32(DOT11_OID_STATIMEOUT, 0x19000000),
202 OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001),
203 OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002),
204 [DOT11_OID_ATTACHMENT] = {0x19000003, 0,
205 sizeof(struct obj_attachment), OID_TYPE_ATTACH},
206 OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
207 OID_TYPE_BUFFER),
208
209 OID_U32(DOT11_OID_BSSS, 0x1C000000),
210 [DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss),
211 OID_TYPE_BSS}, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
212 OID_STRUCT(DOT11_OID_BSSFIND, 0x1C000042, struct obj_bss, OID_TYPE_BSS),
213 [DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct
214 obj_bsslist) +
215 sizeof (struct obj_bss[IWMAX_BSS]),
216 OID_TYPE_BSSLIST},
217
218 OID_UNKNOWN(OID_INL_TUNNEL, 0xFF020000),
219 OID_UNKNOWN(OID_INL_MEMADDR, 0xFF020001),
220 OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002),
221 OID_U32_C(OID_INL_MODE, 0xFF020003),
222 OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004),
223 OID_STRUCT(OID_INL_VERSION, 0xFF020005, u8[8], OID_TYPE_RAW),
224 OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006),
225 OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007),
226 OID_U32_C(OID_INL_CONFIG, 0xFF020008),
227 OID_U32_C(OID_INL_DOT11D_CONFORMANCE, 0xFF02000C),
228 OID_U32(OID_INL_PHYCAPABILITIES, 0xFF02000D),
229 OID_U32_C(OID_INL_OUTPUTPOWER, 0xFF02000F),
230
231};
232
233int
234mgt_init(islpci_private *priv)
235{
236 int i;
237
238 priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL);
239 if (!priv->mib)
240 return -ENOMEM;
241
242 memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *));
243
244 /* Alloc the cache */
245 for (i = 0; i < OID_NUM_LAST; i++) {
246 if (isl_oid[i].flags & OID_FLAG_CACHED) {
247 priv->mib[i] = kmalloc(isl_oid[i].size *
248 (isl_oid[i].range + 1),
249 GFP_KERNEL);
250 if (!priv->mib[i])
251 return -ENOMEM;
252 memset(priv->mib[i], 0,
253 isl_oid[i].size * (isl_oid[i].range + 1));
254 } else
255 priv->mib[i] = NULL;
256 }
257
258 init_rwsem(&priv->mib_sem);
259 prism54_mib_init(priv);
260
261 return 0;
262}
263
264void
265mgt_clean(islpci_private *priv)
266{
267 int i;
268
269 if (!priv->mib)
270 return;
271 for (i = 0; i < OID_NUM_LAST; i++)
272 if (priv->mib[i]) {
273 kfree(priv->mib[i]);
274 priv->mib[i] = NULL;
275 }
276 kfree(priv->mib);
277 priv->mib = NULL;
278}
279
280void
281mgt_le_to_cpu(int type, void *data)
282{
283 switch (type) {
284 case OID_TYPE_U32:
285 *(u32 *) data = le32_to_cpu(*(u32 *) data);
286 break;
287 case OID_TYPE_BUFFER:{
288 struct obj_buffer *buff = data;
289 buff->size = le32_to_cpu(buff->size);
290 buff->addr = le32_to_cpu(buff->addr);
291 break;
292 }
293 case OID_TYPE_BSS:{
294 struct obj_bss *bss = data;
295 bss->age = le16_to_cpu(bss->age);
296 bss->channel = le16_to_cpu(bss->channel);
297 bss->capinfo = le16_to_cpu(bss->capinfo);
298 bss->rates = le16_to_cpu(bss->rates);
299 bss->basic_rates = le16_to_cpu(bss->basic_rates);
300 break;
301 }
302 case OID_TYPE_BSSLIST:{
303 struct obj_bsslist *list = data;
304 int i;
305 list->nr = le32_to_cpu(list->nr);
306 for (i = 0; i < list->nr; i++)
307 mgt_le_to_cpu(OID_TYPE_BSS, &list->bsslist[i]);
308 break;
309 }
310 case OID_TYPE_FREQUENCIES:{
311 struct obj_frequencies *freq = data;
312 int i;
313 freq->nr = le16_to_cpu(freq->nr);
314 for (i = 0; i < freq->nr; i++)
315 freq->mhz[i] = le16_to_cpu(freq->mhz[i]);
316 break;
317 }
318 case OID_TYPE_MLME:{
319 struct obj_mlme *mlme = data;
320 mlme->id = le16_to_cpu(mlme->id);
321 mlme->state = le16_to_cpu(mlme->state);
322 mlme->code = le16_to_cpu(mlme->code);
323 break;
324 }
325 case OID_TYPE_MLMEEX:{
326 struct obj_mlmeex *mlme = data;
327 mlme->id = le16_to_cpu(mlme->id);
328 mlme->state = le16_to_cpu(mlme->state);
329 mlme->code = le16_to_cpu(mlme->code);
330 mlme->size = le16_to_cpu(mlme->size);
331 break;
332 }
333 case OID_TYPE_ATTACH:{
334 struct obj_attachment *attach = data;
335 attach->id = le16_to_cpu(attach->id);
336 attach->size = le16_to_cpu(attach->size);;
337 break;
338 }
339 case OID_TYPE_SSID:
340 case OID_TYPE_KEY:
341 case OID_TYPE_ADDR:
342 case OID_TYPE_RAW:
343 break;
344 default:
345 BUG();
346 }
347}
348
349static void
350mgt_cpu_to_le(int type, void *data)
351{
352 switch (type) {
353 case OID_TYPE_U32:
354 *(u32 *) data = cpu_to_le32(*(u32 *) data);
355 break;
356 case OID_TYPE_BUFFER:{
357 struct obj_buffer *buff = data;
358 buff->size = cpu_to_le32(buff->size);
359 buff->addr = cpu_to_le32(buff->addr);
360 break;
361 }
362 case OID_TYPE_BSS:{
363 struct obj_bss *bss = data;
364 bss->age = cpu_to_le16(bss->age);
365 bss->channel = cpu_to_le16(bss->channel);
366 bss->capinfo = cpu_to_le16(bss->capinfo);
367 bss->rates = cpu_to_le16(bss->rates);
368 bss->basic_rates = cpu_to_le16(bss->basic_rates);
369 break;
370 }
371 case OID_TYPE_BSSLIST:{
372 struct obj_bsslist *list = data;
373 int i;
374 list->nr = cpu_to_le32(list->nr);
375 for (i = 0; i < list->nr; i++)
376 mgt_cpu_to_le(OID_TYPE_BSS, &list->bsslist[i]);
377 break;
378 }
379 case OID_TYPE_FREQUENCIES:{
380 struct obj_frequencies *freq = data;
381 int i;
382 freq->nr = cpu_to_le16(freq->nr);
383 for (i = 0; i < freq->nr; i++)
384 freq->mhz[i] = cpu_to_le16(freq->mhz[i]);
385 break;
386 }
387 case OID_TYPE_MLME:{
388 struct obj_mlme *mlme = data;
389 mlme->id = cpu_to_le16(mlme->id);
390 mlme->state = cpu_to_le16(mlme->state);
391 mlme->code = cpu_to_le16(mlme->code);
392 break;
393 }
394 case OID_TYPE_MLMEEX:{
395 struct obj_mlmeex *mlme = data;
396 mlme->id = cpu_to_le16(mlme->id);
397 mlme->state = cpu_to_le16(mlme->state);
398 mlme->code = cpu_to_le16(mlme->code);
399 mlme->size = cpu_to_le16(mlme->size);
400 break;
401 }
402 case OID_TYPE_ATTACH:{
403 struct obj_attachment *attach = data;
404 attach->id = cpu_to_le16(attach->id);
405 attach->size = cpu_to_le16(attach->size);;
406 break;
407 }
408 case OID_TYPE_SSID:
409 case OID_TYPE_KEY:
410 case OID_TYPE_ADDR:
411 case OID_TYPE_RAW:
412 break;
413 default:
414 BUG();
415 }
416}
417
418/* Note : data is modified during this function */
419
420int
421mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
422{
423 int ret = 0;
424 struct islpci_mgmtframe *response = NULL;
425 int response_op = PIMFOR_OP_ERROR;
426 int dlen;
427 void *cache, *_data = data;
428 u32 oid;
429
430 BUG_ON(OID_NUM_LAST <= n);
431 BUG_ON(extra > isl_oid[n].range);
432
433 if (!priv->mib)
434 /* memory has been freed */
435 return -1;
436
437 dlen = isl_oid[n].size;
438 cache = priv->mib[n];
439 cache += (cache ? extra * dlen : 0);
440 oid = isl_oid[n].oid + extra;
441
442 if (_data == NULL)
443 /* we are requested to re-set a cached value */
444 _data = cache;
445 else
446 mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, _data);
447 /* If we are going to write to the cache, we don't want anyone to read
448 * it -> acquire write lock.
449 * Else we could acquire a read lock to be sure we don't bother the
450 * commit process (which takes a write lock). But I'm not sure if it's
451 * needed.
452 */
453 if (cache)
454 down_write(&priv->mib_sem);
455
456 if (islpci_get_state(priv) >= PRV_STATE_READY) {
457 ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
458 _data, dlen, &response);
459 if (!ret) {
460 response_op = response->header->operation;
461 islpci_mgt_release(response);
462 }
463 if (ret || response_op == PIMFOR_OP_ERROR)
464 ret = -EIO;
465 } else if (!cache)
466 ret = -EIO;
467
468 if (cache) {
469 if (!ret && data)
470 memcpy(cache, _data, dlen);
471 up_write(&priv->mib_sem);
472 }
473
474 /* re-set given data to what it was */
475 if (data)
476 mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data);
477
478 return ret;
479}
480
481/* None of these are cached */
482int
483mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len)
484{
485 int ret = 0;
486 struct islpci_mgmtframe *response;
487 int response_op = PIMFOR_OP_ERROR;
488 int dlen;
489 u32 oid;
490
491 BUG_ON(OID_NUM_LAST <= n);
492
493 dlen = isl_oid[n].size;
494 oid = isl_oid[n].oid;
495
496 mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data);
497
498 if (islpci_get_state(priv) >= PRV_STATE_READY) {
499 ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
500 data, dlen + extra_len, &response);
501 if (!ret) {
502 response_op = response->header->operation;
503 islpci_mgt_release(response);
504 }
505 if (ret || response_op == PIMFOR_OP_ERROR)
506 ret = -EIO;
507 } else
508 ret = -EIO;
509
510 /* re-set given data to what it was */
511 if (data)
512 mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data);
513
514 return ret;
515}
516
517int
518mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
519 union oid_res_t *res)
520{
521
522 int ret = -EIO;
523 int reslen = 0;
524 struct islpci_mgmtframe *response = NULL;
525
526 int dlen;
527 void *cache, *_res = NULL;
528 u32 oid;
529
530 BUG_ON(OID_NUM_LAST <= n);
531 BUG_ON(extra > isl_oid[n].range);
532
533 res->ptr = NULL;
534
535 if (!priv->mib)
536 /* memory has been freed */
537 return -1;
538
539 dlen = isl_oid[n].size;
540 cache = priv->mib[n];
541 cache += cache ? extra * dlen : 0;
542 oid = isl_oid[n].oid + extra;
543 reslen = dlen;
544
545 if (cache)
546 down_read(&priv->mib_sem);
547
548 if (islpci_get_state(priv) >= PRV_STATE_READY) {
549 ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
550 oid, data, dlen, &response);
551 if (ret || !response ||
552 response->header->operation == PIMFOR_OP_ERROR) {
553 if (response)
554 islpci_mgt_release(response);
555 ret = -EIO;
556 }
557 if (!ret) {
558 _res = response->data;
559 reslen = response->header->length;
560 }
561 } else if (cache) {
562 _res = cache;
563 ret = 0;
564 }
565 if ((isl_oid[n].flags & OID_FLAG_TYPE) == OID_TYPE_U32)
566 res->u = ret ? 0 : le32_to_cpu(*(u32 *) _res);
567 else {
568 res->ptr = kmalloc(reslen, GFP_KERNEL);
569 BUG_ON(res->ptr == NULL);
570 if (ret)
571 memset(res->ptr, 0, reslen);
572 else {
573 memcpy(res->ptr, _res, reslen);
574 mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE,
575 res->ptr);
576 }
577 }
578 if (cache)
579 up_read(&priv->mib_sem);
580
581 if (response && !ret)
582 islpci_mgt_release(response);
583
584 if (reslen > isl_oid[n].size)
585 printk(KERN_DEBUG
586 "mgt_get_request(0x%x): received data length was bigger "
587 "than expected (%d > %d). Memory is probably corrupted...",
588 oid, reslen, isl_oid[n].size);
589
590 return ret;
591}
592
593/* lock outside */
594int
595mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n)
596{
597 int i, ret = 0;
598 struct islpci_mgmtframe *response;
599
600 for (i = 0; i < n; i++) {
601 struct oid_t *t = &(isl_oid[l[i]]);
602 void *data = priv->mib[l[i]];
603 int j = 0;
604 u32 oid = t->oid;
605 BUG_ON(data == NULL);
606 while (j <= t->range) {
607 int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
608 oid, data, t->size,
609 &response);
610 if (response) {
611 r |= (response->header->operation == PIMFOR_OP_ERROR);
612 islpci_mgt_release(response);
613 }
614 if (r)
615 printk(KERN_ERR "%s: mgt_commit_list: failure. "
616 "oid=%08x err=%d\n",
617 priv->ndev->name, oid, r);
618 ret |= r;
619 j++;
620 oid++;
621 data += t->size;
622 }
623 }
624 return ret;
625}
626
627/* Lock outside */
628
629void
630mgt_set(islpci_private *priv, enum oid_num_t n, void *data)
631{
632 BUG_ON(OID_NUM_LAST <= n);
633 BUG_ON(priv->mib[n] == NULL);
634
635 memcpy(priv->mib[n], data, isl_oid[n].size);
636 mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, priv->mib[n]);
637}
638
639void
640mgt_get(islpci_private *priv, enum oid_num_t n, void *res)
641{
642 BUG_ON(OID_NUM_LAST <= n);
643 BUG_ON(priv->mib[n] == NULL);
644 BUG_ON(res == NULL);
645
646 memcpy(res, priv->mib[n], isl_oid[n].size);
647 mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, res);
648}
649
650/* Commits the cache. Lock outside. */
651
652static enum oid_num_t commit_part1[] = {
653 OID_INL_CONFIG,
654 OID_INL_MODE,
655 DOT11_OID_BSSTYPE,
656 DOT11_OID_CHANNEL,
657 DOT11_OID_MLMEAUTOLEVEL
658};
659
660static enum oid_num_t commit_part2[] = {
661 DOT11_OID_SSID,
662 DOT11_OID_PSMBUFFER,
663 DOT11_OID_AUTHENABLE,
664 DOT11_OID_PRIVACYINVOKED,
665 DOT11_OID_EXUNENCRYPTED,
666 DOT11_OID_DEFKEYX, /* MULTIPLE */
667 DOT11_OID_DEFKEYID,
668 DOT11_OID_DOT1XENABLE,
669 OID_INL_DOT11D_CONFORMANCE,
670 /* Do not initialize this - fw < 1.0.4.3 rejects it
671 OID_INL_OUTPUTPOWER,
672 */
673};
674
675/* update the MAC addr. */
676static int
677mgt_update_addr(islpci_private *priv)
678{
679 struct islpci_mgmtframe *res;
680 int ret;
681
682 ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
683 isl_oid[GEN_OID_MACADDRESS].oid, NULL,
684 isl_oid[GEN_OID_MACADDRESS].size, &res);
685
686 if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR))
687 memcpy(priv->ndev->dev_addr, res->data, 6);
688 else
689 ret = -EIO;
690 if (res)
691 islpci_mgt_release(res);
692
693 if (ret)
694 printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name);
695 return ret;
696}
697
698#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
699
700int
701mgt_commit(islpci_private *priv)
702{
703 int rvalue;
704 u32 u;
705
706 if (islpci_get_state(priv) < PRV_STATE_INIT)
707 return 0;
708
709 rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1));
710
711 if (priv->iw_mode != IW_MODE_MONITOR)
712 rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2));
713
714 u = OID_INL_MODE;
715 rvalue |= mgt_commit_list(priv, &u, 1);
716 rvalue |= mgt_update_addr(priv);
717
718 if (rvalue) {
719 /* some request have failed. The device might be in an
720 incoherent state. We should reset it ! */
721 printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name);
722 }
723 return rvalue;
724}
725
726/* The following OIDs need to be "unlatched":
727 *
728 * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL
729 * FREQUENCY,EXTENDEDRATES.
730 *
731 * The way to do this is to set ESSID. Note though that they may get
732 * unlatch before though by setting another OID. */
733#if 0
734void
735mgt_unlatch_all(islpci_private *priv)
736{
737 u32 u;
738 int rvalue = 0;
739
740 if (islpci_get_state(priv) < PRV_STATE_INIT)
741 return;
742
743 u = DOT11_OID_SSID;
744 rvalue = mgt_commit_list(priv, &u, 1);
745 /* Necessary if in MANUAL RUN mode? */
746#if 0
747 u = OID_INL_MODE;
748 rvalue |= mgt_commit_list(priv, &u, 1);
749
750 u = DOT11_OID_MLMEAUTOLEVEL;
751 rvalue |= mgt_commit_list(priv, &u, 1);
752
753 u = OID_INL_MODE;
754 rvalue |= mgt_commit_list(priv, &u, 1);
755#endif
756
757 if (rvalue)
758 printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name);
759}
760#endif
761
762/* This will tell you if you are allowed to answer a mlme(ex) request .*/
763
764int
765mgt_mlme_answer(islpci_private *priv)
766{
767 u32 mlmeautolevel;
768 /* Acquire a read lock because if we are in a mode change, it's
769 * possible to answer true, while the card is leaving master to managed
770 * mode. Answering to a mlme in this situation could hang the card.
771 */
772 down_read(&priv->mib_sem);
773 mlmeautolevel =
774 le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]);
775 up_read(&priv->mib_sem);
776
777 return ((priv->iw_mode == IW_MODE_MASTER) &&
778 (mlmeautolevel >= DOT11_MLME_INTERMEDIATE));
779}
780
781enum oid_num_t
782mgt_oidtonum(u32 oid)
783{
784 int i;
785
786 for (i = 0; i < OID_NUM_LAST; i++)
787 if (isl_oid[i].oid == oid)
788 return i;
789
790 printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid);
791
792 return OID_NUM_LAST;
793}
794
795int
796mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
797{
798 switch (isl_oid[n].flags & OID_FLAG_TYPE) {
799 case OID_TYPE_U32:
800 return snprintf(str, PRIV_STR_SIZE, "%u\n", r->u);
801 break;
802 case OID_TYPE_BUFFER:{
803 struct obj_buffer *buff = r->ptr;
804 return snprintf(str, PRIV_STR_SIZE,
805 "size=%u\naddr=0x%X\n", buff->size,
806 buff->addr);
807 }
808 break;
809 case OID_TYPE_BSS:{
810 struct obj_bss *bss = r->ptr;
811 return snprintf(str, PRIV_STR_SIZE,
812 "age=%u\nchannel=%u\n"
813 "capinfo=0x%X\nrates=0x%X\n"
814 "basic_rates=0x%X\n", bss->age,
815 bss->channel, bss->capinfo,
816 bss->rates, bss->basic_rates);
817 }
818 break;
819 case OID_TYPE_BSSLIST:{
820 struct obj_bsslist *list = r->ptr;
821 int i, k;
822 k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr);
823 for (i = 0; i < list->nr; i++)
824 k += snprintf(str + k, PRIV_STR_SIZE - k,
825 "bss[%u] : \nage=%u\nchannel=%u\n"
826 "capinfo=0x%X\nrates=0x%X\n"
827 "basic_rates=0x%X\n",
828 i, list->bsslist[i].age,
829 list->bsslist[i].channel,
830 list->bsslist[i].capinfo,
831 list->bsslist[i].rates,
832 list->bsslist[i].basic_rates);
833 return k;
834 }
835 break;
836 case OID_TYPE_FREQUENCIES:{
837 struct obj_frequencies *freq = r->ptr;
838 int i, t;
839 printk("nr : %u\n", freq->nr);
840 t = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", freq->nr);
841 for (i = 0; i < freq->nr; i++)
842 t += snprintf(str + t, PRIV_STR_SIZE - t,
843 "mhz[%u]=%u\n", i, freq->mhz[i]);
844 return t;
845 }
846 break;
847 case OID_TYPE_MLME:{
848 struct obj_mlme *mlme = r->ptr;
849 return snprintf(str, PRIV_STR_SIZE,
850 "id=0x%X\nstate=0x%X\ncode=0x%X\n",
851 mlme->id, mlme->state, mlme->code);
852 }
853 break;
854 case OID_TYPE_MLMEEX:{
855 struct obj_mlmeex *mlme = r->ptr;
856 return snprintf(str, PRIV_STR_SIZE,
857 "id=0x%X\nstate=0x%X\n"
858 "code=0x%X\nsize=0x%X\n", mlme->id,
859 mlme->state, mlme->code, mlme->size);
860 }
861 break;
862 case OID_TYPE_ATTACH:{
863 struct obj_attachment *attach = r->ptr;
864 return snprintf(str, PRIV_STR_SIZE,
865 "id=%d\nsize=%d\n",
866 attach->id,
867 attach->size);
868 }
869 break;
870 case OID_TYPE_SSID:{
871 struct obj_ssid *ssid = r->ptr;
872 return snprintf(str, PRIV_STR_SIZE,
873 "length=%u\noctets=%.*s\n",
874 ssid->length, ssid->length,
875 ssid->octets);
876 }
877 break;
878 case OID_TYPE_KEY:{
879 struct obj_key *key = r->ptr;
880 int t, i;
881 t = snprintf(str, PRIV_STR_SIZE,
882 "type=0x%X\nlength=0x%X\nkey=0x",
883 key->type, key->length);
884 for (i = 0; i < key->length; i++)
885 t += snprintf(str + t, PRIV_STR_SIZE - t,
886 "%02X:", key->key[i]);
887 t += snprintf(str + t, PRIV_STR_SIZE - t, "\n");
888 return t;
889 }
890 break;
891 case OID_TYPE_RAW:
892 case OID_TYPE_ADDR:{
893 unsigned char *buff = r->ptr;
894 int t, i;
895 t = snprintf(str, PRIV_STR_SIZE, "hex data=");
896 for (i = 0; i < isl_oid[n].size; i++)
897 t += snprintf(str + t, PRIV_STR_SIZE - t,
898 "%02X:", buff[i]);
899 t += snprintf(str + t, PRIV_STR_SIZE - t, "\n");
900 return t;
901 }
902 break;
903 default:
904 BUG();
905 }
906 return 0;
907}
diff --git a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h
new file mode 100644
index 000000000000..92c8a2d4acd8
--- /dev/null
+++ b/drivers/net/wireless/prism54/oid_mgt.h
@@ -0,0 +1,59 @@
1/*
2 * Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
18
19#if !defined(_OID_MGT_H)
20#define _OID_MGT_H
21
22#include "isl_oid.h"
23#include "islpci_dev.h"
24
25extern struct oid_t isl_oid[];
26
27int mgt_init(islpci_private *);
28
29void mgt_clean(islpci_private *);
30
31/* I don't know where to put these 2 */
32extern const int frequency_list_a[];
33int channel_of_freq(int);
34
35void mgt_le_to_cpu(int, void *);
36
37int mgt_set_request(islpci_private *, enum oid_num_t, int, void *);
38int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int);
39
40
41int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
42 union oid_res_t *);
43
44int mgt_commit_list(islpci_private *, enum oid_num_t *, int);
45
46void mgt_set(islpci_private *, enum oid_num_t, void *);
47
48void mgt_get(islpci_private *, enum oid_num_t, void *);
49
50int mgt_commit(islpci_private *);
51
52int mgt_mlme_answer(islpci_private *);
53
54enum oid_num_t mgt_oidtonum(u32 oid);
55
56int mgt_response_to_str(enum oid_num_t, union oid_res_t *, char *);
57
58#endif /* !defined(_OID_MGT_H) */
59/* EOF */
diff --git a/drivers/net/wireless/prism54/prismcompat.h b/drivers/net/wireless/prism54/prismcompat.h
new file mode 100644
index 000000000000..55541c01752e
--- /dev/null
+++ b/drivers/net/wireless/prism54/prismcompat.h
@@ -0,0 +1,44 @@
1/*
2 * (C) 2004 Margit Schubert-While <margitsw@t-online.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
18
19/*
20 * Compatibility header file to aid support of different kernel versions
21 */
22
23#ifdef PRISM54_COMPAT24
24#include "prismcompat24.h"
25#else /* PRISM54_COMPAT24 */
26
27#ifndef _PRISM_COMPAT_H
28#define _PRISM_COMPAT_H
29
30#include <linux/device.h>
31#include <linux/firmware.h>
32#include <linux/config.h>
33#include <linux/moduleparam.h>
34#include <linux/workqueue.h>
35#include <linux/compiler.h>
36
37#ifndef __iomem
38#define __iomem
39#endif
40
41#define PRISM_FW_PDEV &priv->pdev->dev
42
43#endif /* _PRISM_COMPAT_H */
44#endif /* PRISM54_COMPAT24 */