diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/wireless/ray_cs.c |
Linux-2.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/ray_cs.c')
-rw-r--r-- | drivers/net/wireless/ray_cs.c | 2957 |
1 files changed, 2957 insertions, 0 deletions
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c new file mode 100644 index 000000000000..6e5bda56b8f8 --- /dev/null +++ b/drivers/net/wireless/ray_cs.c | |||
@@ -0,0 +1,2957 @@ | |||
1 | /*============================================================================= | ||
2 | * | ||
3 | * A PCMCIA client driver for the Raylink wireless LAN card. | ||
4 | * The starting point for this module was the skeleton.c in the | ||
5 | * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net | ||
6 | * | ||
7 | * | ||
8 | * Copyright (c) 1998 Corey Thomas (corey@world.std.com) | ||
9 | * | ||
10 | * This driver is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 only of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * It is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
22 | * | ||
23 | * Changes: | ||
24 | * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000 | ||
25 | * - reorganize kmallocs in ray_attach, checking all for failure | ||
26 | * and releasing the previous allocations if one fails | ||
27 | * | ||
28 | * Daniele Bellucci <bellucda@tiscali.it> - 07/10/2003 | ||
29 | * - Audit copy_to_user in ioctl(SIOCGIWESSID) | ||
30 | * | ||
31 | =============================================================================*/ | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/proc_fs.h> | ||
37 | #include <linux/ptrace.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/timer.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/netdevice.h> | ||
43 | #include <linux/etherdevice.h> | ||
44 | #include <linux/if_arp.h> | ||
45 | #include <linux/ioport.h> | ||
46 | #include <linux/skbuff.h> | ||
47 | #include <linux/ethtool.h> | ||
48 | |||
49 | #include <pcmcia/version.h> | ||
50 | #include <pcmcia/cs_types.h> | ||
51 | #include <pcmcia/cs.h> | ||
52 | #include <pcmcia/cistpl.h> | ||
53 | #include <pcmcia/cisreg.h> | ||
54 | #include <pcmcia/ds.h> | ||
55 | #include <pcmcia/mem_op.h> | ||
56 | |||
57 | #include <linux/wireless.h> | ||
58 | |||
59 | #include <asm/io.h> | ||
60 | #include <asm/system.h> | ||
61 | #include <asm/byteorder.h> | ||
62 | #include <asm/uaccess.h> | ||
63 | |||
64 | /* Warning : these stuff will slow down the driver... */ | ||
65 | #define WIRELESS_SPY /* Enable spying addresses */ | ||
66 | /* Definitions we need for spy */ | ||
67 | typedef struct iw_statistics iw_stats; | ||
68 | typedef struct iw_quality iw_qual; | ||
69 | typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ | ||
70 | |||
71 | #include "rayctl.h" | ||
72 | #include "ray_cs.h" | ||
73 | |||
74 | /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If | ||
75 | you do not define PCMCIA_DEBUG at all, all the debug code will be | ||
76 | left out. If you compile with PCMCIA_DEBUG=0, the debug code will | ||
77 | be present but disabled -- but it can then be enabled for specific | ||
78 | modules at load time with a 'pc_debug=#' option to insmod. | ||
79 | */ | ||
80 | |||
81 | #ifdef RAYLINK_DEBUG | ||
82 | #define PCMCIA_DEBUG RAYLINK_DEBUG | ||
83 | #endif | ||
84 | #ifdef PCMCIA_DEBUG | ||
85 | static int ray_debug; | ||
86 | static int pc_debug = PCMCIA_DEBUG; | ||
87 | module_param(pc_debug, int, 0); | ||
88 | /* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */ | ||
89 | #define DEBUG(n, args...) if (pc_debug>(n)) printk(args); | ||
90 | #else | ||
91 | #define DEBUG(n, args...) | ||
92 | #endif | ||
93 | /** Prototypes based on PCMCIA skeleton driver *******************************/ | ||
94 | static void ray_config(dev_link_t *link); | ||
95 | static void ray_release(dev_link_t *link); | ||
96 | static int ray_event(event_t event, int priority, event_callback_args_t *args); | ||
97 | static dev_link_t *ray_attach(void); | ||
98 | static void ray_detach(dev_link_t *); | ||
99 | |||
100 | /***** Prototypes indicated by device structure ******************************/ | ||
101 | static int ray_dev_close(struct net_device *dev); | ||
102 | static int ray_dev_config(struct net_device *dev, struct ifmap *map); | ||
103 | static struct net_device_stats *ray_get_stats(struct net_device *dev); | ||
104 | static int ray_dev_init(struct net_device *dev); | ||
105 | static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | ||
106 | |||
107 | static struct ethtool_ops netdev_ethtool_ops; | ||
108 | |||
109 | static int ray_open(struct net_device *dev); | ||
110 | static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
111 | static void set_multicast_list(struct net_device *dev); | ||
112 | static void ray_update_multi_list(struct net_device *dev, int all); | ||
113 | static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, | ||
114 | unsigned char *data, int len); | ||
115 | static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, | ||
116 | unsigned char *data); | ||
117 | static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); | ||
118 | #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ | ||
119 | static iw_stats * ray_get_wireless_stats(struct net_device * dev); | ||
120 | #endif /* WIRELESS_EXT > 7 */ | ||
121 | |||
122 | /***** Prototypes for raylink functions **************************************/ | ||
123 | static int asc_to_int(char a); | ||
124 | static void authenticate(ray_dev_t *local); | ||
125 | static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type); | ||
126 | static void authenticate_timeout(u_long); | ||
127 | static int get_free_ccs(ray_dev_t *local); | ||
128 | static int get_free_tx_ccs(ray_dev_t *local); | ||
129 | static void init_startup_params(ray_dev_t *local); | ||
130 | static int parse_addr(char *in_str, UCHAR *out); | ||
131 | static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type); | ||
132 | static int ray_init(struct net_device *dev); | ||
133 | static int interrupt_ecf(ray_dev_t *local, int ccs); | ||
134 | static void ray_reset(struct net_device *dev); | ||
135 | static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len); | ||
136 | static void verify_dl_startup(u_long); | ||
137 | |||
138 | /* Prototypes for interrpt time functions **********************************/ | ||
139 | static irqreturn_t ray_interrupt (int reg, void *dev_id, struct pt_regs *regs); | ||
140 | static void clear_interrupt(ray_dev_t *local); | ||
141 | static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
142 | unsigned int pkt_addr, int rx_len); | ||
143 | static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); | ||
144 | static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs); | ||
145 | static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs); | ||
146 | static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
147 | unsigned int pkt_addr, int rx_len); | ||
148 | static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, | ||
149 | int rx_len); | ||
150 | static void associate(ray_dev_t *local); | ||
151 | |||
152 | /* Card command functions */ | ||
153 | static int dl_startup_params(struct net_device *dev); | ||
154 | static void join_net(u_long local); | ||
155 | static void start_net(u_long local); | ||
156 | /* void start_net(ray_dev_t *local); */ | ||
157 | |||
158 | /*===========================================================================*/ | ||
159 | /* Parameters that can be set with 'insmod' */ | ||
160 | |||
161 | /* ADHOC=0, Infrastructure=1 */ | ||
162 | static int net_type = ADHOC; | ||
163 | |||
164 | /* Hop dwell time in Kus (1024 us units defined by 802.11) */ | ||
165 | static int hop_dwell = 128; | ||
166 | |||
167 | /* Beacon period in Kus */ | ||
168 | static int beacon_period = 256; | ||
169 | |||
170 | /* power save mode (0 = off, 1 = save power) */ | ||
171 | static int psm; | ||
172 | |||
173 | /* String for network's Extended Service Set ID. 32 Characters max */ | ||
174 | static char *essid; | ||
175 | |||
176 | /* Default to encapsulation unless translation requested */ | ||
177 | static int translate = 1; | ||
178 | |||
179 | static int country = USA; | ||
180 | |||
181 | static int sniffer; | ||
182 | |||
183 | static int bc; | ||
184 | |||
185 | /* 48 bit physical card address if overriding card's real physical | ||
186 | * address is required. Since IEEE 802.11 addresses are 48 bits | ||
187 | * like ethernet, an int can't be used, so a string is used. To | ||
188 | * allow use of addresses starting with a decimal digit, the first | ||
189 | * character must be a letter and will be ignored. This letter is | ||
190 | * followed by up to 12 hex digits which are the address. If less | ||
191 | * than 12 digits are used, the address will be left filled with 0's. | ||
192 | * Note that bit 0 of the first byte is the broadcast bit, and evil | ||
193 | * things will happen if it is not 0 in a card address. | ||
194 | */ | ||
195 | static char *phy_addr = NULL; | ||
196 | |||
197 | |||
198 | /* The dev_info variable is the "key" that is used to match up this | ||
199 | device driver with appropriate cards, through the card configuration | ||
200 | database. | ||
201 | */ | ||
202 | static dev_info_t dev_info = "ray_cs"; | ||
203 | |||
204 | /* A linked list of "instances" of the ray device. Each actual | ||
205 | PCMCIA card corresponds to one device instance, and is described | ||
206 | by one dev_link_t structure (defined in ds.h). | ||
207 | */ | ||
208 | static dev_link_t *dev_list = NULL; | ||
209 | |||
210 | /* A dev_link_t structure has fields for most things that are needed | ||
211 | to keep track of a socket, but there will usually be some device | ||
212 | specific information that also needs to be kept track of. The | ||
213 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
214 | a device-specific private data structure, like this. | ||
215 | */ | ||
216 | static unsigned int ray_mem_speed = 500; | ||
217 | |||
218 | MODULE_AUTHOR("Corey Thomas <corey@world.std.com>"); | ||
219 | MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); | ||
220 | MODULE_LICENSE("GPL"); | ||
221 | |||
222 | module_param(net_type, int, 0); | ||
223 | module_param(hop_dwell, int, 0); | ||
224 | module_param(beacon_period, int, 0); | ||
225 | module_param(psm, int, 0); | ||
226 | module_param(essid, charp, 0); | ||
227 | module_param(translate, int, 0); | ||
228 | module_param(country, int, 0); | ||
229 | module_param(sniffer, int, 0); | ||
230 | module_param(bc, int, 0); | ||
231 | module_param(phy_addr, charp, 0); | ||
232 | module_param(ray_mem_speed, int, 0); | ||
233 | |||
234 | static UCHAR b5_default_startup_parms[] = { | ||
235 | 0, 0, /* Adhoc station */ | ||
236 | 'L','I','N','U','X', 0, 0, 0, /* 32 char ESSID */ | ||
237 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
238 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
239 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
240 | 1, 0, /* Active scan, CA Mode */ | ||
241 | 0, 0, 0, 0, 0, 0, /* No default MAC addr */ | ||
242 | 0x7f, 0xff, /* Frag threshold */ | ||
243 | 0x00, 0x80, /* Hop time 128 Kus*/ | ||
244 | 0x01, 0x00, /* Beacon period 256 Kus */ | ||
245 | 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout*/ | ||
246 | 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */ | ||
247 | 0x7f, 0xff, /* RTS threshold */ | ||
248 | 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */ | ||
249 | 0x05, /* assoc resp timeout thresh */ | ||
250 | 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max*/ | ||
251 | 0, /* Promiscuous mode */ | ||
252 | 0x0c, 0x0bd, /* Unique word */ | ||
253 | 0x32, /* Slot time */ | ||
254 | 0xff, 0xff, /* roam-low snr, low snr count */ | ||
255 | 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ | ||
256 | 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */ | ||
257 | /* b4 - b5 differences start here */ | ||
258 | 0x00, 0x3f, /* CW max */ | ||
259 | 0x00, 0x0f, /* CW min */ | ||
260 | 0x04, 0x08, /* Noise gain, limit offset */ | ||
261 | 0x28, 0x28, /* det rssi, med busy offsets */ | ||
262 | 7, /* det sync thresh */ | ||
263 | 0, 2, 2, /* test mode, min, max */ | ||
264 | 0, /* allow broadcast SSID probe resp */ | ||
265 | 0, 0, /* privacy must start, can join */ | ||
266 | 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */ | ||
267 | }; | ||
268 | |||
269 | static UCHAR b4_default_startup_parms[] = { | ||
270 | 0, 0, /* Adhoc station */ | ||
271 | 'L','I','N','U','X', 0, 0, 0, /* 32 char ESSID */ | ||
272 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
273 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
274 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
275 | 1, 0, /* Active scan, CA Mode */ | ||
276 | 0, 0, 0, 0, 0, 0, /* No default MAC addr */ | ||
277 | 0x7f, 0xff, /* Frag threshold */ | ||
278 | 0x02, 0x00, /* Hop time */ | ||
279 | 0x00, 0x01, /* Beacon period */ | ||
280 | 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout*/ | ||
281 | 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */ | ||
282 | 0x7f, 0xff, /* RTS threshold */ | ||
283 | 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */ | ||
284 | 0x05, /* assoc resp timeout thresh */ | ||
285 | 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max*/ | ||
286 | 0, /* Promiscuous mode */ | ||
287 | 0x0c, 0x0bd, /* Unique word */ | ||
288 | 0x4e, /* Slot time (TBD seems wrong)*/ | ||
289 | 0xff, 0xff, /* roam-low snr, low snr count */ | ||
290 | 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ | ||
291 | 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */ | ||
292 | /* b4 - b5 differences start here */ | ||
293 | 0x3f, 0x0f, /* CW max, min */ | ||
294 | 0x04, 0x08, /* Noise gain, limit offset */ | ||
295 | 0x28, 0x28, /* det rssi, med busy offsets */ | ||
296 | 7, /* det sync thresh */ | ||
297 | 0, 2, 2 /* test mode, min, max*/ | ||
298 | }; | ||
299 | /*===========================================================================*/ | ||
300 | static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0}; | ||
301 | |||
302 | static char hop_pattern_length[] = { 1, | ||
303 | USA_HOP_MOD, EUROPE_HOP_MOD, | ||
304 | JAPAN_HOP_MOD, KOREA_HOP_MOD, | ||
305 | SPAIN_HOP_MOD, FRANCE_HOP_MOD, | ||
306 | ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD, | ||
307 | JAPAN_TEST_HOP_MOD | ||
308 | }; | ||
309 | |||
310 | static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>"; | ||
311 | |||
312 | /*============================================================================= | ||
313 | ray_attach() creates an "instance" of the driver, allocating | ||
314 | local data structures for one device. The device is registered | ||
315 | with Card Services. | ||
316 | The dev_link structure is initialized, but we don't actually | ||
317 | configure the card at this point -- we wait until we receive a | ||
318 | card insertion event. | ||
319 | =============================================================================*/ | ||
320 | static dev_link_t *ray_attach(void) | ||
321 | { | ||
322 | client_reg_t client_reg; | ||
323 | dev_link_t *link; | ||
324 | ray_dev_t *local; | ||
325 | int ret; | ||
326 | struct net_device *dev; | ||
327 | |||
328 | DEBUG(1, "ray_attach()\n"); | ||
329 | |||
330 | /* Initialize the dev_link_t structure */ | ||
331 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | ||
332 | |||
333 | if (!link) | ||
334 | return NULL; | ||
335 | |||
336 | /* Allocate space for private device-specific data */ | ||
337 | dev = alloc_etherdev(sizeof(ray_dev_t)); | ||
338 | |||
339 | if (!dev) | ||
340 | goto fail_alloc_dev; | ||
341 | |||
342 | local = dev->priv; | ||
343 | |||
344 | memset(link, 0, sizeof(struct dev_link_t)); | ||
345 | |||
346 | /* The io structure describes IO port mapping. None used here */ | ||
347 | link->io.NumPorts1 = 0; | ||
348 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
349 | link->io.IOAddrLines = 5; | ||
350 | |||
351 | /* Interrupt setup. For PCMCIA, driver takes what's given */ | ||
352 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
353 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
354 | link->irq.Handler = &ray_interrupt; | ||
355 | |||
356 | /* General socket configuration */ | ||
357 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
358 | link->conf.Vcc = 50; | ||
359 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
360 | link->conf.ConfigIndex = 1; | ||
361 | link->conf.Present = PRESENT_OPTION; | ||
362 | |||
363 | link->priv = dev; | ||
364 | link->irq.Instance = dev; | ||
365 | |||
366 | local->finder = link; | ||
367 | local->card_status = CARD_INSERTED; | ||
368 | local->authentication_state = UNAUTHENTICATED; | ||
369 | local->num_multi = 0; | ||
370 | DEBUG(2,"ray_attach link = %p, dev = %p, local = %p, intr = %p\n", | ||
371 | link,dev,local,&ray_interrupt); | ||
372 | |||
373 | /* Raylink entries in the device structure */ | ||
374 | dev->hard_start_xmit = &ray_dev_start_xmit; | ||
375 | dev->set_config = &ray_dev_config; | ||
376 | dev->get_stats = &ray_get_stats; | ||
377 | dev->do_ioctl = &ray_dev_ioctl; | ||
378 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | ||
379 | #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ | ||
380 | dev->get_wireless_stats = ray_get_wireless_stats; | ||
381 | #endif | ||
382 | |||
383 | dev->set_multicast_list = &set_multicast_list; | ||
384 | |||
385 | DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); | ||
386 | SET_MODULE_OWNER(dev); | ||
387 | dev->init = &ray_dev_init; | ||
388 | dev->open = &ray_open; | ||
389 | dev->stop = &ray_dev_close; | ||
390 | netif_stop_queue(dev); | ||
391 | |||
392 | /* Register with Card Services */ | ||
393 | link->next = dev_list; | ||
394 | dev_list = link; | ||
395 | client_reg.dev_info = &dev_info; | ||
396 | client_reg.EventMask = | ||
397 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
398 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
399 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
400 | client_reg.event_handler = &ray_event; | ||
401 | client_reg.Version = 0x0210; | ||
402 | client_reg.event_callback_args.client_data = link; | ||
403 | |||
404 | DEBUG(2,"ray_cs ray_attach calling pcmcia_register_client(...)\n"); | ||
405 | |||
406 | init_timer(&local->timer); | ||
407 | |||
408 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
409 | if (ret != 0) { | ||
410 | printk("ray_cs ray_attach RegisterClient unhappy - detaching\n"); | ||
411 | cs_error(link->handle, RegisterClient, ret); | ||
412 | ray_detach(link); | ||
413 | return NULL; | ||
414 | } | ||
415 | DEBUG(2,"ray_cs ray_attach ending\n"); | ||
416 | return link; | ||
417 | |||
418 | fail_alloc_dev: | ||
419 | kfree(link); | ||
420 | return NULL; | ||
421 | } /* ray_attach */ | ||
422 | /*============================================================================= | ||
423 | This deletes a driver "instance". The device is de-registered | ||
424 | with Card Services. If it has been released, all local data | ||
425 | structures are freed. Otherwise, the structures will be freed | ||
426 | when the device is released. | ||
427 | =============================================================================*/ | ||
428 | static void ray_detach(dev_link_t *link) | ||
429 | { | ||
430 | dev_link_t **linkp; | ||
431 | |||
432 | DEBUG(1, "ray_detach(0x%p)\n", link); | ||
433 | |||
434 | /* Locate device structure */ | ||
435 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
436 | if (*linkp == link) break; | ||
437 | if (*linkp == NULL) | ||
438 | return; | ||
439 | |||
440 | /* If the device is currently configured and active, we won't | ||
441 | actually delete it yet. Instead, it is marked so that when | ||
442 | the release() function is called, that will trigger a proper | ||
443 | detach(). | ||
444 | */ | ||
445 | if (link->state & DEV_CONFIG) | ||
446 | ray_release(link); | ||
447 | |||
448 | /* Break the link with Card Services */ | ||
449 | if (link->handle) | ||
450 | pcmcia_deregister_client(link->handle); | ||
451 | |||
452 | /* Unlink device structure, free pieces */ | ||
453 | *linkp = link->next; | ||
454 | if (link->priv) { | ||
455 | struct net_device *dev = link->priv; | ||
456 | if (link->dev) unregister_netdev(dev); | ||
457 | free_netdev(dev); | ||
458 | } | ||
459 | kfree(link); | ||
460 | DEBUG(2,"ray_cs ray_detach ending\n"); | ||
461 | } /* ray_detach */ | ||
462 | /*============================================================================= | ||
463 | ray_config() is run after a CARD_INSERTION event | ||
464 | is received, to configure the PCMCIA socket, and to make the | ||
465 | ethernet device available to the system. | ||
466 | =============================================================================*/ | ||
467 | #define CS_CHECK(fn, ret) \ | ||
468 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
469 | #define MAX_TUPLE_SIZE 128 | ||
470 | static void ray_config(dev_link_t *link) | ||
471 | { | ||
472 | client_handle_t handle = link->handle; | ||
473 | tuple_t tuple; | ||
474 | cisparse_t parse; | ||
475 | int last_fn = 0, last_ret = 0; | ||
476 | int i; | ||
477 | u_char buf[MAX_TUPLE_SIZE]; | ||
478 | win_req_t req; | ||
479 | memreq_t mem; | ||
480 | struct net_device *dev = (struct net_device *)link->priv; | ||
481 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
482 | |||
483 | DEBUG(1, "ray_config(0x%p)\n", link); | ||
484 | |||
485 | /* This reads the card's CONFIG tuple to find its configuration regs */ | ||
486 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
487 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
488 | tuple.TupleData = buf; | ||
489 | tuple.TupleDataMax = MAX_TUPLE_SIZE; | ||
490 | tuple.TupleOffset = 0; | ||
491 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
492 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
493 | link->conf.ConfigBase = parse.config.base; | ||
494 | link->conf.Present = parse.config.rmask[0]; | ||
495 | |||
496 | /* Determine card type and firmware version */ | ||
497 | buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; | ||
498 | tuple.DesiredTuple = CISTPL_VERS_1; | ||
499 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
500 | tuple.TupleData = buf; | ||
501 | tuple.TupleDataMax = MAX_TUPLE_SIZE; | ||
502 | tuple.TupleOffset = 2; | ||
503 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
504 | |||
505 | for (i=0; i<tuple.TupleDataLen - 4; i++) | ||
506 | if (buf[i] == 0) buf[i] = ' '; | ||
507 | printk(KERN_INFO "ray_cs Detected: %s\n",buf); | ||
508 | |||
509 | /* Configure card */ | ||
510 | link->state |= DEV_CONFIG; | ||
511 | |||
512 | /* Now allocate an interrupt line. Note that this does not | ||
513 | actually assign a handler to the interrupt. | ||
514 | */ | ||
515 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
516 | dev->irq = link->irq.AssignedIRQ; | ||
517 | |||
518 | /* This actually configures the PCMCIA socket -- setting up | ||
519 | the I/O windows and the interrupt mapping. | ||
520 | */ | ||
521 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | ||
522 | |||
523 | /*** Set up 32k window for shared memory (transmit and control) ************/ | ||
524 | req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; | ||
525 | req.Base = 0; | ||
526 | req.Size = 0x8000; | ||
527 | req.AccessSpeed = ray_mem_speed; | ||
528 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); | ||
529 | mem.CardOffset = 0x0000; mem.Page = 0; | ||
530 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); | ||
531 | local->sram = ioremap(req.Base,req.Size); | ||
532 | |||
533 | /*** Set up 16k window for shared memory (receive buffer) ***************/ | ||
534 | req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; | ||
535 | req.Base = 0; | ||
536 | req.Size = 0x4000; | ||
537 | req.AccessSpeed = ray_mem_speed; | ||
538 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->rmem_handle)); | ||
539 | mem.CardOffset = 0x8000; mem.Page = 0; | ||
540 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); | ||
541 | local->rmem = ioremap(req.Base,req.Size); | ||
542 | |||
543 | /*** Set up window for attribute memory ***********************************/ | ||
544 | req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; | ||
545 | req.Base = 0; | ||
546 | req.Size = 0x1000; | ||
547 | req.AccessSpeed = ray_mem_speed; | ||
548 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->amem_handle)); | ||
549 | mem.CardOffset = 0x0000; mem.Page = 0; | ||
550 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); | ||
551 | local->amem = ioremap(req.Base,req.Size); | ||
552 | |||
553 | DEBUG(3,"ray_config sram=%p\n",local->sram); | ||
554 | DEBUG(3,"ray_config rmem=%p\n",local->rmem); | ||
555 | DEBUG(3,"ray_config amem=%p\n",local->amem); | ||
556 | if (ray_init(dev) < 0) { | ||
557 | ray_release(link); | ||
558 | return; | ||
559 | } | ||
560 | |||
561 | SET_NETDEV_DEV(dev, &handle_to_dev(handle)); | ||
562 | i = register_netdev(dev); | ||
563 | if (i != 0) { | ||
564 | printk("ray_config register_netdev() failed\n"); | ||
565 | ray_release(link); | ||
566 | return; | ||
567 | } | ||
568 | |||
569 | strcpy(local->node.dev_name, dev->name); | ||
570 | link->dev = &local->node; | ||
571 | |||
572 | link->state &= ~DEV_CONFIG_PENDING; | ||
573 | printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", | ||
574 | dev->name, dev->irq); | ||
575 | for (i = 0; i < 6; i++) | ||
576 | printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); | ||
577 | |||
578 | return; | ||
579 | |||
580 | cs_failed: | ||
581 | cs_error(link->handle, last_fn, last_ret); | ||
582 | |||
583 | ray_release(link); | ||
584 | } /* ray_config */ | ||
585 | |||
586 | static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) | ||
587 | { | ||
588 | return dev->sram + CCS_BASE; | ||
589 | } | ||
590 | |||
591 | static inline struct rcs __iomem *rcs_base(ray_dev_t *dev) | ||
592 | { | ||
593 | /* | ||
594 | * This looks nonsensical, since there is a separate | ||
595 | * RCS_BASE. But the difference between a "struct rcs" | ||
596 | * and a "struct ccs" ends up being in the _index_ off | ||
597 | * the base, so the base pointer is the same for both | ||
598 | * ccs/rcs. | ||
599 | */ | ||
600 | return dev->sram + CCS_BASE; | ||
601 | } | ||
602 | |||
603 | /*===========================================================================*/ | ||
604 | static int ray_init(struct net_device *dev) | ||
605 | { | ||
606 | int i; | ||
607 | UCHAR *p; | ||
608 | struct ccs __iomem *pccs; | ||
609 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
610 | dev_link_t *link = local->finder; | ||
611 | DEBUG(1, "ray_init(0x%p)\n", dev); | ||
612 | if (!(link->state & DEV_PRESENT)) { | ||
613 | DEBUG(0,"ray_init - device not present\n"); | ||
614 | return -1; | ||
615 | } | ||
616 | |||
617 | local->net_type = net_type; | ||
618 | local->sta_type = TYPE_STA; | ||
619 | |||
620 | /* Copy the startup results to local memory */ | ||
621 | memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,\ | ||
622 | sizeof(struct startup_res_6)); | ||
623 | |||
624 | /* Check Power up test status and get mac address from card */ | ||
625 | if (local->startup_res.startup_word != 0x80) { | ||
626 | printk(KERN_INFO "ray_init ERROR card status = %2x\n", | ||
627 | local->startup_res.startup_word); | ||
628 | local->card_status = CARD_INIT_ERROR; | ||
629 | return -1; | ||
630 | } | ||
631 | |||
632 | local->fw_ver = local->startup_res.firmware_version[0]; | ||
633 | local->fw_bld = local->startup_res.firmware_version[1]; | ||
634 | local->fw_var = local->startup_res.firmware_version[2]; | ||
635 | DEBUG(1,"ray_init firmware version %d.%d \n",local->fw_ver, local->fw_bld); | ||
636 | |||
637 | local->tib_length = 0x20; | ||
638 | if ((local->fw_ver == 5) && (local->fw_bld >= 30)) | ||
639 | local->tib_length = local->startup_res.tib_length; | ||
640 | DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length); | ||
641 | /* Initialize CCS's to buffer free state */ | ||
642 | pccs = ccs_base(local); | ||
643 | for (i=0; i<NUMBER_OF_CCS; i++) { | ||
644 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
645 | } | ||
646 | init_startup_params(local); | ||
647 | |||
648 | /* copy mac address to startup parameters */ | ||
649 | if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) | ||
650 | { | ||
651 | p = local->sparm.b4.a_mac_addr; | ||
652 | } | ||
653 | else | ||
654 | { | ||
655 | memcpy(&local->sparm.b4.a_mac_addr, | ||
656 | &local->startup_res.station_addr, ADDRLEN); | ||
657 | p = local->sparm.b4.a_mac_addr; | ||
658 | } | ||
659 | |||
660 | clear_interrupt(local); /* Clear any interrupt from the card */ | ||
661 | local->card_status = CARD_AWAITING_PARAM; | ||
662 | DEBUG(2,"ray_init ending\n"); | ||
663 | return 0; | ||
664 | } /* ray_init */ | ||
665 | /*===========================================================================*/ | ||
666 | /* Download startup parameters to the card and command it to read them */ | ||
667 | static int dl_startup_params(struct net_device *dev) | ||
668 | { | ||
669 | int ccsindex; | ||
670 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
671 | struct ccs __iomem *pccs; | ||
672 | dev_link_t *link = local->finder; | ||
673 | |||
674 | DEBUG(1,"dl_startup_params entered\n"); | ||
675 | if (!(link->state & DEV_PRESENT)) { | ||
676 | DEBUG(2,"ray_cs dl_startup_params - device not present\n"); | ||
677 | return -1; | ||
678 | } | ||
679 | |||
680 | /* Copy parameters to host to ECF area */ | ||
681 | if (local->fw_ver == 0x55) | ||
682 | memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4, | ||
683 | sizeof(struct b4_startup_params)); | ||
684 | else | ||
685 | memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5, | ||
686 | sizeof(struct b5_startup_params)); | ||
687 | |||
688 | |||
689 | /* Fill in the CCS fields for the ECF */ | ||
690 | if ((ccsindex = get_free_ccs(local)) < 0) return -1; | ||
691 | local->dl_param_ccs = ccsindex; | ||
692 | pccs = ccs_base(local) + ccsindex; | ||
693 | writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); | ||
694 | DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); | ||
695 | /* Interrupt the firmware to process the command */ | ||
696 | if (interrupt_ecf(local, ccsindex)) { | ||
697 | printk(KERN_INFO "ray dl_startup_params failed - " | ||
698 | "ECF not ready for intr\n"); | ||
699 | local->card_status = CARD_DL_PARAM_ERROR; | ||
700 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
701 | return -2; | ||
702 | } | ||
703 | local->card_status = CARD_DL_PARAM; | ||
704 | /* Start kernel timer to wait for dl startup to complete. */ | ||
705 | local->timer.expires = jiffies + HZ/2; | ||
706 | local->timer.data = (long)local; | ||
707 | local->timer.function = &verify_dl_startup; | ||
708 | add_timer(&local->timer); | ||
709 | DEBUG(2,"ray_cs dl_startup_params started timer for verify_dl_startup\n"); | ||
710 | return 0; | ||
711 | } /* dl_startup_params */ | ||
712 | /*===========================================================================*/ | ||
713 | static void init_startup_params(ray_dev_t *local) | ||
714 | { | ||
715 | int i; | ||
716 | |||
717 | if (country > JAPAN_TEST) country = USA; | ||
718 | else | ||
719 | if (country < USA) country = USA; | ||
720 | /* structure for hop time and beacon period is defined here using | ||
721 | * New 802.11D6.1 format. Card firmware is still using old format | ||
722 | * until version 6. | ||
723 | * Before After | ||
724 | * a_hop_time ms byte a_hop_time ms byte | ||
725 | * a_hop_time 2s byte a_hop_time ls byte | ||
726 | * a_hop_time ls byte a_beacon_period ms byte | ||
727 | * a_beacon_period a_beacon_period ls byte | ||
728 | * | ||
729 | * a_hop_time = uS a_hop_time = KuS | ||
730 | * a_beacon_period = hops a_beacon_period = KuS | ||
731 | */ /* 64ms = 010000 */ | ||
732 | if (local->fw_ver == 0x55) { | ||
733 | memcpy((UCHAR *)&local->sparm.b4, b4_default_startup_parms, | ||
734 | sizeof(struct b4_startup_params)); | ||
735 | /* Translate sane kus input values to old build 4/5 format */ | ||
736 | /* i = hop time in uS truncated to 3 bytes */ | ||
737 | i = (hop_dwell * 1024) & 0xffffff; | ||
738 | local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff; | ||
739 | local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff; | ||
740 | local->sparm.b4.a_beacon_period[0] = 0; | ||
741 | local->sparm.b4.a_beacon_period[1] = | ||
742 | ((beacon_period/hop_dwell) - 1) & 0xff; | ||
743 | local->sparm.b4.a_curr_country_code = country; | ||
744 | local->sparm.b4.a_hop_pattern_length = | ||
745 | hop_pattern_length[(int)country] - 1; | ||
746 | if (bc) | ||
747 | { | ||
748 | local->sparm.b4.a_ack_timeout = 0x50; | ||
749 | local->sparm.b4.a_sifs = 0x3f; | ||
750 | } | ||
751 | } | ||
752 | else { /* Version 5 uses real kus values */ | ||
753 | memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, | ||
754 | sizeof(struct b5_startup_params)); | ||
755 | |||
756 | local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff; | ||
757 | local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff; | ||
758 | local->sparm.b5.a_beacon_period[0] = (beacon_period >> 8) & 0xff; | ||
759 | local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff; | ||
760 | if (psm) | ||
761 | local->sparm.b5.a_power_mgt_state = 1; | ||
762 | local->sparm.b5.a_curr_country_code = country; | ||
763 | local->sparm.b5.a_hop_pattern_length = | ||
764 | hop_pattern_length[(int)country]; | ||
765 | } | ||
766 | |||
767 | local->sparm.b4.a_network_type = net_type & 0x01; | ||
768 | local->sparm.b4.a_acting_as_ap_status = TYPE_STA; | ||
769 | |||
770 | if (essid != NULL) | ||
771 | strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); | ||
772 | } /* init_startup_params */ | ||
773 | /*===========================================================================*/ | ||
774 | static void verify_dl_startup(u_long data) | ||
775 | { | ||
776 | ray_dev_t *local = (ray_dev_t *)data; | ||
777 | struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; | ||
778 | UCHAR status; | ||
779 | dev_link_t *link = local->finder; | ||
780 | |||
781 | if (!(link->state & DEV_PRESENT)) { | ||
782 | DEBUG(2,"ray_cs verify_dl_startup - device not present\n"); | ||
783 | return; | ||
784 | } | ||
785 | #ifdef PCMCIA_DEBUG | ||
786 | if (pc_debug > 2) { | ||
787 | int i; | ||
788 | printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n", | ||
789 | local->dl_param_ccs); | ||
790 | for (i=0; i<sizeof(struct b5_startup_params); i++) { | ||
791 | printk(" %2x", (unsigned int) readb(local->sram + HOST_TO_ECF_BASE + i)); | ||
792 | } | ||
793 | printk("\n"); | ||
794 | } | ||
795 | #endif | ||
796 | |||
797 | status = readb(&pccs->buffer_status); | ||
798 | if (status!= CCS_BUFFER_FREE) | ||
799 | { | ||
800 | printk(KERN_INFO "Download startup params failed. Status = %d\n", | ||
801 | status); | ||
802 | local->card_status = CARD_DL_PARAM_ERROR; | ||
803 | return; | ||
804 | } | ||
805 | if (local->sparm.b4.a_network_type == ADHOC) | ||
806 | start_net((u_long)local); | ||
807 | else | ||
808 | join_net((u_long)local); | ||
809 | |||
810 | return; | ||
811 | } /* end verify_dl_startup */ | ||
812 | /*===========================================================================*/ | ||
813 | /* Command card to start a network */ | ||
814 | static void start_net(u_long data) | ||
815 | { | ||
816 | ray_dev_t *local = (ray_dev_t *)data; | ||
817 | struct ccs __iomem *pccs; | ||
818 | int ccsindex; | ||
819 | dev_link_t *link = local->finder; | ||
820 | if (!(link->state & DEV_PRESENT)) { | ||
821 | DEBUG(2,"ray_cs start_net - device not present\n"); | ||
822 | return; | ||
823 | } | ||
824 | /* Fill in the CCS fields for the ECF */ | ||
825 | if ((ccsindex = get_free_ccs(local)) < 0) return; | ||
826 | pccs = ccs_base(local) + ccsindex; | ||
827 | writeb(CCS_START_NETWORK, &pccs->cmd); | ||
828 | writeb(0, &pccs->var.start_network.update_param); | ||
829 | /* Interrupt the firmware to process the command */ | ||
830 | if (interrupt_ecf(local, ccsindex)) { | ||
831 | DEBUG(1,"ray start net failed - card not ready for intr\n"); | ||
832 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
833 | return; | ||
834 | } | ||
835 | local->card_status = CARD_DOING_ACQ; | ||
836 | return; | ||
837 | } /* end start_net */ | ||
838 | /*===========================================================================*/ | ||
839 | /* Command card to join a network */ | ||
840 | static void join_net(u_long data) | ||
841 | { | ||
842 | ray_dev_t *local = (ray_dev_t *)data; | ||
843 | |||
844 | struct ccs __iomem *pccs; | ||
845 | int ccsindex; | ||
846 | dev_link_t *link = local->finder; | ||
847 | |||
848 | if (!(link->state & DEV_PRESENT)) { | ||
849 | DEBUG(2,"ray_cs join_net - device not present\n"); | ||
850 | return; | ||
851 | } | ||
852 | /* Fill in the CCS fields for the ECF */ | ||
853 | if ((ccsindex = get_free_ccs(local)) < 0) return; | ||
854 | pccs = ccs_base(local) + ccsindex; | ||
855 | writeb(CCS_JOIN_NETWORK, &pccs->cmd); | ||
856 | writeb(0, &pccs->var.join_network.update_param); | ||
857 | writeb(0, &pccs->var.join_network.net_initiated); | ||
858 | /* Interrupt the firmware to process the command */ | ||
859 | if (interrupt_ecf(local, ccsindex)) { | ||
860 | DEBUG(1,"ray join net failed - card not ready for intr\n"); | ||
861 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
862 | return; | ||
863 | } | ||
864 | local->card_status = CARD_DOING_ACQ; | ||
865 | return; | ||
866 | } | ||
867 | /*============================================================================ | ||
868 | After a card is removed, ray_release() will unregister the net | ||
869 | device, and release the PCMCIA configuration. If the device is | ||
870 | still open, this will be postponed until it is closed. | ||
871 | =============================================================================*/ | ||
872 | static void ray_release(dev_link_t *link) | ||
873 | { | ||
874 | struct net_device *dev = link->priv; | ||
875 | ray_dev_t *local = dev->priv; | ||
876 | int i; | ||
877 | |||
878 | DEBUG(1, "ray_release(0x%p)\n", link); | ||
879 | |||
880 | del_timer(&local->timer); | ||
881 | link->state &= ~DEV_CONFIG; | ||
882 | |||
883 | iounmap(local->sram); | ||
884 | iounmap(local->rmem); | ||
885 | iounmap(local->amem); | ||
886 | /* Do bother checking to see if these succeed or not */ | ||
887 | i = pcmcia_release_window(link->win); | ||
888 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i); | ||
889 | i = pcmcia_release_window(local->amem_handle); | ||
890 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); | ||
891 | i = pcmcia_release_window(local->rmem_handle); | ||
892 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); | ||
893 | i = pcmcia_release_configuration(link->handle); | ||
894 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i); | ||
895 | i = pcmcia_release_irq(link->handle, &link->irq); | ||
896 | if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i); | ||
897 | |||
898 | DEBUG(2,"ray_release ending\n"); | ||
899 | } | ||
900 | |||
901 | /*============================================================================= | ||
902 | The card status event handler. Mostly, this schedules other | ||
903 | stuff to run after an event is received. A CARD_REMOVAL event | ||
904 | also sets some flags to discourage the net drivers from trying | ||
905 | to talk to the card any more. | ||
906 | |||
907 | When a CARD_REMOVAL event is received, we immediately set a flag | ||
908 | to block future accesses to this device. All the functions that | ||
909 | actually access the device should check this flag to make sure | ||
910 | the card is still present. | ||
911 | =============================================================================*/ | ||
912 | static int ray_event(event_t event, int priority, | ||
913 | event_callback_args_t *args) | ||
914 | { | ||
915 | dev_link_t *link = args->client_data; | ||
916 | struct net_device *dev = link->priv; | ||
917 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
918 | DEBUG(1, "ray_event(0x%06x)\n", event); | ||
919 | |||
920 | switch (event) { | ||
921 | case CS_EVENT_CARD_REMOVAL: | ||
922 | link->state &= ~DEV_PRESENT; | ||
923 | netif_device_detach(dev); | ||
924 | if (link->state & DEV_CONFIG) { | ||
925 | ray_release(link); | ||
926 | del_timer(&local->timer); | ||
927 | } | ||
928 | break; | ||
929 | case CS_EVENT_CARD_INSERTION: | ||
930 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
931 | ray_config(link); | ||
932 | break; | ||
933 | case CS_EVENT_PM_SUSPEND: | ||
934 | link->state |= DEV_SUSPEND; | ||
935 | /* Fall through... */ | ||
936 | case CS_EVENT_RESET_PHYSICAL: | ||
937 | if (link->state & DEV_CONFIG) { | ||
938 | if (link->open) | ||
939 | netif_device_detach(dev); | ||
940 | |||
941 | pcmcia_release_configuration(link->handle); | ||
942 | } | ||
943 | break; | ||
944 | case CS_EVENT_PM_RESUME: | ||
945 | link->state &= ~DEV_SUSPEND; | ||
946 | /* Fall through... */ | ||
947 | case CS_EVENT_CARD_RESET: | ||
948 | if (link->state & DEV_CONFIG) { | ||
949 | pcmcia_request_configuration(link->handle, &link->conf); | ||
950 | if (link->open) { | ||
951 | ray_reset(dev); | ||
952 | netif_device_attach(dev); | ||
953 | } | ||
954 | } | ||
955 | break; | ||
956 | } | ||
957 | return 0; | ||
958 | DEBUG(2,"ray_event ending\n"); | ||
959 | } /* ray_event */ | ||
960 | /*===========================================================================*/ | ||
961 | int ray_dev_init(struct net_device *dev) | ||
962 | { | ||
963 | #ifdef RAY_IMMEDIATE_INIT | ||
964 | int i; | ||
965 | #endif /* RAY_IMMEDIATE_INIT */ | ||
966 | ray_dev_t *local = dev->priv; | ||
967 | dev_link_t *link = local->finder; | ||
968 | |||
969 | DEBUG(1,"ray_dev_init(dev=%p)\n",dev); | ||
970 | if (!(link->state & DEV_PRESENT)) { | ||
971 | DEBUG(2,"ray_dev_init - device not present\n"); | ||
972 | return -1; | ||
973 | } | ||
974 | #ifdef RAY_IMMEDIATE_INIT | ||
975 | /* Download startup parameters */ | ||
976 | if ( (i = dl_startup_params(dev)) < 0) | ||
977 | { | ||
978 | printk(KERN_INFO "ray_dev_init dl_startup_params failed - " | ||
979 | "returns 0x%x\n",i); | ||
980 | return -1; | ||
981 | } | ||
982 | #else /* RAY_IMMEDIATE_INIT */ | ||
983 | /* Postpone the card init so that we can still configure the card, | ||
984 | * for example using the Wireless Extensions. The init will happen | ||
985 | * in ray_open() - Jean II */ | ||
986 | DEBUG(1,"ray_dev_init: postponing card init to ray_open() ; Status = %d\n", | ||
987 | local->card_status); | ||
988 | #endif /* RAY_IMMEDIATE_INIT */ | ||
989 | |||
990 | /* copy mac and broadcast addresses to linux device */ | ||
991 | memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); | ||
992 | memset(dev->broadcast, 0xff, ETH_ALEN); | ||
993 | |||
994 | DEBUG(2,"ray_dev_init ending\n"); | ||
995 | return 0; | ||
996 | } | ||
997 | /*===========================================================================*/ | ||
998 | static int ray_dev_config(struct net_device *dev, struct ifmap *map) | ||
999 | { | ||
1000 | ray_dev_t *local = dev->priv; | ||
1001 | dev_link_t *link = local->finder; | ||
1002 | /* Dummy routine to satisfy device structure */ | ||
1003 | DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); | ||
1004 | if (!(link->state & DEV_PRESENT)) { | ||
1005 | DEBUG(2,"ray_dev_config - device not present\n"); | ||
1006 | return -1; | ||
1007 | } | ||
1008 | |||
1009 | return 0; | ||
1010 | } | ||
1011 | /*===========================================================================*/ | ||
1012 | static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
1013 | { | ||
1014 | ray_dev_t *local = dev->priv; | ||
1015 | dev_link_t *link = local->finder; | ||
1016 | short length = skb->len; | ||
1017 | |||
1018 | if (!(link->state & DEV_PRESENT)) { | ||
1019 | DEBUG(2,"ray_dev_start_xmit - device not present\n"); | ||
1020 | return -1; | ||
1021 | } | ||
1022 | DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev); | ||
1023 | if (local->authentication_state == NEED_TO_AUTH) { | ||
1024 | DEBUG(0,"ray_cs Sending authentication request.\n"); | ||
1025 | if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) { | ||
1026 | local->authentication_state = AUTHENTICATED; | ||
1027 | netif_stop_queue(dev); | ||
1028 | return 1; | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | if (length < ETH_ZLEN) | ||
1033 | { | ||
1034 | skb = skb_padto(skb, ETH_ZLEN); | ||
1035 | if (skb == NULL) | ||
1036 | return 0; | ||
1037 | length = ETH_ZLEN; | ||
1038 | } | ||
1039 | switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) { | ||
1040 | case XMIT_NO_CCS: | ||
1041 | case XMIT_NEED_AUTH: | ||
1042 | netif_stop_queue(dev); | ||
1043 | return 1; | ||
1044 | case XMIT_NO_INTR: | ||
1045 | case XMIT_MSG_BAD: | ||
1046 | case XMIT_OK: | ||
1047 | default: | ||
1048 | dev->trans_start = jiffies; | ||
1049 | dev_kfree_skb(skb); | ||
1050 | return 0; | ||
1051 | } | ||
1052 | return 0; | ||
1053 | } /* ray_dev_start_xmit */ | ||
1054 | /*===========================================================================*/ | ||
1055 | static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, | ||
1056 | UCHAR msg_type) | ||
1057 | { | ||
1058 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1059 | struct ccs __iomem *pccs; | ||
1060 | int ccsindex; | ||
1061 | int offset; | ||
1062 | struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ | ||
1063 | short int addr; /* Address of xmit buffer in card space */ | ||
1064 | |||
1065 | DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev); | ||
1066 | if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) | ||
1067 | { | ||
1068 | printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len); | ||
1069 | return XMIT_MSG_BAD; | ||
1070 | } | ||
1071 | switch (ccsindex = get_free_tx_ccs(local)) { | ||
1072 | case ECCSBUSY: | ||
1073 | DEBUG(2,"ray_hw_xmit tx_ccs table busy\n"); | ||
1074 | case ECCSFULL: | ||
1075 | DEBUG(2,"ray_hw_xmit No free tx ccs\n"); | ||
1076 | case ECARDGONE: | ||
1077 | netif_stop_queue(dev); | ||
1078 | return XMIT_NO_CCS; | ||
1079 | default: | ||
1080 | break; | ||
1081 | } | ||
1082 | addr = TX_BUF_BASE + (ccsindex << 11); | ||
1083 | |||
1084 | if (msg_type == DATA_TYPE) { | ||
1085 | local->stats.tx_bytes += len; | ||
1086 | local->stats.tx_packets++; | ||
1087 | } | ||
1088 | |||
1089 | ptx = local->sram + addr; | ||
1090 | |||
1091 | ray_build_header(local, ptx, msg_type, data); | ||
1092 | if (translate) { | ||
1093 | offset = translate_frame(local, ptx, data, len); | ||
1094 | } | ||
1095 | else { /* Encapsulate frame */ | ||
1096 | /* TBD TIB length will move address of ptx->var */ | ||
1097 | memcpy_toio(&ptx->var, data, len); | ||
1098 | offset = 0; | ||
1099 | } | ||
1100 | |||
1101 | /* fill in the CCS */ | ||
1102 | pccs = ccs_base(local) + ccsindex; | ||
1103 | len += TX_HEADER_LENGTH + offset; | ||
1104 | writeb(CCS_TX_REQUEST, &pccs->cmd); | ||
1105 | writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); | ||
1106 | writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]); | ||
1107 | writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]); | ||
1108 | writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]); | ||
1109 | /* TBD still need psm_cam? */ | ||
1110 | writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); | ||
1111 | writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); | ||
1112 | writeb(0, &pccs->var.tx_request.antenna); | ||
1113 | DEBUG(3,"ray_hw_xmit default_tx_rate = 0x%x\n",\ | ||
1114 | local->net_default_tx_rate); | ||
1115 | |||
1116 | /* Interrupt the firmware to process the command */ | ||
1117 | if (interrupt_ecf(local, ccsindex)) { | ||
1118 | DEBUG(2,"ray_hw_xmit failed - ECF not ready for intr\n"); | ||
1119 | /* TBD very inefficient to copy packet to buffer, and then not | ||
1120 | send it, but the alternative is to queue the messages and that | ||
1121 | won't be done for a while. Maybe set tbusy until a CCS is free? | ||
1122 | */ | ||
1123 | writeb(CCS_BUFFER_FREE, &pccs->buffer_status); | ||
1124 | return XMIT_NO_INTR; | ||
1125 | } | ||
1126 | return XMIT_OK; | ||
1127 | } /* end ray_hw_xmit */ | ||
1128 | /*===========================================================================*/ | ||
1129 | static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, | ||
1130 | int len) | ||
1131 | { | ||
1132 | unsigned short int proto = ((struct ethhdr *)data)->h_proto; | ||
1133 | if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ | ||
1134 | DEBUG(3,"ray_cs translate_frame DIX II\n"); | ||
1135 | /* Copy LLC header to card buffer */ | ||
1136 | memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); | ||
1137 | memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); | ||
1138 | if ((proto == 0xf380) || (proto == 0x3781)) { | ||
1139 | /* This is the selective translation table, only 2 entries */ | ||
1140 | writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); | ||
1141 | } | ||
1142 | /* Copy body of ethernet packet without ethernet header */ | ||
1143 | memcpy_toio((void __iomem *)&ptx->var + sizeof(struct snaphdr_t), \ | ||
1144 | data + ETH_HLEN, len - ETH_HLEN); | ||
1145 | return (int) sizeof(struct snaphdr_t) - ETH_HLEN; | ||
1146 | } | ||
1147 | else { /* already 802 type, and proto is length */ | ||
1148 | DEBUG(3,"ray_cs translate_frame 802\n"); | ||
1149 | if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ | ||
1150 | DEBUG(3,"ray_cs translate_frame evil IPX\n"); | ||
1151 | memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); | ||
1152 | return 0 - ETH_HLEN; | ||
1153 | } | ||
1154 | memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); | ||
1155 | return 0 - ETH_HLEN; | ||
1156 | } | ||
1157 | /* TBD do other frame types */ | ||
1158 | } /* end translate_frame */ | ||
1159 | /*===========================================================================*/ | ||
1160 | static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type, | ||
1161 | unsigned char *data) | ||
1162 | { | ||
1163 | writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); | ||
1164 | /*** IEEE 802.11 Address field assignments ************* | ||
1165 | TODS FROMDS addr_1 addr_2 addr_3 addr_4 | ||
1166 | Adhoc 0 0 dest src (terminal) BSSID N/A | ||
1167 | AP to Terminal 0 1 dest AP(BSSID) source N/A | ||
1168 | Terminal to AP 1 0 AP(BSSID) src (terminal) dest N/A | ||
1169 | AP to AP 1 1 dest AP src AP dest source | ||
1170 | *******************************************************/ | ||
1171 | if (local->net_type == ADHOC) { | ||
1172 | writeb(0, &ptx->mac.frame_ctl_2); | ||
1173 | memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, 2 * ADDRLEN); | ||
1174 | memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); | ||
1175 | } | ||
1176 | else /* infrastructure */ | ||
1177 | { | ||
1178 | if (local->sparm.b4.a_acting_as_ap_status) | ||
1179 | { | ||
1180 | writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2); | ||
1181 | memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, ADDRLEN); | ||
1182 | memcpy_toio(ptx->mac.addr_2, local->bss_id, 6); | ||
1183 | memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_source, ADDRLEN); | ||
1184 | } | ||
1185 | else /* Terminal */ | ||
1186 | { | ||
1187 | writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2); | ||
1188 | memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN); | ||
1189 | memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, ADDRLEN); | ||
1190 | memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_dest, ADDRLEN); | ||
1191 | } | ||
1192 | } | ||
1193 | } /* end encapsulate_frame */ | ||
1194 | |||
1195 | |||
1196 | /*===========================================================================*/ | ||
1197 | |||
1198 | static void netdev_get_drvinfo(struct net_device *dev, | ||
1199 | struct ethtool_drvinfo *info) | ||
1200 | { | ||
1201 | strcpy(info->driver, "ray_cs"); | ||
1202 | } | ||
1203 | |||
1204 | static struct ethtool_ops netdev_ethtool_ops = { | ||
1205 | .get_drvinfo = netdev_get_drvinfo, | ||
1206 | }; | ||
1207 | |||
1208 | /*====================================================================*/ | ||
1209 | |||
1210 | static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1211 | { | ||
1212 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1213 | dev_link_t *link = local->finder; | ||
1214 | int err = 0; | ||
1215 | #if WIRELESS_EXT > 7 | ||
1216 | struct iwreq *wrq = (struct iwreq *) ifr; | ||
1217 | #endif /* WIRELESS_EXT > 7 */ | ||
1218 | #ifdef WIRELESS_SPY | ||
1219 | struct sockaddr address[IW_MAX_SPY]; | ||
1220 | #endif /* WIRELESS_SPY */ | ||
1221 | |||
1222 | if (!(link->state & DEV_PRESENT)) { | ||
1223 | DEBUG(2,"ray_dev_ioctl - device not present\n"); | ||
1224 | return -1; | ||
1225 | } | ||
1226 | DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd); | ||
1227 | /* Validate the command */ | ||
1228 | switch (cmd) | ||
1229 | { | ||
1230 | #if WIRELESS_EXT > 7 | ||
1231 | /* --------------- WIRELESS EXTENSIONS --------------- */ | ||
1232 | /* Get name */ | ||
1233 | case SIOCGIWNAME: | ||
1234 | strcpy(wrq->u.name, "IEEE 802.11-FH"); | ||
1235 | break; | ||
1236 | |||
1237 | /* Get frequency/channel */ | ||
1238 | case SIOCGIWFREQ: | ||
1239 | wrq->u.freq.m = local->sparm.b5.a_hop_pattern; | ||
1240 | wrq->u.freq.e = 0; | ||
1241 | break; | ||
1242 | |||
1243 | /* Set frequency/channel */ | ||
1244 | case SIOCSIWFREQ: | ||
1245 | /* Reject if card is already initialised */ | ||
1246 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1247 | { | ||
1248 | err = -EBUSY; | ||
1249 | break; | ||
1250 | } | ||
1251 | |||
1252 | /* Setting by channel number */ | ||
1253 | if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0)) | ||
1254 | err = -EOPNOTSUPP; | ||
1255 | else | ||
1256 | local->sparm.b5.a_hop_pattern = wrq->u.freq.m; | ||
1257 | break; | ||
1258 | |||
1259 | /* Get current network name (ESSID) */ | ||
1260 | case SIOCGIWESSID: | ||
1261 | if (wrq->u.data.pointer) | ||
1262 | { | ||
1263 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
1264 | /* Get the essid that was set */ | ||
1265 | memcpy(essid, local->sparm.b5.a_current_ess_id, | ||
1266 | IW_ESSID_MAX_SIZE); | ||
1267 | essid[IW_ESSID_MAX_SIZE] = '\0'; | ||
1268 | |||
1269 | /* Push it out ! */ | ||
1270 | wrq->u.data.length = strlen(essid) + 1; | ||
1271 | wrq->u.data.flags = 1; /* active */ | ||
1272 | if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid))) | ||
1273 | err = -EFAULT; | ||
1274 | } | ||
1275 | break; | ||
1276 | |||
1277 | /* Set desired network name (ESSID) */ | ||
1278 | case SIOCSIWESSID: | ||
1279 | /* Reject if card is already initialised */ | ||
1280 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1281 | { | ||
1282 | err = -EBUSY; | ||
1283 | break; | ||
1284 | } | ||
1285 | |||
1286 | if (wrq->u.data.pointer) | ||
1287 | { | ||
1288 | char card_essid[IW_ESSID_MAX_SIZE + 1]; | ||
1289 | |||
1290 | /* Check if we asked for `any' */ | ||
1291 | if(wrq->u.data.flags == 0) | ||
1292 | { | ||
1293 | /* Corey : can you do that ? */ | ||
1294 | err = -EOPNOTSUPP; | ||
1295 | } | ||
1296 | else | ||
1297 | { | ||
1298 | /* Check the size of the string */ | ||
1299 | if(wrq->u.data.length > | ||
1300 | IW_ESSID_MAX_SIZE + 1) | ||
1301 | { | ||
1302 | err = -E2BIG; | ||
1303 | break; | ||
1304 | } | ||
1305 | if (copy_from_user(card_essid, | ||
1306 | wrq->u.data.pointer, | ||
1307 | wrq->u.data.length)) { | ||
1308 | err = -EFAULT; | ||
1309 | break; | ||
1310 | } | ||
1311 | card_essid[IW_ESSID_MAX_SIZE] = '\0'; | ||
1312 | |||
1313 | /* Set the ESSID in the card */ | ||
1314 | memcpy(local->sparm.b5.a_current_ess_id, card_essid, | ||
1315 | IW_ESSID_MAX_SIZE); | ||
1316 | } | ||
1317 | } | ||
1318 | break; | ||
1319 | |||
1320 | /* Get current Access Point (BSSID in our case) */ | ||
1321 | case SIOCGIWAP: | ||
1322 | memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN); | ||
1323 | wrq->u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1324 | break; | ||
1325 | |||
1326 | /* Get the current bit-rate */ | ||
1327 | case SIOCGIWRATE: | ||
1328 | if(local->net_default_tx_rate == 3) | ||
1329 | wrq->u.bitrate.value = 2000000; /* Hum... */ | ||
1330 | else | ||
1331 | wrq->u.bitrate.value = local->net_default_tx_rate * 500000; | ||
1332 | wrq->u.bitrate.fixed = 0; /* We are in auto mode */ | ||
1333 | break; | ||
1334 | |||
1335 | /* Set the desired bit-rate */ | ||
1336 | case SIOCSIWRATE: | ||
1337 | /* Check if rate is in range */ | ||
1338 | if((wrq->u.bitrate.value != 1000000) && | ||
1339 | (wrq->u.bitrate.value != 2000000)) | ||
1340 | { | ||
1341 | err = -EINVAL; | ||
1342 | break; | ||
1343 | } | ||
1344 | /* Hack for 1.5 Mb/s instead of 2 Mb/s */ | ||
1345 | if((local->fw_ver == 0x55) && /* Please check */ | ||
1346 | (wrq->u.bitrate.value == 2000000)) | ||
1347 | local->net_default_tx_rate = 3; | ||
1348 | else | ||
1349 | local->net_default_tx_rate = wrq->u.bitrate.value/500000; | ||
1350 | break; | ||
1351 | |||
1352 | /* Get the current RTS threshold */ | ||
1353 | case SIOCGIWRTS: | ||
1354 | wrq->u.rts.value = (local->sparm.b5.a_rts_threshold[0] << 8) | ||
1355 | + local->sparm.b5.a_rts_threshold[1]; | ||
1356 | #if WIRELESS_EXT > 8 | ||
1357 | wrq->u.rts.disabled = (wrq->u.rts.value == 32767); | ||
1358 | #endif /* WIRELESS_EXT > 8 */ | ||
1359 | wrq->u.rts.fixed = 1; | ||
1360 | break; | ||
1361 | |||
1362 | /* Set the desired RTS threshold */ | ||
1363 | case SIOCSIWRTS: | ||
1364 | { | ||
1365 | int rthr = wrq->u.rts.value; | ||
1366 | |||
1367 | /* Reject if card is already initialised */ | ||
1368 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1369 | { | ||
1370 | err = -EBUSY; | ||
1371 | break; | ||
1372 | } | ||
1373 | |||
1374 | /* if(wrq->u.rts.fixed == 0) we should complain */ | ||
1375 | #if WIRELESS_EXT > 8 | ||
1376 | if(wrq->u.rts.disabled) | ||
1377 | rthr = 32767; | ||
1378 | else | ||
1379 | #endif /* WIRELESS_EXT > 8 */ | ||
1380 | if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ | ||
1381 | { | ||
1382 | err = -EINVAL; | ||
1383 | break; | ||
1384 | } | ||
1385 | local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF; | ||
1386 | local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF; | ||
1387 | } | ||
1388 | break; | ||
1389 | |||
1390 | /* Get the current fragmentation threshold */ | ||
1391 | case SIOCGIWFRAG: | ||
1392 | wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) | ||
1393 | + local->sparm.b5.a_frag_threshold[1]; | ||
1394 | #if WIRELESS_EXT > 8 | ||
1395 | wrq->u.frag.disabled = (wrq->u.frag.value == 32767); | ||
1396 | #endif /* WIRELESS_EXT > 8 */ | ||
1397 | wrq->u.frag.fixed = 1; | ||
1398 | break; | ||
1399 | |||
1400 | /* Set the desired fragmentation threshold */ | ||
1401 | case SIOCSIWFRAG: | ||
1402 | { | ||
1403 | int fthr = wrq->u.frag.value; | ||
1404 | |||
1405 | /* Reject if card is already initialised */ | ||
1406 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1407 | { | ||
1408 | err = -EBUSY; | ||
1409 | break; | ||
1410 | } | ||
1411 | |||
1412 | /* if(wrq->u.frag.fixed == 0) should complain */ | ||
1413 | #if WIRELESS_EXT > 8 | ||
1414 | if(wrq->u.frag.disabled) | ||
1415 | fthr = 32767; | ||
1416 | else | ||
1417 | #endif /* WIRELESS_EXT > 8 */ | ||
1418 | if((fthr < 256) || (fthr > 2347)) /* To check out ! */ | ||
1419 | { | ||
1420 | err = -EINVAL; | ||
1421 | break; | ||
1422 | } | ||
1423 | local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF; | ||
1424 | local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF; | ||
1425 | } | ||
1426 | break; | ||
1427 | |||
1428 | #endif /* WIRELESS_EXT > 7 */ | ||
1429 | #if WIRELESS_EXT > 8 | ||
1430 | |||
1431 | /* Get the current mode of operation */ | ||
1432 | case SIOCGIWMODE: | ||
1433 | if(local->sparm.b5.a_network_type) | ||
1434 | wrq->u.mode = IW_MODE_INFRA; | ||
1435 | else | ||
1436 | wrq->u.mode = IW_MODE_ADHOC; | ||
1437 | break; | ||
1438 | |||
1439 | /* Set the current mode of operation */ | ||
1440 | case SIOCSIWMODE: | ||
1441 | { | ||
1442 | char card_mode = 1; | ||
1443 | |||
1444 | /* Reject if card is already initialised */ | ||
1445 | if(local->card_status != CARD_AWAITING_PARAM) | ||
1446 | { | ||
1447 | err = -EBUSY; | ||
1448 | break; | ||
1449 | } | ||
1450 | |||
1451 | switch (wrq->u.mode) | ||
1452 | { | ||
1453 | case IW_MODE_ADHOC: | ||
1454 | card_mode = 0; | ||
1455 | // Fall through | ||
1456 | case IW_MODE_INFRA: | ||
1457 | local->sparm.b5.a_network_type = card_mode; | ||
1458 | break; | ||
1459 | default: | ||
1460 | err = -EINVAL; | ||
1461 | } | ||
1462 | } | ||
1463 | break; | ||
1464 | |||
1465 | #endif /* WIRELESS_EXT > 8 */ | ||
1466 | #if WIRELESS_EXT > 7 | ||
1467 | /* ------------------ IWSPY SUPPORT ------------------ */ | ||
1468 | /* Define the range (variations) of above parameters */ | ||
1469 | case SIOCGIWRANGE: | ||
1470 | /* Basic checking... */ | ||
1471 | if(wrq->u.data.pointer != (caddr_t) 0) | ||
1472 | { | ||
1473 | struct iw_range range; | ||
1474 | memset((char *) &range, 0, sizeof(struct iw_range)); | ||
1475 | |||
1476 | /* Set the length (very important for backward compatibility) */ | ||
1477 | wrq->u.data.length = sizeof(struct iw_range); | ||
1478 | |||
1479 | #if WIRELESS_EXT > 10 | ||
1480 | /* Set the Wireless Extension versions */ | ||
1481 | range.we_version_compiled = WIRELESS_EXT; | ||
1482 | range.we_version_source = 9; | ||
1483 | #endif /* WIRELESS_EXT > 10 */ | ||
1484 | |||
1485 | /* Set information in the range struct */ | ||
1486 | range.throughput = 1.1 * 1000 * 1000; /* Put the right number here */ | ||
1487 | range.num_channels = hop_pattern_length[(int)country]; | ||
1488 | range.num_frequency = 0; | ||
1489 | range.max_qual.qual = 0; | ||
1490 | range.max_qual.level = 255; /* What's the correct value ? */ | ||
1491 | range.max_qual.noise = 255; /* Idem */ | ||
1492 | range.num_bitrates = 2; | ||
1493 | range.bitrate[0] = 1000000; /* 1 Mb/s */ | ||
1494 | range.bitrate[1] = 2000000; /* 2 Mb/s */ | ||
1495 | |||
1496 | /* Copy structure to the user buffer */ | ||
1497 | if(copy_to_user(wrq->u.data.pointer, &range, | ||
1498 | sizeof(struct iw_range))) | ||
1499 | err = -EFAULT; | ||
1500 | } | ||
1501 | break; | ||
1502 | |||
1503 | #ifdef WIRELESS_SPY | ||
1504 | /* Set addresses to spy */ | ||
1505 | case SIOCSIWSPY: | ||
1506 | /* Check the number of addresses */ | ||
1507 | if(wrq->u.data.length > IW_MAX_SPY) | ||
1508 | { | ||
1509 | err = -E2BIG; | ||
1510 | break; | ||
1511 | } | ||
1512 | local->spy_number = wrq->u.data.length; | ||
1513 | |||
1514 | /* If there is some addresses to copy */ | ||
1515 | if(local->spy_number > 0) | ||
1516 | { | ||
1517 | int i; | ||
1518 | |||
1519 | /* Copy addresses to the driver */ | ||
1520 | if(copy_from_user(address, wrq->u.data.pointer, | ||
1521 | sizeof(struct sockaddr) * local->spy_number)) | ||
1522 | { | ||
1523 | err = -EFAULT; | ||
1524 | break; | ||
1525 | } | ||
1526 | |||
1527 | /* Copy addresses to the lp structure */ | ||
1528 | for(i = 0; i < local->spy_number; i++) | ||
1529 | memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN); | ||
1530 | |||
1531 | /* Reset structure... */ | ||
1532 | memset(local->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); | ||
1533 | |||
1534 | #ifdef DEBUG_IOCTL_INFO | ||
1535 | printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); | ||
1536 | for(i = 0; i < local->spy_number; i++) | ||
1537 | printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n", | ||
1538 | local->spy_address[i][0], | ||
1539 | local->spy_address[i][1], | ||
1540 | local->spy_address[i][2], | ||
1541 | local->spy_address[i][3], | ||
1542 | local->spy_address[i][4], | ||
1543 | local->spy_address[i][5]); | ||
1544 | #endif /* DEBUG_IOCTL_INFO */ | ||
1545 | } | ||
1546 | break; | ||
1547 | |||
1548 | /* Get the spy list and spy stats */ | ||
1549 | case SIOCGIWSPY: | ||
1550 | /* Set the number of addresses */ | ||
1551 | wrq->u.data.length = local->spy_number; | ||
1552 | |||
1553 | /* If the user want to have the addresses back... */ | ||
1554 | if((local->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) | ||
1555 | { | ||
1556 | int i; | ||
1557 | |||
1558 | /* Copy addresses from the lp structure */ | ||
1559 | for(i = 0; i < local->spy_number; i++) | ||
1560 | { | ||
1561 | memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN); | ||
1562 | address[i].sa_family = ARPHRD_ETHER; | ||
1563 | } | ||
1564 | |||
1565 | /* Copy addresses to the user buffer */ | ||
1566 | if(copy_to_user(wrq->u.data.pointer, address, | ||
1567 | sizeof(struct sockaddr) * local->spy_number)) | ||
1568 | { | ||
1569 | err = -EFAULT; | ||
1570 | break; | ||
1571 | } | ||
1572 | |||
1573 | /* Copy stats to the user buffer (just after) */ | ||
1574 | if(copy_to_user(wrq->u.data.pointer + | ||
1575 | (sizeof(struct sockaddr) * local->spy_number), | ||
1576 | local->spy_stat, sizeof(iw_qual) * local->spy_number)) | ||
1577 | { | ||
1578 | err = -EFAULT; | ||
1579 | break; | ||
1580 | } | ||
1581 | |||
1582 | /* Reset updated flags */ | ||
1583 | for(i = 0; i < local->spy_number; i++) | ||
1584 | local->spy_stat[i].updated = 0x0; | ||
1585 | } /* if(pointer != NULL) */ | ||
1586 | |||
1587 | break; | ||
1588 | #endif /* WIRELESS_SPY */ | ||
1589 | |||
1590 | /* ------------------ PRIVATE IOCTL ------------------ */ | ||
1591 | #ifndef SIOCIWFIRSTPRIV | ||
1592 | #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE | ||
1593 | #endif /* SIOCIWFIRSTPRIV */ | ||
1594 | #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ | ||
1595 | #define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */ | ||
1596 | #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ | ||
1597 | case SIOCSIPFRAMING: | ||
1598 | if(!capable(CAP_NET_ADMIN)) /* For private IOCTLs, we need to check permissions */ | ||
1599 | { | ||
1600 | err = -EPERM; | ||
1601 | break; | ||
1602 | } | ||
1603 | translate = *(wrq->u.name); /* Set framing mode */ | ||
1604 | break; | ||
1605 | case SIOCGIPFRAMING: | ||
1606 | *(wrq->u.name) = translate; | ||
1607 | break; | ||
1608 | case SIOCGIPCOUNTRY: | ||
1609 | *(wrq->u.name) = country; | ||
1610 | break; | ||
1611 | case SIOCGIWPRIV: | ||
1612 | /* Export our "private" intercace */ | ||
1613 | if(wrq->u.data.pointer != (caddr_t) 0) | ||
1614 | { | ||
1615 | struct iw_priv_args priv[] = | ||
1616 | { /* cmd, set_args, get_args, name */ | ||
1617 | { SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" }, | ||
1618 | { SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" }, | ||
1619 | { SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" }, | ||
1620 | }; | ||
1621 | /* Set the number of ioctl available */ | ||
1622 | wrq->u.data.length = 3; | ||
1623 | /* Copy structure to the user buffer */ | ||
1624 | if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, | ||
1625 | sizeof(priv))) | ||
1626 | err = -EFAULT; | ||
1627 | } | ||
1628 | break; | ||
1629 | #endif /* WIRELESS_EXT > 7 */ | ||
1630 | |||
1631 | |||
1632 | default: | ||
1633 | DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd); | ||
1634 | err = -EOPNOTSUPP; | ||
1635 | } | ||
1636 | return err; | ||
1637 | } /* end ray_dev_ioctl */ | ||
1638 | /*===========================================================================*/ | ||
1639 | #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ | ||
1640 | static iw_stats * ray_get_wireless_stats(struct net_device * dev) | ||
1641 | { | ||
1642 | ray_dev_t * local = (ray_dev_t *) dev->priv; | ||
1643 | dev_link_t *link = local->finder; | ||
1644 | struct status __iomem *p = local->sram + STATUS_BASE; | ||
1645 | |||
1646 | if(local == (ray_dev_t *) NULL) | ||
1647 | return (iw_stats *) NULL; | ||
1648 | |||
1649 | local->wstats.status = local->card_status; | ||
1650 | #ifdef WIRELESS_SPY | ||
1651 | if((local->spy_number > 0) && (local->sparm.b5.a_network_type == 0)) | ||
1652 | { | ||
1653 | /* Get it from the first node in spy list */ | ||
1654 | local->wstats.qual.qual = local->spy_stat[0].qual; | ||
1655 | local->wstats.qual.level = local->spy_stat[0].level; | ||
1656 | local->wstats.qual.noise = local->spy_stat[0].noise; | ||
1657 | local->wstats.qual.updated = local->spy_stat[0].updated; | ||
1658 | } | ||
1659 | #endif /* WIRELESS_SPY */ | ||
1660 | |||
1661 | if((link->state & DEV_PRESENT)) { | ||
1662 | local->wstats.qual.noise = readb(&p->rxnoise); | ||
1663 | local->wstats.qual.updated |= 4; | ||
1664 | } | ||
1665 | |||
1666 | return &local->wstats; | ||
1667 | } /* end ray_get_wireless_stats */ | ||
1668 | #endif /* WIRELESS_EXT > 7 */ | ||
1669 | /*===========================================================================*/ | ||
1670 | static int ray_open(struct net_device *dev) | ||
1671 | { | ||
1672 | dev_link_t *link; | ||
1673 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1674 | |||
1675 | DEBUG(1, "ray_open('%s')\n", dev->name); | ||
1676 | |||
1677 | for (link = dev_list; link; link = link->next) | ||
1678 | if (link->priv == dev) break; | ||
1679 | if (!DEV_OK(link)) { | ||
1680 | return -ENODEV; | ||
1681 | } | ||
1682 | |||
1683 | if (link->open == 0) local->num_multi = 0; | ||
1684 | link->open++; | ||
1685 | |||
1686 | /* If the card is not started, time to start it ! - Jean II */ | ||
1687 | if(local->card_status == CARD_AWAITING_PARAM) { | ||
1688 | int i; | ||
1689 | |||
1690 | DEBUG(1,"ray_open: doing init now !\n"); | ||
1691 | |||
1692 | /* Download startup parameters */ | ||
1693 | if ( (i = dl_startup_params(dev)) < 0) | ||
1694 | { | ||
1695 | printk(KERN_INFO "ray_dev_init dl_startup_params failed - " | ||
1696 | "returns 0x%x\n",i); | ||
1697 | return -1; | ||
1698 | } | ||
1699 | } | ||
1700 | |||
1701 | if (sniffer) netif_stop_queue(dev); | ||
1702 | else netif_start_queue(dev); | ||
1703 | |||
1704 | DEBUG(2,"ray_open ending\n"); | ||
1705 | return 0; | ||
1706 | } /* end ray_open */ | ||
1707 | /*===========================================================================*/ | ||
1708 | static int ray_dev_close(struct net_device *dev) | ||
1709 | { | ||
1710 | dev_link_t *link; | ||
1711 | |||
1712 | DEBUG(1, "ray_dev_close('%s')\n", dev->name); | ||
1713 | |||
1714 | for (link = dev_list; link; link = link->next) | ||
1715 | if (link->priv == dev) break; | ||
1716 | if (link == NULL) | ||
1717 | return -ENODEV; | ||
1718 | |||
1719 | link->open--; | ||
1720 | netif_stop_queue(dev); | ||
1721 | |||
1722 | /* In here, we should stop the hardware (stop card from beeing active) | ||
1723 | * and set local->card_status to CARD_AWAITING_PARAM, so that while the | ||
1724 | * card is closed we can chage its configuration. | ||
1725 | * Probably also need a COR reset to get sane state - Jean II */ | ||
1726 | |||
1727 | return 0; | ||
1728 | } /* end ray_dev_close */ | ||
1729 | /*===========================================================================*/ | ||
1730 | static void ray_reset(struct net_device *dev) { | ||
1731 | DEBUG(1,"ray_reset entered\n"); | ||
1732 | return; | ||
1733 | } | ||
1734 | /*===========================================================================*/ | ||
1735 | /* Cause a firmware interrupt if it is ready for one */ | ||
1736 | /* Return nonzero if not ready */ | ||
1737 | static int interrupt_ecf(ray_dev_t *local, int ccs) | ||
1738 | { | ||
1739 | int i = 50; | ||
1740 | dev_link_t *link = local->finder; | ||
1741 | |||
1742 | if (!(link->state & DEV_PRESENT)) { | ||
1743 | DEBUG(2,"ray_cs interrupt_ecf - device not present\n"); | ||
1744 | return -1; | ||
1745 | } | ||
1746 | DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs); | ||
1747 | |||
1748 | while ( i && | ||
1749 | (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET)) | ||
1750 | i--; | ||
1751 | if (i == 0) { | ||
1752 | DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n"); | ||
1753 | return -1; | ||
1754 | } | ||
1755 | /* Fill the mailbox, then kick the card */ | ||
1756 | writeb(ccs, local->sram + SCB_BASE); | ||
1757 | writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET); | ||
1758 | return 0; | ||
1759 | } /* interrupt_ecf */ | ||
1760 | /*===========================================================================*/ | ||
1761 | /* Get next free transmit CCS */ | ||
1762 | /* Return - index of current tx ccs */ | ||
1763 | static int get_free_tx_ccs(ray_dev_t *local) | ||
1764 | { | ||
1765 | int i; | ||
1766 | struct ccs __iomem *pccs = ccs_base(local); | ||
1767 | dev_link_t *link = local->finder; | ||
1768 | |||
1769 | if (!(link->state & DEV_PRESENT)) { | ||
1770 | DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n"); | ||
1771 | return ECARDGONE; | ||
1772 | } | ||
1773 | |||
1774 | if (test_and_set_bit(0,&local->tx_ccs_lock)) { | ||
1775 | DEBUG(1,"ray_cs tx_ccs_lock busy\n"); | ||
1776 | return ECCSBUSY; | ||
1777 | } | ||
1778 | |||
1779 | for (i=0; i < NUMBER_OF_TX_CCS; i++) { | ||
1780 | if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { | ||
1781 | writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); | ||
1782 | writeb(CCS_END_LIST, &(pccs+i)->link); | ||
1783 | local->tx_ccs_lock = 0; | ||
1784 | return i; | ||
1785 | } | ||
1786 | } | ||
1787 | local->tx_ccs_lock = 0; | ||
1788 | DEBUG(2,"ray_cs ERROR no free tx CCS for raylink card\n"); | ||
1789 | return ECCSFULL; | ||
1790 | } /* get_free_tx_ccs */ | ||
1791 | /*===========================================================================*/ | ||
1792 | /* Get next free CCS */ | ||
1793 | /* Return - index of current ccs */ | ||
1794 | static int get_free_ccs(ray_dev_t *local) | ||
1795 | { | ||
1796 | int i; | ||
1797 | struct ccs __iomem *pccs = ccs_base(local); | ||
1798 | dev_link_t *link = local->finder; | ||
1799 | |||
1800 | if (!(link->state & DEV_PRESENT)) { | ||
1801 | DEBUG(2,"ray_cs get_free_ccs - device not present\n"); | ||
1802 | return ECARDGONE; | ||
1803 | } | ||
1804 | if (test_and_set_bit(0,&local->ccs_lock)) { | ||
1805 | DEBUG(1,"ray_cs ccs_lock busy\n"); | ||
1806 | return ECCSBUSY; | ||
1807 | } | ||
1808 | |||
1809 | for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) { | ||
1810 | if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { | ||
1811 | writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); | ||
1812 | writeb(CCS_END_LIST, &(pccs+i)->link); | ||
1813 | local->ccs_lock = 0; | ||
1814 | return i; | ||
1815 | } | ||
1816 | } | ||
1817 | local->ccs_lock = 0; | ||
1818 | DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n"); | ||
1819 | return ECCSFULL; | ||
1820 | } /* get_free_ccs */ | ||
1821 | /*===========================================================================*/ | ||
1822 | static void authenticate_timeout(u_long data) | ||
1823 | { | ||
1824 | ray_dev_t *local = (ray_dev_t *)data; | ||
1825 | del_timer(&local->timer); | ||
1826 | printk(KERN_INFO "ray_cs Authentication with access point failed" | ||
1827 | " - timeout\n"); | ||
1828 | join_net((u_long)local); | ||
1829 | } | ||
1830 | /*===========================================================================*/ | ||
1831 | static int asc_to_int(char a) | ||
1832 | { | ||
1833 | if (a < '0') return -1; | ||
1834 | if (a <= '9') return (a - '0'); | ||
1835 | if (a < 'A') return -1; | ||
1836 | if (a <= 'F') return (10 + a - 'A'); | ||
1837 | if (a < 'a') return -1; | ||
1838 | if (a <= 'f') return (10 + a - 'a'); | ||
1839 | return -1; | ||
1840 | } | ||
1841 | /*===========================================================================*/ | ||
1842 | static int parse_addr(char *in_str, UCHAR *out) | ||
1843 | { | ||
1844 | int len; | ||
1845 | int i,j,k; | ||
1846 | int status; | ||
1847 | |||
1848 | if (in_str == NULL) return 0; | ||
1849 | if ((len = strlen(in_str)) < 2) return 0; | ||
1850 | memset(out, 0, ADDRLEN); | ||
1851 | |||
1852 | status = 1; | ||
1853 | j = len - 1; | ||
1854 | if (j > 12) j = 12; | ||
1855 | i = 5; | ||
1856 | |||
1857 | while (j > 0) | ||
1858 | { | ||
1859 | if ((k = asc_to_int(in_str[j--])) != -1) out[i] = k; | ||
1860 | else return 0; | ||
1861 | |||
1862 | if (j == 0) break; | ||
1863 | if ((k = asc_to_int(in_str[j--])) != -1) out[i] += k << 4; | ||
1864 | else return 0; | ||
1865 | if (!i--) break; | ||
1866 | } | ||
1867 | return status; | ||
1868 | } | ||
1869 | /*===========================================================================*/ | ||
1870 | static struct net_device_stats *ray_get_stats(struct net_device *dev) | ||
1871 | { | ||
1872 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1873 | dev_link_t *link = local->finder; | ||
1874 | struct status __iomem *p = local->sram + STATUS_BASE; | ||
1875 | if (!(link->state & DEV_PRESENT)) { | ||
1876 | DEBUG(2,"ray_cs net_device_stats - device not present\n"); | ||
1877 | return &local->stats; | ||
1878 | } | ||
1879 | if (readb(&p->mrx_overflow_for_host)) | ||
1880 | { | ||
1881 | local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow)); | ||
1882 | writeb(0,&p->mrx_overflow); | ||
1883 | writeb(0,&p->mrx_overflow_for_host); | ||
1884 | } | ||
1885 | if (readb(&p->mrx_checksum_error_for_host)) | ||
1886 | { | ||
1887 | local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error)); | ||
1888 | writeb(0,&p->mrx_checksum_error); | ||
1889 | writeb(0,&p->mrx_checksum_error_for_host); | ||
1890 | } | ||
1891 | if (readb(&p->rx_hec_error_for_host)) | ||
1892 | { | ||
1893 | local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error)); | ||
1894 | writeb(0,&p->rx_hec_error); | ||
1895 | writeb(0,&p->rx_hec_error_for_host); | ||
1896 | } | ||
1897 | return &local->stats; | ||
1898 | } | ||
1899 | /*===========================================================================*/ | ||
1900 | static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len) | ||
1901 | { | ||
1902 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1903 | dev_link_t *link = local->finder; | ||
1904 | int ccsindex; | ||
1905 | int i; | ||
1906 | struct ccs __iomem *pccs; | ||
1907 | |||
1908 | if (!(link->state & DEV_PRESENT)) { | ||
1909 | DEBUG(2,"ray_update_parm - device not present\n"); | ||
1910 | return; | ||
1911 | } | ||
1912 | |||
1913 | if ((ccsindex = get_free_ccs(local)) < 0) | ||
1914 | { | ||
1915 | DEBUG(0,"ray_update_parm - No free ccs\n"); | ||
1916 | return; | ||
1917 | } | ||
1918 | pccs = ccs_base(local) + ccsindex; | ||
1919 | writeb(CCS_UPDATE_PARAMS, &pccs->cmd); | ||
1920 | writeb(objid, &pccs->var.update_param.object_id); | ||
1921 | writeb(1, &pccs->var.update_param.number_objects); | ||
1922 | writeb(0, &pccs->var.update_param.failure_cause); | ||
1923 | for (i=0; i<len; i++) { | ||
1924 | writeb(value[i], local->sram + HOST_TO_ECF_BASE); | ||
1925 | } | ||
1926 | /* Interrupt the firmware to process the command */ | ||
1927 | if (interrupt_ecf(local, ccsindex)) { | ||
1928 | DEBUG(0,"ray_cs associate failed - ECF not ready for intr\n"); | ||
1929 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
1930 | } | ||
1931 | } | ||
1932 | /*===========================================================================*/ | ||
1933 | static void ray_update_multi_list(struct net_device *dev, int all) | ||
1934 | { | ||
1935 | struct dev_mc_list *dmi, **dmip; | ||
1936 | int ccsindex; | ||
1937 | struct ccs __iomem *pccs; | ||
1938 | int i = 0; | ||
1939 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1940 | dev_link_t *link = local->finder; | ||
1941 | void __iomem *p = local->sram + HOST_TO_ECF_BASE; | ||
1942 | |||
1943 | if (!(link->state & DEV_PRESENT)) { | ||
1944 | DEBUG(2,"ray_update_multi_list - device not present\n"); | ||
1945 | return; | ||
1946 | } | ||
1947 | else | ||
1948 | DEBUG(2,"ray_update_multi_list(%p)\n",dev); | ||
1949 | if ((ccsindex = get_free_ccs(local)) < 0) | ||
1950 | { | ||
1951 | DEBUG(1,"ray_update_multi - No free ccs\n"); | ||
1952 | return; | ||
1953 | } | ||
1954 | pccs = ccs_base(local) + ccsindex; | ||
1955 | writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); | ||
1956 | |||
1957 | if (all) { | ||
1958 | writeb(0xff, &pccs->var); | ||
1959 | local->num_multi = 0xff; | ||
1960 | } | ||
1961 | else { | ||
1962 | /* Copy the kernel's list of MC addresses to card */ | ||
1963 | for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) { | ||
1964 | memcpy_toio(p, dmi->dmi_addr, ETH_ALEN); | ||
1965 | DEBUG(1,"ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",dmi->dmi_addr[0],dmi->dmi_addr[1],dmi->dmi_addr[2],dmi->dmi_addr[3],dmi->dmi_addr[4],dmi->dmi_addr[5]); | ||
1966 | p += ETH_ALEN; | ||
1967 | i++; | ||
1968 | } | ||
1969 | if (i > 256/ADDRLEN) i = 256/ADDRLEN; | ||
1970 | writeb((UCHAR)i, &pccs->var); | ||
1971 | DEBUG(1,"ray_cs update_multi %d addresses in list\n", i); | ||
1972 | /* Interrupt the firmware to process the command */ | ||
1973 | local->num_multi = i; | ||
1974 | } | ||
1975 | if (interrupt_ecf(local, ccsindex)) { | ||
1976 | DEBUG(1,"ray_cs update_multi failed - ECF not ready for intr\n"); | ||
1977 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
1978 | } | ||
1979 | } /* end ray_update_multi_list */ | ||
1980 | /*===========================================================================*/ | ||
1981 | static void set_multicast_list(struct net_device *dev) | ||
1982 | { | ||
1983 | ray_dev_t *local = (ray_dev_t *)dev->priv; | ||
1984 | UCHAR promisc; | ||
1985 | |||
1986 | DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev); | ||
1987 | |||
1988 | if (dev->flags & IFF_PROMISC) | ||
1989 | { | ||
1990 | if (local->sparm.b5.a_promiscuous_mode == 0) { | ||
1991 | DEBUG(1,"ray_cs set_multicast_list promisc on\n"); | ||
1992 | local->sparm.b5.a_promiscuous_mode = 1; | ||
1993 | promisc = 1; | ||
1994 | ray_update_parm(dev, OBJID_promiscuous_mode, \ | ||
1995 | &promisc, sizeof(promisc)); | ||
1996 | } | ||
1997 | } | ||
1998 | else { | ||
1999 | if (local->sparm.b5.a_promiscuous_mode == 1) { | ||
2000 | DEBUG(1,"ray_cs set_multicast_list promisc off\n"); | ||
2001 | local->sparm.b5.a_promiscuous_mode = 0; | ||
2002 | promisc = 0; | ||
2003 | ray_update_parm(dev, OBJID_promiscuous_mode, \ | ||
2004 | &promisc, sizeof(promisc)); | ||
2005 | } | ||
2006 | } | ||
2007 | |||
2008 | if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1); | ||
2009 | else | ||
2010 | { | ||
2011 | if (local->num_multi != dev->mc_count) ray_update_multi_list(dev, 0); | ||
2012 | } | ||
2013 | } /* end set_multicast_list */ | ||
2014 | /*============================================================================= | ||
2015 | * All routines below here are run at interrupt time. | ||
2016 | =============================================================================*/ | ||
2017 | static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) | ||
2018 | { | ||
2019 | struct net_device *dev = (struct net_device *)dev_id; | ||
2020 | dev_link_t *link; | ||
2021 | ray_dev_t *local; | ||
2022 | struct ccs __iomem *pccs; | ||
2023 | struct rcs __iomem *prcs; | ||
2024 | UCHAR rcsindex; | ||
2025 | UCHAR tmp; | ||
2026 | UCHAR cmd; | ||
2027 | UCHAR status; | ||
2028 | |||
2029 | if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ | ||
2030 | return IRQ_NONE; | ||
2031 | |||
2032 | DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); | ||
2033 | |||
2034 | local = (ray_dev_t *)dev->priv; | ||
2035 | link = (dev_link_t *)local->finder; | ||
2036 | if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { | ||
2037 | DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); | ||
2038 | return IRQ_NONE; | ||
2039 | } | ||
2040 | rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); | ||
2041 | |||
2042 | if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) | ||
2043 | { | ||
2044 | DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); | ||
2045 | clear_interrupt(local); | ||
2046 | return IRQ_HANDLED; | ||
2047 | } | ||
2048 | if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */ | ||
2049 | { | ||
2050 | pccs = ccs_base(local) + rcsindex; | ||
2051 | cmd = readb(&pccs->cmd); | ||
2052 | status = readb(&pccs->buffer_status); | ||
2053 | switch (cmd) | ||
2054 | { | ||
2055 | case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */ | ||
2056 | del_timer(&local->timer); | ||
2057 | if (status == CCS_COMMAND_COMPLETE) { | ||
2058 | DEBUG(1,"ray_cs interrupt download_startup_parameters OK\n"); | ||
2059 | } | ||
2060 | else { | ||
2061 | DEBUG(1,"ray_cs interrupt download_startup_parameters fail\n"); | ||
2062 | } | ||
2063 | break; | ||
2064 | case CCS_UPDATE_PARAMS: | ||
2065 | DEBUG(1,"ray_cs interrupt update params done\n"); | ||
2066 | if (status != CCS_COMMAND_COMPLETE) { | ||
2067 | tmp = readb(&pccs->var.update_param.failure_cause); | ||
2068 | DEBUG(0,"ray_cs interrupt update params failed - reason %d\n",tmp); | ||
2069 | } | ||
2070 | break; | ||
2071 | case CCS_REPORT_PARAMS: | ||
2072 | DEBUG(1,"ray_cs interrupt report params done\n"); | ||
2073 | break; | ||
2074 | case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */ | ||
2075 | DEBUG(1,"ray_cs interrupt CCS Update Multicast List done\n"); | ||
2076 | break; | ||
2077 | case CCS_UPDATE_POWER_SAVINGS_MODE: | ||
2078 | DEBUG(1,"ray_cs interrupt update power save mode done\n"); | ||
2079 | break; | ||
2080 | case CCS_START_NETWORK: | ||
2081 | case CCS_JOIN_NETWORK: | ||
2082 | if (status == CCS_COMMAND_COMPLETE) { | ||
2083 | if (readb(&pccs->var.start_network.net_initiated) == 1) { | ||
2084 | DEBUG(0,"ray_cs interrupt network \"%s\" started\n",\ | ||
2085 | local->sparm.b4.a_current_ess_id); | ||
2086 | } | ||
2087 | else { | ||
2088 | DEBUG(0,"ray_cs interrupt network \"%s\" joined\n",\ | ||
2089 | local->sparm.b4.a_current_ess_id); | ||
2090 | } | ||
2091 | memcpy_fromio(&local->bss_id,pccs->var.start_network.bssid,ADDRLEN); | ||
2092 | |||
2093 | if (local->fw_ver == 0x55) local->net_default_tx_rate = 3; | ||
2094 | else local->net_default_tx_rate = | ||
2095 | readb(&pccs->var.start_network.net_default_tx_rate); | ||
2096 | local->encryption = readb(&pccs->var.start_network.encryption); | ||
2097 | if (!sniffer && (local->net_type == INFRA) | ||
2098 | && !(local->sparm.b4.a_acting_as_ap_status)) { | ||
2099 | authenticate(local); | ||
2100 | } | ||
2101 | local->card_status = CARD_ACQ_COMPLETE; | ||
2102 | } | ||
2103 | else { | ||
2104 | local->card_status = CARD_ACQ_FAILED; | ||
2105 | |||
2106 | del_timer(&local->timer); | ||
2107 | local->timer.expires = jiffies + HZ*5; | ||
2108 | local->timer.data = (long)local; | ||
2109 | if (status == CCS_START_NETWORK) { | ||
2110 | DEBUG(0,"ray_cs interrupt network \"%s\" start failed\n",\ | ||
2111 | local->sparm.b4.a_current_ess_id); | ||
2112 | local->timer.function = &start_net; | ||
2113 | } | ||
2114 | else { | ||
2115 | DEBUG(0,"ray_cs interrupt network \"%s\" join failed\n",\ | ||
2116 | local->sparm.b4.a_current_ess_id); | ||
2117 | local->timer.function = &join_net; | ||
2118 | } | ||
2119 | add_timer(&local->timer); | ||
2120 | } | ||
2121 | break; | ||
2122 | case CCS_START_ASSOCIATION: | ||
2123 | if (status == CCS_COMMAND_COMPLETE) { | ||
2124 | local->card_status = CARD_ASSOC_COMPLETE; | ||
2125 | DEBUG(0,"ray_cs association successful\n"); | ||
2126 | } | ||
2127 | else | ||
2128 | { | ||
2129 | DEBUG(0,"ray_cs association failed,\n"); | ||
2130 | local->card_status = CARD_ASSOC_FAILED; | ||
2131 | join_net((u_long)local); | ||
2132 | } | ||
2133 | break; | ||
2134 | case CCS_TX_REQUEST: | ||
2135 | if (status == CCS_COMMAND_COMPLETE) { | ||
2136 | DEBUG(3,"ray_cs interrupt tx request complete\n"); | ||
2137 | } | ||
2138 | else { | ||
2139 | DEBUG(1,"ray_cs interrupt tx request failed\n"); | ||
2140 | } | ||
2141 | if (!sniffer) netif_start_queue(dev); | ||
2142 | netif_wake_queue(dev); | ||
2143 | break; | ||
2144 | case CCS_TEST_MEMORY: | ||
2145 | DEBUG(1,"ray_cs interrupt mem test done\n"); | ||
2146 | break; | ||
2147 | case CCS_SHUTDOWN: | ||
2148 | DEBUG(1,"ray_cs interrupt Unexpected CCS returned - Shutdown\n"); | ||
2149 | break; | ||
2150 | case CCS_DUMP_MEMORY: | ||
2151 | DEBUG(1,"ray_cs interrupt dump memory done\n"); | ||
2152 | break; | ||
2153 | case CCS_START_TIMER: | ||
2154 | DEBUG(2,"ray_cs interrupt DING - raylink timer expired\n"); | ||
2155 | break; | ||
2156 | default: | ||
2157 | DEBUG(1,"ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",\ | ||
2158 | rcsindex, cmd); | ||
2159 | } | ||
2160 | writeb(CCS_BUFFER_FREE, &pccs->buffer_status); | ||
2161 | } | ||
2162 | else /* It's an RCS */ | ||
2163 | { | ||
2164 | prcs = rcs_base(local) + rcsindex; | ||
2165 | |||
2166 | switch (readb(&prcs->interrupt_id)) | ||
2167 | { | ||
2168 | case PROCESS_RX_PACKET: | ||
2169 | ray_rx(dev, local, prcs); | ||
2170 | break; | ||
2171 | case REJOIN_NET_COMPLETE: | ||
2172 | DEBUG(1,"ray_cs interrupt rejoin net complete\n"); | ||
2173 | local->card_status = CARD_ACQ_COMPLETE; | ||
2174 | /* do we need to clear tx buffers CCS's? */ | ||
2175 | if (local->sparm.b4.a_network_type == ADHOC) { | ||
2176 | if (!sniffer) netif_start_queue(dev); | ||
2177 | } | ||
2178 | else { | ||
2179 | memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete.bssid, ADDRLEN); | ||
2180 | DEBUG(1,"ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",\ | ||
2181 | local->bss_id[0], local->bss_id[1], local->bss_id[2],\ | ||
2182 | local->bss_id[3], local->bss_id[4], local->bss_id[5]); | ||
2183 | if (!sniffer) authenticate(local); | ||
2184 | } | ||
2185 | break; | ||
2186 | case ROAMING_INITIATED: | ||
2187 | DEBUG(1,"ray_cs interrupt roaming initiated\n"); | ||
2188 | netif_stop_queue(dev); | ||
2189 | local->card_status = CARD_DOING_ACQ; | ||
2190 | break; | ||
2191 | case JAPAN_CALL_SIGN_RXD: | ||
2192 | DEBUG(1,"ray_cs interrupt japan call sign rx\n"); | ||
2193 | break; | ||
2194 | default: | ||
2195 | DEBUG(1,"ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",\ | ||
2196 | rcsindex, (unsigned int) readb(&prcs->interrupt_id)); | ||
2197 | break; | ||
2198 | } | ||
2199 | writeb(CCS_BUFFER_FREE, &prcs->buffer_status); | ||
2200 | } | ||
2201 | clear_interrupt(local); | ||
2202 | return IRQ_HANDLED; | ||
2203 | } /* ray_interrupt */ | ||
2204 | /*===========================================================================*/ | ||
2205 | static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs) | ||
2206 | { | ||
2207 | int rx_len; | ||
2208 | unsigned int pkt_addr; | ||
2209 | void __iomem *pmsg; | ||
2210 | DEBUG(4,"ray_rx process rx packet\n"); | ||
2211 | |||
2212 | /* Calculate address of packet within Rx buffer */ | ||
2213 | pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8) | ||
2214 | + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END; | ||
2215 | /* Length of first packet fragment */ | ||
2216 | rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8) | ||
2217 | + readb(&prcs->var.rx_packet.rx_data_length[1]); | ||
2218 | |||
2219 | local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev); | ||
2220 | pmsg = local->rmem + pkt_addr; | ||
2221 | switch(readb(pmsg)) | ||
2222 | { | ||
2223 | case DATA_TYPE: | ||
2224 | DEBUG(4,"ray_rx data type\n"); | ||
2225 | rx_data(dev, prcs, pkt_addr, rx_len); | ||
2226 | break; | ||
2227 | case AUTHENTIC_TYPE: | ||
2228 | DEBUG(4,"ray_rx authentic type\n"); | ||
2229 | if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); | ||
2230 | else rx_authenticate(local, prcs, pkt_addr, rx_len); | ||
2231 | break; | ||
2232 | case DEAUTHENTIC_TYPE: | ||
2233 | DEBUG(4,"ray_rx deauth type\n"); | ||
2234 | if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); | ||
2235 | else rx_deauthenticate(local, prcs, pkt_addr, rx_len); | ||
2236 | break; | ||
2237 | case NULL_MSG_TYPE: | ||
2238 | DEBUG(3,"ray_cs rx NULL msg\n"); | ||
2239 | break; | ||
2240 | case BEACON_TYPE: | ||
2241 | DEBUG(4,"ray_rx beacon type\n"); | ||
2242 | if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); | ||
2243 | |||
2244 | copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, | ||
2245 | rx_len < sizeof(struct beacon_rx) ? | ||
2246 | rx_len : sizeof(struct beacon_rx)); | ||
2247 | |||
2248 | local->beacon_rxed = 1; | ||
2249 | /* Get the statistics so the card counters never overflow */ | ||
2250 | ray_get_stats(dev); | ||
2251 | break; | ||
2252 | default: | ||
2253 | DEBUG(0,"ray_cs unknown pkt type %2x\n", (unsigned int) readb(pmsg)); | ||
2254 | break; | ||
2255 | } | ||
2256 | |||
2257 | } /* end ray_rx */ | ||
2258 | /*===========================================================================*/ | ||
2259 | static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, | ||
2260 | int rx_len) | ||
2261 | { | ||
2262 | struct sk_buff *skb = NULL; | ||
2263 | struct rcs __iomem *prcslink = prcs; | ||
2264 | ray_dev_t *local = dev->priv; | ||
2265 | UCHAR *rx_ptr; | ||
2266 | int total_len; | ||
2267 | int tmp; | ||
2268 | #ifdef WIRELESS_SPY | ||
2269 | int siglev = local->last_rsl; | ||
2270 | u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */ | ||
2271 | #endif | ||
2272 | |||
2273 | if (!sniffer) { | ||
2274 | if (translate) { | ||
2275 | /* TBD length needs fixing for translated header */ | ||
2276 | if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || | ||
2277 | rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) | ||
2278 | { | ||
2279 | DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len); | ||
2280 | return; | ||
2281 | } | ||
2282 | } | ||
2283 | else /* encapsulated ethernet */ { | ||
2284 | if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || | ||
2285 | rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) | ||
2286 | { | ||
2287 | DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len); | ||
2288 | return; | ||
2289 | } | ||
2290 | } | ||
2291 | } | ||
2292 | DEBUG(4,"ray_cs rx_data packet\n"); | ||
2293 | /* If fragmented packet, verify sizes of fragments add up */ | ||
2294 | if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { | ||
2295 | DEBUG(1,"ray_cs rx'ed fragment\n"); | ||
2296 | tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8) | ||
2297 | + readb(&prcs->var.rx_packet.totalpacketlength[1]); | ||
2298 | total_len = tmp; | ||
2299 | prcslink = prcs; | ||
2300 | do { | ||
2301 | tmp -= (readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) | ||
2302 | + readb(&prcslink->var.rx_packet.rx_data_length[1]); | ||
2303 | if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF | ||
2304 | || tmp < 0) break; | ||
2305 | prcslink = rcs_base(local) | ||
2306 | + readb(&prcslink->link_field); | ||
2307 | } while (1); | ||
2308 | |||
2309 | if (tmp < 0) | ||
2310 | { | ||
2311 | DEBUG(0,"ray_cs rx_data fragment lengths don't add up\n"); | ||
2312 | local->stats.rx_dropped++; | ||
2313 | release_frag_chain(local, prcs); | ||
2314 | return; | ||
2315 | } | ||
2316 | } | ||
2317 | else { /* Single unfragmented packet */ | ||
2318 | total_len = rx_len; | ||
2319 | } | ||
2320 | |||
2321 | skb = dev_alloc_skb( total_len+5 ); | ||
2322 | if (skb == NULL) | ||
2323 | { | ||
2324 | DEBUG(0,"ray_cs rx_data could not allocate skb\n"); | ||
2325 | local->stats.rx_dropped++; | ||
2326 | if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) | ||
2327 | release_frag_chain(local, prcs); | ||
2328 | return; | ||
2329 | } | ||
2330 | skb_reserve( skb, 2); /* Align IP on 16 byte (TBD check this)*/ | ||
2331 | skb->dev = dev; | ||
2332 | |||
2333 | DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len); | ||
2334 | |||
2335 | /************************/ | ||
2336 | /* Reserve enough room for the whole damn packet. */ | ||
2337 | rx_ptr = skb_put( skb, total_len); | ||
2338 | /* Copy the whole packet to sk_buff */ | ||
2339 | rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len); | ||
2340 | /* Get source address */ | ||
2341 | #ifdef WIRELESS_SPY | ||
2342 | memcpy(linksrcaddr, ((struct mac_header *)skb->data)->addr_2, ETH_ALEN); | ||
2343 | #endif | ||
2344 | /* Now, deal with encapsulation/translation/sniffer */ | ||
2345 | if (!sniffer) { | ||
2346 | if (!translate) { | ||
2347 | /* Encapsulated ethernet, so just lop off 802.11 MAC header */ | ||
2348 | /* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */ | ||
2349 | skb_pull( skb, RX_MAC_HEADER_LENGTH); | ||
2350 | } | ||
2351 | else { | ||
2352 | /* Do translation */ | ||
2353 | untranslate(local, skb, total_len); | ||
2354 | } | ||
2355 | } | ||
2356 | else | ||
2357 | { /* sniffer mode, so just pass whole packet */ }; | ||
2358 | |||
2359 | /************************/ | ||
2360 | /* Now pick up the rest of the fragments if any */ | ||
2361 | tmp = 17; | ||
2362 | if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { | ||
2363 | prcslink = prcs; | ||
2364 | DEBUG(1,"ray_cs rx_data in fragment loop\n"); | ||
2365 | do { | ||
2366 | prcslink = rcs_base(local) | ||
2367 | + readb(&prcslink->var.rx_packet.next_frag_rcs_index); | ||
2368 | rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) | ||
2369 | + readb(&prcslink->var.rx_packet.rx_data_length[1])) | ||
2370 | & RX_BUFF_END; | ||
2371 | pkt_addr = (( readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << 8) | ||
2372 | + readb(&prcslink->var.rx_packet.rx_data_ptr[1])) | ||
2373 | & RX_BUFF_END; | ||
2374 | |||
2375 | rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len); | ||
2376 | |||
2377 | } while (tmp-- && | ||
2378 | readb(&prcslink->var.rx_packet.next_frag_rcs_index) != 0xFF); | ||
2379 | release_frag_chain(local, prcs); | ||
2380 | } | ||
2381 | |||
2382 | skb->protocol = eth_type_trans(skb,dev); | ||
2383 | netif_rx(skb); | ||
2384 | dev->last_rx = jiffies; | ||
2385 | local->stats.rx_packets++; | ||
2386 | local->stats.rx_bytes += total_len; | ||
2387 | |||
2388 | /* Gather signal strength per address */ | ||
2389 | #ifdef WIRELESS_SPY | ||
2390 | /* For the Access Point or the node having started the ad-hoc net | ||
2391 | * note : ad-hoc work only in some specific configurations, but we | ||
2392 | * kludge in ray_get_wireless_stats... */ | ||
2393 | if(!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) | ||
2394 | { | ||
2395 | /* Update statistics */ | ||
2396 | /*local->wstats.qual.qual = none ? */ | ||
2397 | local->wstats.qual.level = siglev; | ||
2398 | /*local->wstats.qual.noise = none ? */ | ||
2399 | local->wstats.qual.updated = 0x2; | ||
2400 | } | ||
2401 | /* Now, for the addresses in the spy list */ | ||
2402 | { | ||
2403 | int i; | ||
2404 | /* Look all addresses */ | ||
2405 | for(i = 0; i < local->spy_number; i++) | ||
2406 | /* If match */ | ||
2407 | if(!memcmp(linksrcaddr, local->spy_address[i], ETH_ALEN)) | ||
2408 | { | ||
2409 | /* Update statistics */ | ||
2410 | /*local->spy_stat[i].qual = none ? */ | ||
2411 | local->spy_stat[i].level = siglev; | ||
2412 | /*local->spy_stat[i].noise = none ? */ | ||
2413 | local->spy_stat[i].updated = 0x2; | ||
2414 | } | ||
2415 | } | ||
2416 | #endif /* WIRELESS_SPY */ | ||
2417 | } /* end rx_data */ | ||
2418 | /*===========================================================================*/ | ||
2419 | static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) | ||
2420 | { | ||
2421 | snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH); | ||
2422 | struct mac_header *pmac = (struct mac_header *)skb->data; | ||
2423 | unsigned short type = *(unsigned short *)psnap->ethertype; | ||
2424 | unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff; | ||
2425 | unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff; | ||
2426 | int delta; | ||
2427 | struct ethhdr *peth; | ||
2428 | UCHAR srcaddr[ADDRLEN]; | ||
2429 | UCHAR destaddr[ADDRLEN]; | ||
2430 | |||
2431 | if (pmac->frame_ctl_2 & FC2_FROM_DS) { | ||
2432 | if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */ | ||
2433 | memcpy(destaddr, pmac->addr_3, ADDRLEN); | ||
2434 | memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN); | ||
2435 | } else { /* AP to terminal */ | ||
2436 | memcpy(destaddr, pmac->addr_1, ADDRLEN); | ||
2437 | memcpy(srcaddr, pmac->addr_3, ADDRLEN); | ||
2438 | } | ||
2439 | } else { /* Terminal to AP */ | ||
2440 | if (pmac->frame_ctl_2 & FC2_TO_DS) { | ||
2441 | memcpy(destaddr, pmac->addr_3, ADDRLEN); | ||
2442 | memcpy(srcaddr, pmac->addr_2, ADDRLEN); | ||
2443 | } else { /* Adhoc */ | ||
2444 | memcpy(destaddr, pmac->addr_1, ADDRLEN); | ||
2445 | memcpy(srcaddr, pmac->addr_2, ADDRLEN); | ||
2446 | } | ||
2447 | } | ||
2448 | |||
2449 | #ifdef PCMCIA_DEBUG | ||
2450 | if (pc_debug > 3) { | ||
2451 | int i; | ||
2452 | printk(KERN_DEBUG "skb->data before untranslate"); | ||
2453 | for (i=0;i<64;i++) | ||
2454 | printk("%02x ",skb->data[i]); | ||
2455 | printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n", | ||
2456 | type,xsap,org); | ||
2457 | printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data); | ||
2458 | } | ||
2459 | #endif | ||
2460 | |||
2461 | if ( xsap != SNAP_ID) { | ||
2462 | /* not a snap type so leave it alone */ | ||
2463 | DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff); | ||
2464 | |||
2465 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | ||
2466 | peth = (struct ethhdr *)(skb->data + delta); | ||
2467 | peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); | ||
2468 | } | ||
2469 | else { /* Its a SNAP */ | ||
2470 | if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC */ | ||
2471 | DEBUG(3,"ray_cs untranslate Bridge encap\n"); | ||
2472 | delta = RX_MAC_HEADER_LENGTH | ||
2473 | + sizeof(struct snaphdr_t) - ETH_HLEN; | ||
2474 | peth = (struct ethhdr *)(skb->data + delta); | ||
2475 | peth->h_proto = type; | ||
2476 | } | ||
2477 | else { | ||
2478 | if (org == RFC1042_ENCAP) { | ||
2479 | switch (type) { | ||
2480 | case RAY_IPX_TYPE: | ||
2481 | case APPLEARP_TYPE: | ||
2482 | DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n"); | ||
2483 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | ||
2484 | peth = (struct ethhdr *)(skb->data + delta); | ||
2485 | peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); | ||
2486 | break; | ||
2487 | default: | ||
2488 | DEBUG(3,"ray_cs untranslate RFC default\n"); | ||
2489 | delta = RX_MAC_HEADER_LENGTH + | ||
2490 | sizeof(struct snaphdr_t) - ETH_HLEN; | ||
2491 | peth = (struct ethhdr *)(skb->data + delta); | ||
2492 | peth->h_proto = type; | ||
2493 | break; | ||
2494 | } | ||
2495 | } | ||
2496 | else { | ||
2497 | printk("ray_cs untranslate very confused by packet\n"); | ||
2498 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | ||
2499 | peth = (struct ethhdr *)(skb->data + delta); | ||
2500 | peth->h_proto = type; | ||
2501 | } | ||
2502 | } | ||
2503 | } | ||
2504 | /* TBD reserve skb_reserve(skb, delta); */ | ||
2505 | skb_pull(skb, delta); | ||
2506 | DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data); | ||
2507 | memcpy(peth->h_dest, destaddr, ADDRLEN); | ||
2508 | memcpy(peth->h_source, srcaddr, ADDRLEN); | ||
2509 | #ifdef PCMCIA_DEBUG | ||
2510 | if (pc_debug > 3) { | ||
2511 | int i; | ||
2512 | printk(KERN_DEBUG "skb->data after untranslate:"); | ||
2513 | for (i=0;i<64;i++) | ||
2514 | printk("%02x ",skb->data[i]); | ||
2515 | printk("\n"); | ||
2516 | } | ||
2517 | #endif | ||
2518 | } /* end untranslate */ | ||
2519 | /*===========================================================================*/ | ||
2520 | /* Copy data from circular receive buffer to PC memory. | ||
2521 | * dest = destination address in PC memory | ||
2522 | * pkt_addr = source address in receive buffer | ||
2523 | * len = length of packet to copy | ||
2524 | */ | ||
2525 | static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length) | ||
2526 | { | ||
2527 | int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1); | ||
2528 | if (wrap_bytes <= 0) | ||
2529 | { | ||
2530 | memcpy_fromio(dest,local->rmem + pkt_addr,length); | ||
2531 | } | ||
2532 | else /* Packet wrapped in circular buffer */ | ||
2533 | { | ||
2534 | memcpy_fromio(dest,local->rmem+pkt_addr,length - wrap_bytes); | ||
2535 | memcpy_fromio(dest + length - wrap_bytes, local->rmem, wrap_bytes); | ||
2536 | } | ||
2537 | return length; | ||
2538 | } | ||
2539 | /*===========================================================================*/ | ||
2540 | static void release_frag_chain(ray_dev_t *local, struct rcs __iomem * prcs) | ||
2541 | { | ||
2542 | struct rcs __iomem *prcslink = prcs; | ||
2543 | int tmp = 17; | ||
2544 | unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); | ||
2545 | |||
2546 | while (tmp--) { | ||
2547 | writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); | ||
2548 | if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { | ||
2549 | DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); | ||
2550 | break; | ||
2551 | } | ||
2552 | prcslink = rcs_base(local) + rcsindex; | ||
2553 | rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); | ||
2554 | } | ||
2555 | writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); | ||
2556 | } | ||
2557 | /*===========================================================================*/ | ||
2558 | static void authenticate(ray_dev_t *local) | ||
2559 | { | ||
2560 | dev_link_t *link = local->finder; | ||
2561 | DEBUG(0,"ray_cs Starting authentication.\n"); | ||
2562 | if (!(link->state & DEV_PRESENT)) { | ||
2563 | DEBUG(2,"ray_cs authenticate - device not present\n"); | ||
2564 | return; | ||
2565 | } | ||
2566 | |||
2567 | del_timer(&local->timer); | ||
2568 | if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) { | ||
2569 | local->timer.function = &join_net; | ||
2570 | } | ||
2571 | else { | ||
2572 | local->timer.function = &authenticate_timeout; | ||
2573 | } | ||
2574 | local->timer.expires = jiffies + HZ*2; | ||
2575 | local->timer.data = (long)local; | ||
2576 | add_timer(&local->timer); | ||
2577 | local->authentication_state = AWAITING_RESPONSE; | ||
2578 | } /* end authenticate */ | ||
2579 | /*===========================================================================*/ | ||
2580 | static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
2581 | unsigned int pkt_addr, int rx_len) | ||
2582 | { | ||
2583 | UCHAR buff[256]; | ||
2584 | struct rx_msg *msg = (struct rx_msg *)buff; | ||
2585 | |||
2586 | del_timer(&local->timer); | ||
2587 | |||
2588 | copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); | ||
2589 | /* if we are trying to get authenticated */ | ||
2590 | if (local->sparm.b4.a_network_type == ADHOC) { | ||
2591 | DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]); | ||
2592 | if (msg->var[2] == 1) { | ||
2593 | DEBUG(0,"ray_cs Sending authentication response.\n"); | ||
2594 | if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { | ||
2595 | local->authentication_state = NEED_TO_AUTH; | ||
2596 | memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN); | ||
2597 | } | ||
2598 | } | ||
2599 | } | ||
2600 | else /* Infrastructure network */ | ||
2601 | { | ||
2602 | if (local->authentication_state == AWAITING_RESPONSE) { | ||
2603 | /* Verify authentication sequence #2 and success */ | ||
2604 | if (msg->var[2] == 2) { | ||
2605 | if ((msg->var[3] | msg->var[4]) == 0) { | ||
2606 | DEBUG(1,"Authentication successful\n"); | ||
2607 | local->card_status = CARD_AUTH_COMPLETE; | ||
2608 | associate(local); | ||
2609 | local->authentication_state = AUTHENTICATED; | ||
2610 | } | ||
2611 | else { | ||
2612 | DEBUG(0,"Authentication refused\n"); | ||
2613 | local->card_status = CARD_AUTH_REFUSED; | ||
2614 | join_net((u_long)local); | ||
2615 | local->authentication_state = UNAUTHENTICATED; | ||
2616 | } | ||
2617 | } | ||
2618 | } | ||
2619 | } | ||
2620 | |||
2621 | } /* end rx_authenticate */ | ||
2622 | /*===========================================================================*/ | ||
2623 | static void associate(ray_dev_t *local) | ||
2624 | { | ||
2625 | struct ccs __iomem *pccs; | ||
2626 | dev_link_t *link = local->finder; | ||
2627 | struct net_device *dev = link->priv; | ||
2628 | int ccsindex; | ||
2629 | if (!(link->state & DEV_PRESENT)) { | ||
2630 | DEBUG(2,"ray_cs associate - device not present\n"); | ||
2631 | return; | ||
2632 | } | ||
2633 | /* If no tx buffers available, return*/ | ||
2634 | if ((ccsindex = get_free_ccs(local)) < 0) | ||
2635 | { | ||
2636 | /* TBD should never be here but... what if we are? */ | ||
2637 | DEBUG(1,"ray_cs associate - No free ccs\n"); | ||
2638 | return; | ||
2639 | } | ||
2640 | DEBUG(1,"ray_cs Starting association with access point\n"); | ||
2641 | pccs = ccs_base(local) + ccsindex; | ||
2642 | /* fill in the CCS */ | ||
2643 | writeb(CCS_START_ASSOCIATION, &pccs->cmd); | ||
2644 | /* Interrupt the firmware to process the command */ | ||
2645 | if (interrupt_ecf(local, ccsindex)) { | ||
2646 | DEBUG(1,"ray_cs associate failed - ECF not ready for intr\n"); | ||
2647 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
2648 | |||
2649 | del_timer(&local->timer); | ||
2650 | local->timer.expires = jiffies + HZ*2; | ||
2651 | local->timer.data = (long)local; | ||
2652 | local->timer.function = &join_net; | ||
2653 | add_timer(&local->timer); | ||
2654 | local->card_status = CARD_ASSOC_FAILED; | ||
2655 | return; | ||
2656 | } | ||
2657 | if (!sniffer) netif_start_queue(dev); | ||
2658 | |||
2659 | } /* end associate */ | ||
2660 | /*===========================================================================*/ | ||
2661 | static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, | ||
2662 | unsigned int pkt_addr, int rx_len) | ||
2663 | { | ||
2664 | /* UCHAR buff[256]; | ||
2665 | struct rx_msg *msg = (struct rx_msg *)buff; | ||
2666 | */ | ||
2667 | DEBUG(0,"Deauthentication frame received\n"); | ||
2668 | local->authentication_state = UNAUTHENTICATED; | ||
2669 | /* Need to reauthenticate or rejoin depending on reason code */ | ||
2670 | /* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); | ||
2671 | */ | ||
2672 | } | ||
2673 | /*===========================================================================*/ | ||
2674 | static void clear_interrupt(ray_dev_t *local) | ||
2675 | { | ||
2676 | writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET); | ||
2677 | } | ||
2678 | /*===========================================================================*/ | ||
2679 | #ifdef CONFIG_PROC_FS | ||
2680 | #define MAXDATA (PAGE_SIZE - 80) | ||
2681 | |||
2682 | static char *card_status[] = { | ||
2683 | "Card inserted - uninitialized", /* 0 */ | ||
2684 | "Card not downloaded", /* 1 */ | ||
2685 | "Waiting for download parameters", /* 2 */ | ||
2686 | "Card doing acquisition", /* 3 */ | ||
2687 | "Acquisition complete", /* 4 */ | ||
2688 | "Authentication complete", /* 5 */ | ||
2689 | "Association complete", /* 6 */ | ||
2690 | "???", "???", "???", "???", /* 7 8 9 10 undefined */ | ||
2691 | "Card init error", /* 11 */ | ||
2692 | "Download parameters error", /* 12 */ | ||
2693 | "???", /* 13 */ | ||
2694 | "Acquisition failed", /* 14 */ | ||
2695 | "Authentication refused", /* 15 */ | ||
2696 | "Association failed" /* 16 */ | ||
2697 | }; | ||
2698 | |||
2699 | static char *nettype[] = {"Adhoc", "Infra "}; | ||
2700 | static char *framing[] = {"Encapsulation", "Translation"} | ||
2701 | ; | ||
2702 | /*===========================================================================*/ | ||
2703 | static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) | ||
2704 | { | ||
2705 | /* Print current values which are not available via other means | ||
2706 | * eg ifconfig | ||
2707 | */ | ||
2708 | int i; | ||
2709 | dev_link_t *link; | ||
2710 | struct net_device *dev; | ||
2711 | ray_dev_t *local; | ||
2712 | UCHAR *p; | ||
2713 | struct freq_hop_element *pfh; | ||
2714 | UCHAR c[33]; | ||
2715 | |||
2716 | link = dev_list; | ||
2717 | if (!link) | ||
2718 | return 0; | ||
2719 | dev = (struct net_device *)link->priv; | ||
2720 | if (!dev) | ||
2721 | return 0; | ||
2722 | local = (ray_dev_t *)dev->priv; | ||
2723 | if (!local) | ||
2724 | return 0; | ||
2725 | |||
2726 | len = 0; | ||
2727 | |||
2728 | len += sprintf(buf + len, "Raylink Wireless LAN driver status\n"); | ||
2729 | len += sprintf(buf + len, "%s\n", rcsid); | ||
2730 | /* build 4 does not report version, and field is 0x55 after memtest */ | ||
2731 | len += sprintf(buf + len, "Firmware version = "); | ||
2732 | if (local->fw_ver == 0x55) | ||
2733 | len += sprintf(buf + len, "4 - Use dump_cis for more details\n"); | ||
2734 | else | ||
2735 | len += sprintf(buf + len, "%2d.%02d.%02d\n", | ||
2736 | local->fw_ver, local->fw_bld, local->fw_var); | ||
2737 | |||
2738 | for (i=0; i<32; i++) c[i] = local->sparm.b5.a_current_ess_id[i]; | ||
2739 | c[32] = 0; | ||
2740 | len += sprintf(buf + len, "%s network ESSID = \"%s\"\n", | ||
2741 | nettype[local->sparm.b5.a_network_type], c); | ||
2742 | |||
2743 | p = local->bss_id; | ||
2744 | len += sprintf(buf + len, | ||
2745 | "BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
2746 | p[0],p[1],p[2],p[3],p[4],p[5]); | ||
2747 | |||
2748 | len += sprintf(buf + len, "Country code = %d\n", | ||
2749 | local->sparm.b5.a_curr_country_code); | ||
2750 | |||
2751 | i = local->card_status; | ||
2752 | if (i < 0) i = 10; | ||
2753 | if (i > 16) i = 10; | ||
2754 | len += sprintf(buf + len, "Card status = %s\n", card_status[i]); | ||
2755 | |||
2756 | len += sprintf(buf + len, "Framing mode = %s\n",framing[translate]); | ||
2757 | |||
2758 | len += sprintf(buf + len, "Last pkt signal lvl = %d\n", local->last_rsl); | ||
2759 | |||
2760 | if (local->beacon_rxed) { | ||
2761 | /* Pull some fields out of last beacon received */ | ||
2762 | len += sprintf(buf + len, "Beacon Interval = %d Kus\n", | ||
2763 | local->last_bcn.beacon_intvl[0] | ||
2764 | + 256 * local->last_bcn.beacon_intvl[1]); | ||
2765 | |||
2766 | p = local->last_bcn.elements; | ||
2767 | if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2; | ||
2768 | else { | ||
2769 | len += sprintf(buf + len, "Parse beacon failed at essid element id = %d\n",p[0]); | ||
2770 | return len; | ||
2771 | } | ||
2772 | |||
2773 | if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) { | ||
2774 | len += sprintf(buf + len, "Supported rate codes = "); | ||
2775 | for (i=2; i<p[1] + 2; i++) | ||
2776 | len += sprintf(buf + len, "0x%02x ", p[i]); | ||
2777 | len += sprintf(buf + len, "\n"); | ||
2778 | p += p[1] + 2; | ||
2779 | } | ||
2780 | else { | ||
2781 | len += sprintf(buf + len, "Parse beacon failed at rates element\n"); | ||
2782 | return len; | ||
2783 | } | ||
2784 | |||
2785 | if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) { | ||
2786 | pfh = (struct freq_hop_element *)p; | ||
2787 | len += sprintf(buf + len, "Hop dwell = %d Kus\n", | ||
2788 | pfh->dwell_time[0] + 256 * pfh->dwell_time[1]); | ||
2789 | len += sprintf(buf + len, "Hop set = %d \n", pfh->hop_set); | ||
2790 | len += sprintf(buf + len, "Hop pattern = %d \n", pfh->hop_pattern); | ||
2791 | len += sprintf(buf + len, "Hop index = %d \n", pfh->hop_index); | ||
2792 | p += p[1] + 2; | ||
2793 | } | ||
2794 | else { | ||
2795 | len += sprintf(buf + len, "Parse beacon failed at FH param element\n"); | ||
2796 | return len; | ||
2797 | } | ||
2798 | } else { | ||
2799 | len += sprintf(buf + len, "No beacons received\n"); | ||
2800 | } | ||
2801 | return len; | ||
2802 | } | ||
2803 | |||
2804 | #endif | ||
2805 | /*===========================================================================*/ | ||
2806 | static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) | ||
2807 | { | ||
2808 | int addr; | ||
2809 | struct ccs __iomem *pccs; | ||
2810 | struct tx_msg __iomem *ptx; | ||
2811 | int ccsindex; | ||
2812 | |||
2813 | /* If no tx buffers available, return */ | ||
2814 | if ((ccsindex = get_free_tx_ccs(local)) < 0) | ||
2815 | { | ||
2816 | DEBUG(1,"ray_cs send authenticate - No free tx ccs\n"); | ||
2817 | return -1; | ||
2818 | } | ||
2819 | |||
2820 | pccs = ccs_base(local) + ccsindex; | ||
2821 | |||
2822 | /* Address in card space */ | ||
2823 | addr = TX_BUF_BASE + (ccsindex << 11); | ||
2824 | /* fill in the CCS */ | ||
2825 | writeb(CCS_TX_REQUEST, &pccs->cmd); | ||
2826 | writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr); | ||
2827 | writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1); | ||
2828 | writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length); | ||
2829 | writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1); | ||
2830 | writeb(0, &pccs->var.tx_request.pow_sav_mode); | ||
2831 | |||
2832 | ptx = local->sram + addr; | ||
2833 | /* fill in the mac header */ | ||
2834 | writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); | ||
2835 | writeb(0, &ptx->mac.frame_ctl_2); | ||
2836 | |||
2837 | memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN); | ||
2838 | memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN); | ||
2839 | memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); | ||
2840 | |||
2841 | /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */ | ||
2842 | memset_io(ptx->var, 0, 6); | ||
2843 | writeb(auth_type & 0xff, ptx->var + 2); | ||
2844 | |||
2845 | /* Interrupt the firmware to process the command */ | ||
2846 | if (interrupt_ecf(local, ccsindex)) { | ||
2847 | DEBUG(1,"ray_cs send authentication request failed - ECF not ready for intr\n"); | ||
2848 | writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); | ||
2849 | return -1; | ||
2850 | } | ||
2851 | return 0; | ||
2852 | } /* End build_auth_frame */ | ||
2853 | |||
2854 | /*===========================================================================*/ | ||
2855 | #ifdef CONFIG_PROC_FS | ||
2856 | static void raycs_write(const char *name, write_proc_t *w, void *data) | ||
2857 | { | ||
2858 | struct proc_dir_entry * entry = create_proc_entry(name, S_IFREG | S_IWUSR, NULL); | ||
2859 | if (entry) { | ||
2860 | entry->write_proc = w; | ||
2861 | entry->data = data; | ||
2862 | } | ||
2863 | } | ||
2864 | |||
2865 | static int write_essid(struct file *file, const char __user *buffer, unsigned long count, void *data) | ||
2866 | { | ||
2867 | static char proc_essid[33]; | ||
2868 | int len = count; | ||
2869 | |||
2870 | if (len > 32) | ||
2871 | len = 32; | ||
2872 | memset(proc_essid, 0, 33); | ||
2873 | if (copy_from_user(proc_essid, buffer, len)) | ||
2874 | return -EFAULT; | ||
2875 | essid = proc_essid; | ||
2876 | return count; | ||
2877 | } | ||
2878 | |||
2879 | static int write_int(struct file *file, const char __user *buffer, unsigned long count, void *data) | ||
2880 | { | ||
2881 | static char proc_number[10]; | ||
2882 | char *p; | ||
2883 | int nr, len; | ||
2884 | |||
2885 | if (!count) | ||
2886 | return 0; | ||
2887 | |||
2888 | if (count > 9) | ||
2889 | return -EINVAL; | ||
2890 | if (copy_from_user(proc_number, buffer, count)) | ||
2891 | return -EFAULT; | ||
2892 | p = proc_number; | ||
2893 | nr = 0; | ||
2894 | len = count; | ||
2895 | do { | ||
2896 | unsigned int c = *p - '0'; | ||
2897 | if (c > 9) | ||
2898 | return -EINVAL; | ||
2899 | nr = nr*10 + c; | ||
2900 | p++; | ||
2901 | } while (--len); | ||
2902 | *(int *)data = nr; | ||
2903 | return count; | ||
2904 | } | ||
2905 | #endif | ||
2906 | |||
2907 | static struct pcmcia_driver ray_driver = { | ||
2908 | .owner = THIS_MODULE, | ||
2909 | .drv = { | ||
2910 | .name = "ray_cs", | ||
2911 | }, | ||
2912 | .attach = ray_attach, | ||
2913 | .detach = ray_detach, | ||
2914 | }; | ||
2915 | |||
2916 | static int __init init_ray_cs(void) | ||
2917 | { | ||
2918 | int rc; | ||
2919 | |||
2920 | DEBUG(1, "%s\n", rcsid); | ||
2921 | rc = pcmcia_register_driver(&ray_driver); | ||
2922 | DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc); | ||
2923 | |||
2924 | #ifdef CONFIG_PROC_FS | ||
2925 | proc_mkdir("driver/ray_cs", NULL); | ||
2926 | |||
2927 | create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_read); | ||
2928 | raycs_write("driver/ray_cs/essid", write_essid, NULL); | ||
2929 | raycs_write("driver/ray_cs/net_type", write_int, &net_type); | ||
2930 | raycs_write("driver/ray_cs/translate", write_int, &translate); | ||
2931 | #endif | ||
2932 | if (translate != 0) translate = 1; | ||
2933 | return 0; | ||
2934 | } /* init_ray_cs */ | ||
2935 | |||
2936 | /*===========================================================================*/ | ||
2937 | |||
2938 | static void __exit exit_ray_cs(void) | ||
2939 | { | ||
2940 | DEBUG(0, "ray_cs: cleanup_module\n"); | ||
2941 | |||
2942 | #ifdef CONFIG_PROC_FS | ||
2943 | remove_proc_entry("driver/ray_cs/ray_cs", NULL); | ||
2944 | remove_proc_entry("driver/ray_cs/essid", NULL); | ||
2945 | remove_proc_entry("driver/ray_cs/net_type", NULL); | ||
2946 | remove_proc_entry("driver/ray_cs/translate", NULL); | ||
2947 | remove_proc_entry("driver/ray_cs", NULL); | ||
2948 | #endif | ||
2949 | |||
2950 | pcmcia_unregister_driver(&ray_driver); | ||
2951 | BUG_ON(dev_list != NULL); | ||
2952 | } /* exit_ray_cs */ | ||
2953 | |||
2954 | module_init(init_ray_cs); | ||
2955 | module_exit(exit_ray_cs); | ||
2956 | |||
2957 | /*===========================================================================*/ | ||