Import 2.3.36
[davej-history.git] / drivers / net / aironet4500_core.c
blob1b82d471532e524cd7f5bc0c94668d2c0e4cfe34
1 /*
2 * Aironet 4500/4800 driver core
4 * Elmer Joandi, Januar 1999
5 * Copyright: GPL
6 *
8 * Revision 0.1 ,started 30.12.1998
12 /* CHANGELOG:
13 march 99, stable version 2.0
14 august 99, stable version 2.2
15 november 99, integration with 2.3
16 17.12.99: finally, got SMP near-correct.
17 timing issues remain- on SMP box its 15% slower on tcp
20 #include <linux/module.h>
21 #include <linux/config.h>
22 #include <linux/kernel.h>
23 #include <linux/netdevice.h>
24 #include <linux/etherdevice.h>
25 #include <linux/skbuff.h>
26 #include <linux/if_arp.h>
27 #include <linux/ioport.h>
29 #include <asm/io.h>
30 #include <asm/bitops.h>
31 #include <asm/system.h>
32 #include <asm/byteorder.h>
33 #include <asm/irq.h>
34 #include <linux/time.h>
35 #include <linux/sched.h>
36 #include <linux/delay.h>
37 #include "aironet4500.h"
40 int bap_sleep = 10 ;
41 int bap_sleep_after_setup = 1;
42 int sleep_before_command = 1;
43 int bap_sleep_before_write= 1;
44 int sleep_in_command = 1;
45 int both_bap_lock =0; /* activated at awc_init in this */
46 int bap_setup_spinlock =0; /* file if numcpu >1 */
48 EXPORT_SYMBOL(bap_sleep);
49 EXPORT_SYMBOL(bap_sleep_after_setup);
50 EXPORT_SYMBOL(sleep_before_command);
51 EXPORT_SYMBOL(bap_sleep_before_write);
52 EXPORT_SYMBOL(sleep_in_command);
53 EXPORT_SYMBOL(both_bap_lock);
54 EXPORT_SYMBOL(bap_setup_spinlock);
56 struct awc_strings awc_status_error_codes[]=awc_reply_error_strings;
57 struct awc_strings awc_command_names[]=awc_command_name_strings;
58 struct awc_strings awc_link_status_names[]=awc_link_status_strings;
59 struct awc_strings awc_rid_names[]=aironet4500_RID_Select_strings;
60 struct awc_strings awc_link_failure_reason_names[]=IEEE_802_11_LINK_STATUS_FAILURE_REASON_STRINGS;
62 const char * awc_print_string( struct awc_strings* strings, int code){
64 struct awc_strings * str = strings;
65 int i = 0;
66 while (str[i].string != NULL){
67 if (str[i].par == (code & str[i].mask )){
68 return str[i].string;
70 i++;
72 return "UNKNOWN";
75 int awc_dump_registers(struct NET_DEVICE * dev){
77 #ifdef AWC_DEBUG
78 int i;
79 #endif
80 int status= inw(dev->base_addr +4*2);
81 int r1= inw(dev->base_addr +5*2);
82 int r2= inw(dev->base_addr +6*2);
83 int r3= inw(dev->base_addr +7*2);
85 printk(KERN_ERR "Command %s , result: %s, at memblk %x(RID %s) , offset %x \n",
86 awc_print_string(awc_command_names,status),
87 awc_print_string(awc_status_error_codes,r1),
88 r2, awc_print_string(awc_rid_names,r2),
89 r3);
91 #ifdef AWC_DEBUG
92 printk(KERN_ERR "%s aironet register dump ",dev->name );
95 for (i=0; i < 32; i++){
96 printk("%4x ", inw(dev->base_addr + i*2 ) );
97 if ( (i+1)%8 == 0){
98 printk("\n");
99 printk(KERN_ERR "%02x",(i+1)*2);
102 printk(KERN_ERR " \n");
103 #endif
104 return 0;
107 /****************************** COMMAND ******************/
110 inline
111 int awc_command_busy_clear_wait(struct NET_DEVICE * dev){
112 // long long jiff = jiffies;
113 u16 active_interrupts;
114 int cnt= 0;
116 AWC_ENTRY_EXIT_DEBUG(" entry awc_command_busy_clear_wait ");
118 while (awc_command_busy(dev->base_addr)){
119 if (cnt > 1000 ){
120 printk(KERN_ERR "awc command busy too long, clearing\n");
121 awc_dump_registers(dev);
122 awc_event_ack_ClrStckCmdBsy(dev->base_addr);
123 break;
125 if (((struct awc_private*) dev->priv)->ejected)
126 return -1;
127 cnt++;
128 udelay(10);
131 cnt = 0;
132 while (awc_command_busy(dev->base_addr)){
133 //if (jiffies - jiff > (HZ/3)){
134 if (cnt > 30000 ){
135 printk(KERN_CRIT "awc command busy WAY too long, clearing\n");
136 awc_dump_registers(dev);
137 awc_event_ack_ClrStckCmdBsy(dev->base_addr);
138 active_interrupts = awc_event_status(dev->base_addr);
139 awc_event_ack(dev->base_addr, active_interrupts);
141 AWC_ENTRY_EXIT_DEBUG("BAD exit\n ");
142 return -1 ;
145 if (((struct awc_private*) dev->priv)->ejected)
146 return -1;
147 cnt++;
148 udelay(10);
152 AWC_ENTRY_EXIT_DEBUG(" exit\n ");
154 return 0;
161 inline unsigned short
162 awc_issue_command_and_block(struct awc_command * cmd){
164 int ticks;
165 long long jiff;
166 u16 enabled_interrupts;
167 int cnt = 0;
168 // unsigned long flags;
170 jiff = jiffies;
173 AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command_and_block ");
175 AWC_LOCK_COMMAND_ISSUING(cmd->priv);
177 if (awc_command_busy_clear_wait(cmd->dev)) goto final;
179 if (cmd->priv->sleeping_bap) udelay(sleep_before_command);
181 awc4500wout(cmd->port,cmd->command,cmd->par0,cmd->par1,cmd->par2);
182 // awc_dump_registers(cmd->dev);
185 if (cmd->priv->sleeping_bap) udelay(sleep_in_command);
187 enabled_interrupts = awc_ints_enabled(cmd->dev->base_addr);
188 awc_ints_enable(cmd->dev->base_addr, enabled_interrupts & ~0x10);
189 if(cmd->priv->enabled_interrupts & 0x10)
190 cmd->priv->enabled_interrupts &= ~0x10;
193 while ( awc_command_read(cmd->port) == cmd->command) {
194 udelay(1);
195 awc_command_write(cmd->port, cmd->command);
196 //if ((jiffies - jiff) > 2){
197 if (cnt > 2000 ){
198 printk(" long wait with commmand reg busy in blocking command \n");
199 awc_dump_registers(cmd->dev);
200 goto final;
202 if (cmd->priv->ejected)
203 goto final;
204 cnt++;
205 udelay(10);
208 AWC_ENTRY_EXIT_DEBUG(" issued " );
210 ticks = 0;
211 while ( awc_event_status_Cmd(cmd->port) == 0) {
212 ticks++;
213 if (ticks > 100000){
214 printk(" long wait with commmand reg busy \n");
215 awc_dump_registers(cmd->dev);
216 goto final;
218 if (ticks > 500){
219 DEBUG(1, " long wait after issue 10mks * %d ", ticks );
220 //printk(" long wait with command reg busy about ticks\n");
221 // sti();
223 if (cmd->priv->ejected)
224 goto final;
225 udelay(10);
227 if (cmd->priv->sleeping_bap) udelay(sleep_in_command);
229 awc_read_response(cmd);
230 AWC_ENTRY_EXIT_DEBUG(" resp read \n");
232 if (awc_command_busy(cmd->port))
233 awc_event_ack_ClrStckCmdBsy(cmd->port);
235 awc_event_ack_Cmd(cmd->port);
236 if (cmd->priv->sleeping_bap) udelay(sleep_in_command);
238 if (cmd->status & 0xff00){
239 printk(KERN_ERR " bad response to command %s, parameter %x \n",awc_print_string(awc_command_names, cmd->command),cmd->par0);
240 awc_dump_registers(cmd->dev);
241 goto final;
244 AWC_UNLOCK_COMMAND_ISSUING(cmd->priv);
245 AWC_ENTRY_EXIT_DEBUG(" exit \n");
246 udelay(1);
247 return 0;
248 final:
249 AWC_UNLOCK_COMMAND_ISSUING(cmd->priv);
250 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
251 return -1; ;
255 inline
256 unsigned short
257 awc_issue_command(struct awc_command * cmd){
260 // long long jiff = jiffies;
261 // unsigned short enabled_ints;
262 int cnt = 0;
263 // int i=0;
265 AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command");
267 if (!cmd){
268 printk(KERN_CRIT "cmd == NULL in awc_issue_command\n");
269 return -1;
272 if (!cmd->dev){
273 printk(KERN_CRIT "cmd->dev == NULL in awc_issue_command\n");
274 return -1;
278 AWC_LOCK_COMMAND_ISSUING(cmd->priv);
280 if(awc_command_busy_clear_wait(cmd->dev)) goto final;
282 if(!cmd->priv->enabled_interrupts & 0x10){
283 cmd->priv->enabled_interrupts |= 0x10;
284 awc_ints_enable(cmd->port, cmd->priv->enabled_interrupts );
287 cmd->priv->async_command_start = jiffies;
288 cmd->priv->command_semaphore_on++;
291 awc4500wout(cmd->port,cmd->command,cmd->par0,cmd->par1,cmd->par2);
293 while ( awc_command_read(cmd->port) == cmd->command) {
295 awc_command_write(cmd->port, cmd->command);
296 //if ((jiffies - jiff) > 2){
297 if (cnt > 2000) {
298 printk(" long wait with commmand reg busy in async command \n");
299 awc_dump_registers(cmd->dev);
300 goto final;
302 if (cmd->priv->ejected)
303 goto final;
304 cnt++;
305 udelay(10);
308 cmd->priv->cmd = *cmd;
311 AWC_ENTRY_EXIT_DEBUG(" exit \n");
312 return 0;
313 final:
314 AWC_UNLOCK_COMMAND_ISSUING(cmd->priv);
315 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
316 return -1; ;
320 inline
321 unsigned short
322 awc_issue_command_no_ack(struct NET_DEVICE * dev,
323 u16 com, u16 par1, u16 par2, u16 par3){
325 struct awc_private * priv = (struct awc_private *)dev->priv;
326 int cnt = 0;
327 long long jiff;
328 jiff = jiffies;
330 AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command_no_ack ");
333 AWC_LOCK_COMMAND_ISSUING(priv);
335 if (awc_command_busy_clear_wait(dev)) {
336 printk("aironet4x00 no_ack command (reset) with stuck card \n");
339 awc4500wout(dev->base_addr,com, par1, par2,par3);
341 udelay(10);
342 while ( awc_event_status_Cmd(dev->base_addr) == 0) {
343 if (awc_command_read(dev->base_addr) == com) {
344 awc_command_write(dev->base_addr, com);
346 //if ((jiffies - jiff) > 2){
347 if (cnt > 2000) {
348 printk(" long wait with commmand reg busy in noack command %d par %d %d %d\n",com,par1,par2,par3);
349 awc_dump_registers(dev);
350 goto final;
352 if (priv->ejected)
353 goto final;
354 udelay(10);
355 cnt++;
358 if (awc_command_busy(dev->base_addr))
359 awc_event_ack_ClrStckCmdBsy(dev->base_addr);
361 AWC_UNLOCK_COMMAND_ISSUING(priv);
362 AWC_ENTRY_EXIT_DEBUG(" exit \n");
363 return 0;
364 final:
365 AWC_UNLOCK_COMMAND_ISSUING(priv);
366 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
367 return -1; ;
371 /******************************** BAP *************************/
373 inline
374 int awc_bap_setup(struct awc_command * cmd) {
376 int status;
377 long long jiff;
378 unsigned long flags;
379 int cleared = 0;
380 int cycles = 0;
382 AWC_ENTRY_EXIT_DEBUG(" entry awc_bap_setup ");
384 if ( cmd->priv->sleeping_bap)
385 udelay(bap_sleep);
387 if (cmd->priv->ejected)
388 return -1;
390 if (!cmd->bap || !(cmd->lock_state & (AWC_BAP_SEMALOCKED |AWC_BAP_LOCKED)))
391 DEBUG(1,"no bap or bap not locked cmd %d !!", cmd->command);
393 if (bap_setup_spinlock)
394 my_spin_lock_irqsave(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags);
395 status = AWC_IN(cmd->bap->offset);
397 if (status & ~0x2000 ){
398 WAIT61x3;
399 status = AWC_IN(cmd->bap->offset);
402 if (status & ~0x2000 ){
403 WAIT61x3;
404 AWC_IN(cmd->dev->base_addr + 0x26);
405 AWC_OUT(cmd->dev->base_addr + 0x26, 0);
406 WAIT61x3;
407 udelay(60);
408 #ifdef AWC_DEBUG
409 printk("b");
410 #endif
411 status = AWC_IN(cmd->bap->offset);
415 if (status & 0xC000){
416 printk(KERN_ERR "bap entered with err or busy bit set %x \n",status);
417 if (cmd->bap->lock != 1)
418 printk(KERN_ERR "bap lock bad same time %x\n",cmd->bap->lock);
419 awc_dump_registers(cmd->dev);
420 // AWC_OUT(cmd->bap->offset, 0x800);
423 save_flags(flags);
424 cli();
426 AWC_OUT(cmd->bap->select, cmd->rid);
427 WAIT61x3;
428 AWC_OUT(cmd->bap->offset, cmd->offset);
430 restore_flags(flags);
432 WAIT61x3;
434 jiff = jiffies;
436 while (1) {
437 cycles++;
438 status = AWC_IN(cmd->bap->offset);
439 if ( cmd->priv->sleeping_bap)
440 udelay(bap_sleep);
441 if (cmd->priv->ejected)
442 goto ejected_unlock;
443 udelay(1);
444 if (cycles > 10000) {
445 printk(KERN_CRIT "deadlock in bap\n");
446 goto return_AWC_ERROR;
448 status = AWC_IN(cmd->bap->offset);
449 if (status & AWC_BAP_BUSY) {
450 if (cycles % 100 == 99 ) {
451 save_flags(flags);
452 cli();
453 if (!cleared){
454 AWC_IN(cmd->dev->base_addr + 0x26);
455 AWC_OUT(cmd->dev->base_addr + 0x26, 0);
456 WAIT61x3;
457 cleared = 1;
459 AWC_OUT(cmd->bap->select, cmd->rid);
460 WAIT61x3;
461 AWC_OUT(cmd->bap->offset, cmd->offset);
462 restore_flags(flags);
463 #ifdef AWC_DEBUG
464 printk("B");
465 #endif
467 if ( cmd->priv->sleeping_bap)
468 udelay(bap_sleep);
469 else udelay(30);
470 //restart_timeout();
472 if (jiffies - jiff > 1 ) {
473 AWC_ENTRY_EXIT_DEBUG(" BAD BUSY exit \n");
474 awc_dump_registers(cmd->dev);
475 goto return_AWC_ERROR;
477 continue;
479 if (status & AWC_BAP_DONE) {
480 WAIT61x3; WAIT61x3; WAIT61x3;
482 // if ((status & 0xfff) != cmd->offset)
483 // printk(KERN_ERR "awcPBD %x ",status);
484 AWC_ENTRY_EXIT_DEBUG(" exit \n");
485 if (cmd->priv->sleeping_bap)
486 udelay(bap_sleep_after_setup);
488 // success
489 goto return_AWC_SUCCESS;
492 if (status & AWC_BAP_ERR) {
493 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
494 // invalid rid or offset
495 printk(KERN_ERR "bap setup error bit set for rid %x offset %x \n",cmd->rid,cmd->offset);
496 awc_dump_registers(cmd->dev);
497 goto return_AWC_ERROR;
499 if ( cmd->priv->sleeping_bap)
500 udelay(bap_sleep);
501 else udelay(1);
502 // -- awc missed it, try again
504 save_flags(flags);
505 cli();
506 AWC_OUT(cmd->bap->select, cmd->rid);
507 WAIT61x3;
508 AWC_OUT(cmd->bap->offset, cmd->offset);
509 WAIT61x3;
510 restore_flags(flags);
512 if (jiffies - jiff > HZ)
513 if (! (status &(AWC_BAP_ERR |AWC_BAP_DONE |AWC_BAP_BUSY))){
514 printk("aironet4500: bap setup lock without any status bits set");
515 awc_dump_registers(cmd->dev);
516 goto return_AWC_ERROR;
522 AWC_ENTRY_EXIT_DEBUG(" WE MUST NOT BE HERE exit \n");
524 ejected_unlock:
525 if (bap_setup_spinlock)
526 my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags);
527 AWC_ENTRY_EXIT_DEBUG(" ejected_unlock_exit \n");
528 return -1;
530 return_AWC_ERROR:
531 if (bap_setup_spinlock)
532 my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags);
533 AWC_ENTRY_EXIT_DEBUG(" AWC_ERROR_exit \n");
534 return AWC_ERROR;
536 return_AWC_SUCCESS:
537 if (bap_setup_spinlock)
538 my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags);
539 AWC_ENTRY_EXIT_DEBUG(" exit \n");
540 return AWC_SUCCESS;
544 // requires call to awc_bap_setup() first
545 inline
547 awc_bap_read(struct awc_command * cmd) {
548 register u16 len;
549 register u16 * buff = (u16 *) cmd->buff;
550 register u16 port= cmd->bap->data;
553 AWC_ENTRY_EXIT_DEBUG(" entry awc_bap_read ");
554 if (!cmd->bap && !(cmd->lock_state & (AWC_BAP_SEMALOCKED |AWC_BAP_LOCKED)))
555 DEBUG(0,"no bap or bap not locked %d !!", cmd->command);
556 cmd->len = (cmd->len + 1) & (~1); // round up to even value
557 len = cmd->len / 2;
558 if (cmd->priv->ejected)
559 return -1;
562 if (cmd->priv->sleeping_bap)
563 udelay(bap_sleep_before_write);
565 if (!cmd->priv->sleeping_bap)
566 while ( len-- > 0)
567 *buff++ = AWC_IN(port);
568 else
569 while ( len-- > 0){
570 *buff++ = AWC_IN(port);
572 AWC_ENTRY_EXIT_DEBUG(" exit \n");
573 if (cmd->priv->ejected)
574 return -1;
576 return AWC_SUCCESS;
579 // requires call to awc_bap_setup() first
580 inline
582 awc_bap_write(struct awc_command * cmd){
583 register u16 len;
584 register u16 * buff = (u16 *) cmd->buff;
585 register u16 port= cmd->bap->data;
588 AWC_ENTRY_EXIT_DEBUG(" entry awc_bap_write ");
589 if (!cmd->bap && !(cmd->lock_state & (AWC_BAP_SEMALOCKED |AWC_BAP_LOCKED)))
590 DEBUG(0,"no bap or bap not locked %d !!", cmd->command);
592 cmd->len = (cmd->len + 1) & (~1); // round up to even value
593 len = cmd->len / 2;
595 if (cmd->priv->ejected)
596 return -1;
598 if (cmd->priv->sleeping_bap)
599 udelay(bap_sleep_before_write);
602 if (!cmd->priv->sleeping_bap)
603 while (len-- > 0)
604 AWC_OUT(port, *buff++);
605 else
606 while ( len-- > 0){
607 AWC_OUT(port, *buff++);
609 if (cmd->priv->ejected)
610 return -1;
613 AWC_ENTRY_EXIT_DEBUG(" exit \n");
615 return AWC_SUCCESS;
621 /***************************** RID READ/WRITE ********************/
623 const struct aironet4500_rid_selector aironet4500_RID_Select_General_Config =(const struct aironet4500_rid_selector){ 0xFF10, 1,0,0, "General Configuration" }; // See notes General Configuration Many configuration items.
624 const struct aironet4500_rid_selector aironet4500_RID_Select_SSID_list =(const struct aironet4500_rid_selector){ 0xFF11, 1,0,0, "Valid SSID list" }; // See notes Valid SSID list List of SSIDs which the station may associate to.
625 const struct aironet4500_rid_selector aironet4500_RID_Select_AP_list =(const struct aironet4500_rid_selector){ 0xFF12, 1,0,0, "Valid AP list" }; // See notes Valid AP list List of APs which the station may associate to.
626 const struct aironet4500_rid_selector aironet4500_RID_Select_Driver_name =(const struct aironet4500_rid_selector){ 0xFF13, 1,0,0, "Driver name" }; // See notes Driver name The name and version of the driver (for debugging)
627 const struct aironet4500_rid_selector aironet4500_RID_Select_Encapsulation =(const struct aironet4500_rid_selector){ 0xFF14, 1,0,0, "Ethernet Protocol" }; // See notes Ethernet Protocol Rules for encapsulating ethernet payloads onto 802.11.
628 const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_volatile =(const struct aironet4500_rid_selector){ 0xFF15, 1,0,0, "WEP key volatile" }; //
629 const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_nonvolatile =(const struct aironet4500_rid_selector){ 0xFF16, 1,0,0, "WEP key non-volatile" }; //
630 const struct aironet4500_rid_selector aironet4500_RID_Select_Modulation =(const struct aironet4500_rid_selector){ 0xFF17, 1,0,0, "Modulation" }; //
631 const struct aironet4500_rid_selector aironet4500_RID_Select_Active_Config =(const struct aironet4500_rid_selector){ 0xFF20, 0,1,1, "Actual Configuration" }; // Read only Actual Configuration This has the same format as the General Configuration.
632 const struct aironet4500_rid_selector aironet4500_RID_Select_Capabilities =(const struct aironet4500_rid_selector){ 0xFF00, 0,1,0, "Capabilities" }; // Read Only Capabilities PC4500 Information
633 const struct aironet4500_rid_selector aironet4500_RID_Select_AP_Info =(const struct aironet4500_rid_selector){ 0xFF01, 0,1,1, "AP Info" }; // Read Only AP Info Access Point Information
634 const struct aironet4500_rid_selector aironet4500_RID_Select_Radio_Info =(const struct aironet4500_rid_selector){ 0xFF02, 0,1,1, "Radio Info" }; // Read Only Radio Info Radio Information -- note radio specific
635 const struct aironet4500_rid_selector aironet4500_RID_Select_Status =(const struct aironet4500_rid_selector){ 0xFF50, 0,1,1, "Status" }; // Read Only Status PC4500 Current Status Information
636 const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats =(const struct aironet4500_rid_selector){ 0xFF60, 0,1,1, "Cumulative 16-bit Statistics" }; // Read Only 16-bit Statistics Cumulative 16-bit Statistics
637 const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_delta =(const struct aironet4500_rid_selector){ 0xFF61, 0,1,1, "Delta 16-bit Statistics" }; // Read Only 16-bit Statistics Delta 16-bit Statistics (since last clear)
638 const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_clear =(const struct aironet4500_rid_selector){ 0xFF62, 0,1,1, "Delta 16-bit Statistics and Clear" }; // Read Only / 16-bit Statistics Delta 16-bit Statistics and Clear
639 const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats =(const struct aironet4500_rid_selector){ 0xFF68, 0,1,1, "Cumulative 32-bit Statistics" }; // Read Only 32-bit Statistics Cumulative 32-bit Statistics
640 const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_delta =(const struct aironet4500_rid_selector){ 0xFF69, 0,1,1, "Delta 32-bit Statistics" }; // Read Only 32-bit Statistics Delta 32-bit Statistics (since last clear)
641 const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_clear =(const struct aironet4500_rid_selector){ 0xFF6A, 0,1,1, "Delta 32-bit Statistics and Clear" }; // Read Only / 32-bit Statistics Delta 32-bit Statistics and Clear
643 EXPORT_SYMBOL(aironet4500_RID_Select_General_Config);
644 EXPORT_SYMBOL(aironet4500_RID_Select_SSID_list);
645 EXPORT_SYMBOL(aironet4500_RID_Select_AP_list);
646 EXPORT_SYMBOL(aironet4500_RID_Select_Driver_name);
647 EXPORT_SYMBOL(aironet4500_RID_Select_Encapsulation);
648 EXPORT_SYMBOL(aironet4500_RID_Select_WEP_volatile);
649 EXPORT_SYMBOL(aironet4500_RID_Select_WEP_nonvolatile);
650 EXPORT_SYMBOL(aironet4500_RID_Select_Modulation);
651 EXPORT_SYMBOL(aironet4500_RID_Select_Active_Config);
652 EXPORT_SYMBOL(aironet4500_RID_Select_Capabilities);
653 EXPORT_SYMBOL(aironet4500_RID_Select_AP_Info);
654 EXPORT_SYMBOL(aironet4500_RID_Select_Radio_Info);
655 EXPORT_SYMBOL(aironet4500_RID_Select_Status);
656 EXPORT_SYMBOL(aironet4500_RID_Select_16_stats);
657 EXPORT_SYMBOL(aironet4500_RID_Select_16_stats_delta);
658 EXPORT_SYMBOL(aironet4500_RID_Select_16_stats_clear);
659 EXPORT_SYMBOL(aironet4500_RID_Select_32_stats);
660 EXPORT_SYMBOL(aironet4500_RID_Select_32_stats_delta);
661 EXPORT_SYMBOL(aironet4500_RID_Select_32_stats_clear);
664 struct awc_rid_dir awc_rids_temp[]={
665 // following MUST be consistent with awc_rids_setup !!!
666 {&aironet4500_RID_Select_General_Config, 0x100 , NULL, NULL, NULL,0 },
667 {&aironet4500_RID_Select_SSID_list, 0x68 , NULL, NULL, NULL,0 },
668 {&aironet4500_RID_Select_AP_list, 0x20 , NULL, NULL, NULL,0 },
669 {&aironet4500_RID_Select_Driver_name, 0x12 , NULL, NULL, NULL,0 },
670 {&aironet4500_RID_Select_Encapsulation, 0x22 , NULL, NULL, NULL,0 },
671 {&aironet4500_RID_Select_Active_Config, 0x100 , NULL, NULL, NULL,0 },
672 {&aironet4500_RID_Select_Capabilities, 0x80 , NULL, NULL, NULL,0 },
673 {&aironet4500_RID_Select_Status, 0x6c , NULL, NULL, NULL,0 },
674 {&aironet4500_RID_Select_AP_Info, 0x06 , NULL, NULL, NULL,0 },
675 {&aironet4500_RID_Select_32_stats, 0x184 , NULL, NULL, NULL,0 },
676 {&aironet4500_RID_Select_32_stats_delta, 0x184 , NULL, NULL, NULL,0 },
677 {&aironet4500_RID_Select_32_stats_clear, 0x184 , NULL, NULL, NULL,0 },
678 {&aironet4500_RID_Select_WEP_volatile, 0x1c , NULL, NULL, NULL,0 },
679 {&aironet4500_RID_Select_WEP_nonvolatile, 0x1c , NULL, NULL, NULL,0 },
680 {&aironet4500_RID_Select_Modulation, 0x04 , NULL, NULL, NULL,0 },
682 #ifdef AWC_USE_16BIT_STATS
683 {&aironet4500_RID_Select_16_stats, 0xC2 , NULL, NULL, NULL,0 },
684 {&aironet4500_RID_Select_16_stats_delta, 0xC2 , NULL, NULL, NULL,0 },
685 {&aironet4500_RID_Select_16_stats_clear, 0xC2 , NULL, NULL, NULL,0 },
686 #else
687 {NULL},{NULL},{NULL},
688 #endif
690 {0}
697 int
698 awc_readrid(struct NET_DEVICE * dev, struct aironet4500_RID * rid, void *pBuf ){
699 struct awc_command cmd;
701 int sleep_state ;
703 AWC_ENTRY_EXIT_DEBUG(" entry awc_readrid ");
704 if (!rid) return -1;
705 if (!rid->selector) return -1;
706 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector,
707 rid->selector->selector, rid->offset, (rid->bits / 8),pBuf);
709 sleep_state = cmd.priv->sleeping_bap ;
710 cmd.priv->sleeping_bap = 1;
711 udelay(500);
712 AWC_BAP_LOCK_NOT_CLI(cmd);
713 if (awc_issue_command_and_block(&cmd)) goto final;
714 udelay(1);
715 if (awc_bap_setup(&cmd)) goto final;
716 udelay(1);
717 if (awc_bap_read(&cmd)) goto final;
718 cmd.priv->sleeping_bap = sleep_state;
720 AWC_RELEASE_COMMAND(cmd);
721 AWC_ENTRY_EXIT_DEBUG(" exit \n");
722 return 0;
723 final:
724 cmd.priv->sleeping_bap = sleep_state;
725 AWC_RELEASE_COMMAND(cmd);
726 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
727 return -1; ;
730 int
731 awc_writerid(struct NET_DEVICE * dev, struct aironet4500_RID * rid, void *pBuf){
733 struct awc_command cmd;
734 int sleep_state ;
736 AWC_ENTRY_EXIT_DEBUG(" entry awc_writerid ");
739 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector,
740 rid->selector->selector,rid->offset, rid->bits/8,pBuf);
742 sleep_state = cmd.priv->sleeping_bap ;
743 cmd.priv->sleeping_bap = 1;
745 udelay(500);
746 AWC_BAP_LOCK_NOT_CLI(cmd);
747 if (awc_issue_command_and_block(&cmd)) goto final;
748 udelay(10);
749 if (awc_bap_setup(&cmd)) goto final;
750 udelay(10);
751 if (awc_bap_write(&cmd)) goto final;
752 udelay(10);
753 cmd.command=0x121;
754 if (awc_issue_command_and_block(&cmd)) goto final;
755 cmd.priv->sleeping_bap = sleep_state;
757 AWC_RELEASE_COMMAND(cmd);
758 AWC_ENTRY_EXIT_DEBUG(" exit \n");
759 return 0;
760 final:
761 cmd.priv->sleeping_bap = sleep_state;
762 AWC_RELEASE_COMMAND(cmd);
763 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
764 return -1; ;
767 int
768 awc_readrid_dir(struct NET_DEVICE * dev, struct awc_rid_dir * rid ){
769 struct awc_command cmd;
770 int sleep_state;
772 AWC_ENTRY_EXIT_DEBUG(" entry awcreadrid_dir ");
775 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector,
776 rid->selector->selector,0, rid->bufflen,rid->buff);
778 sleep_state = cmd.priv->sleeping_bap ;
779 cmd.priv->sleeping_bap = 1;
781 udelay(500);
783 AWC_BAP_LOCK_NOT_CLI(cmd);
784 if (awc_issue_command_and_block(&cmd)) goto final;
786 if (awc_bap_setup(&cmd)) goto final;
787 if (awc_bap_read(&cmd)) goto final;
788 cmd.priv->sleeping_bap = sleep_state;
790 AWC_RELEASE_COMMAND(cmd);
791 AWC_ENTRY_EXIT_DEBUG(" exit \n");
792 return 0;
793 final:
794 cmd.priv->sleeping_bap = sleep_state;
795 AWC_RELEASE_COMMAND(cmd);
796 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
797 return -1; ;
800 int
801 awc_writerid_dir(struct NET_DEVICE * dev, struct awc_rid_dir * rid){
803 struct awc_command cmd;
804 int sleep_state ;
807 AWC_ENTRY_EXIT_DEBUG(" entry awc_writerid_dir ");
811 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector,
812 rid->selector->selector,0, rid->bufflen,((char *)rid->buff));
814 sleep_state = cmd.priv->sleeping_bap ;
815 cmd.priv->sleeping_bap = 1;
817 udelay(500);
819 AWC_BAP_LOCK_NOT_CLI(cmd);
821 if (awc_issue_command_and_block(&cmd)) goto final;
822 if (awc_bap_setup(&cmd)) goto final;
823 if (awc_bap_write(&cmd)) goto final;
824 cmd.priv->sleeping_bap = sleep_state;
826 cmd.command=0x121;
827 udelay(500);
828 if (awc_issue_command_and_block(&cmd)) goto final;
830 AWC_RELEASE_COMMAND(cmd);
831 AWC_ENTRY_EXIT_DEBUG(" exit \n");
832 return 0;
833 final:
834 cmd.priv->sleeping_bap = sleep_state;
835 AWC_RELEASE_COMMAND(cmd);
836 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
837 return -1; ;
840 EXPORT_SYMBOL(awc_readrid);
841 EXPORT_SYMBOL(awc_writerid);
842 EXPORT_SYMBOL(awc_readrid_dir);
843 EXPORT_SYMBOL(awc_writerid_dir);
845 /***************************** STARTUP *******************/
848 inline
850 awc_issue_blocking_command(struct NET_DEVICE * dev,u16 comm){
852 struct awc_command cmd;
853 // struct awc_private * priv = (struct awc_private *)dev->priv;
855 AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_blocking_command ");
857 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,comm,0, 0, 0, 0 ,0 );
859 AWC_BAP_LOCK_NOT_CLI(cmd);
861 if (awc_issue_command_and_block(&cmd))
862 goto final;
864 AWC_RELEASE_COMMAND(cmd);
865 AWC_ENTRY_EXIT_DEBUG(" exit \n");
866 return 0;
867 final:
868 AWC_RELEASE_COMMAND(cmd);
869 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
870 return -1; ;
874 int
875 awc_issue_soft_reset(struct NET_DEVICE * dev){
877 u16 status ;
878 // int i= 0;
880 /* outw(inw(dev->base_addr + 0x30), dev->base_addr + 0x32);
881 udelay(10);
882 outw(inw(dev->base_addr + 0x30), dev->base_addr + 0x34);
884 for (i=0; i< 32; i++)
885 outw(0,dev->base_addr + i*2);
886 udelay(100);
887 outw(0x6,dev->base_addr + 0x34);
888 udelay(100);
889 outw(0x6,dev->base_addr + 0x34);
890 outw(0x6,dev->base_addr + 0x34);
891 WAIT61x3;
892 AWC_IN(dev->base_addr + 0x26);
893 AWC_OUT(dev->base_addr + 0x26, 0);
894 WAIT61x3;
895 udelay(60);
898 outw(0x4, dev->base_addr);
899 udelay(1000);
900 WAIT61x3;
901 AWC_IN(dev->base_addr + 0x26);
902 AWC_OUT(dev->base_addr + 0x26, 0);
903 WAIT61x3;
904 udelay(60);
907 status = awc_issue_command_no_ack(dev, AWC_COMMAND_SOFT_RESET,0,0,0);
909 // awc_command_busy_clear_wait(dev);
911 return status;
915 awc_issue_noop(struct NET_DEVICE * dev){
916 int retval;
917 AWC_OUT(dev->base_addr + 0x28, 0);
918 AWC_OUT(dev->base_addr + 0x2A, 0);
919 udelay(1000);
920 retval= awc_issue_blocking_command(dev, AWC_COMMAND_NOOP);
921 udelay(1000);
922 return retval;
925 EXPORT_SYMBOL(awc_enable_MAC);
928 awc_enable_MAC(struct NET_DEVICE * dev){
930 struct awc_private * priv = (struct awc_private *)dev->priv;
931 AWC_ENTRY_EXIT_DEBUG(" entry awc_enable_MAC ");
933 if (priv->mac_enabled){
935 AWC_ENTRY_EXIT_DEBUG(" mac already enabled exit \n");
936 return 0;
938 udelay(500);
939 if (awc_issue_blocking_command(dev, AWC_COMMAND_ENABLE)){
940 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
941 return -1; ;
943 udelay(500);
945 priv->mac_enabled = 1;
947 AWC_ENTRY_EXIT_DEBUG(" exit \n");
948 return 0;
951 EXPORT_SYMBOL(awc_disable_MAC);
953 awc_disable_MAC(struct NET_DEVICE * dev){
955 struct awc_private * priv = (struct awc_private *)dev->priv;
956 AWC_ENTRY_EXIT_DEBUG(" entry awc_disable_MAC ");
958 if (!priv->mac_enabled){
959 AWC_ENTRY_EXIT_DEBUG(" mac allready disabled exit \n");
960 return 0;
962 udelay(1000);
963 if (awc_issue_blocking_command(dev, AWC_COMMAND_DISABLE)){
964 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
965 return -1; ;
967 udelay(1000);
968 priv->mac_enabled = 0;
969 AWC_ENTRY_EXIT_DEBUG(" exit \n");
970 return 0;
976 awc_read_all_rids(struct NET_DEVICE * dev){
978 struct awc_private * priv = (struct awc_private *)dev->priv;
979 int status,i;
980 AWC_ENTRY_EXIT_DEBUG(" entry awc_read_all_rids ");
982 for (i=0; i< AWC_NOF_RIDS && priv->rid_dir[i].selector ; i++){
983 status = awc_readrid_dir(dev,&priv->rid_dir[i]);
984 udelay(50);
985 if (status) return status;
988 priv->rids_read = 1;
990 AWC_ENTRY_EXIT_DEBUG(" exit \n");
991 return 0;
995 awc_write_all_rids(struct NET_DEVICE * dev){
997 struct awc_private * priv = (struct awc_private *)dev->priv;
998 int i,status ;
999 AWC_ENTRY_EXIT_DEBUG(" entry awc_write_all_rids ");
1001 for (i=0;i < 5 && i< AWC_NOF_RIDS && priv->rid_dir[i].selector ; i++){
1002 status = awc_writerid_dir(dev,&priv->rid_dir[i]);
1003 udelay(10);
1004 if(status) return status;
1006 AWC_ENTRY_EXIT_DEBUG(" exit \n");
1007 return 0;
1010 /************************** FID QUEUES ****************************/
1011 /**************************** TX ALLOC / DEALLOC ***************/
1015 int awc_tx_alloc(struct NET_DEVICE * dev) {
1017 struct awc_command cmd;
1018 int k=0;
1019 int tot=0;
1020 struct awc_fid * fid = NULL;
1022 AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_alloc ");
1025 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x0A,0, 0,0,0,NULL);
1026 cmd.par0 = dev->mtu + AWC_TX_HEAD_SIZE + 8 ;
1028 DEBUG(32,"about to allocate %x bytes ",cmd.priv->large_buff_mem);
1029 DEBUG(32,"in %x large buffers ",cmd.priv->large_buff_mem / (dev->mtu + AWC_TX_HEAD_SIZE + 8) );
1031 k=0;tot=0;
1032 AWC_BAP_LOCK_NOT_CLI(cmd);
1034 while (k < cmd.priv->large_buff_mem / (dev->mtu + AWC_TX_HEAD_SIZE + 8) ) {
1036 fid = kmalloc(sizeof(struct awc_fid),GFP_KERNEL );
1037 if (!fid) goto final;
1038 memset(fid, 0, sizeof(struct awc_fid));
1040 if (awc_issue_command_and_block(&cmd)) goto final;
1042 while ( awc_event_status_Alloc(cmd.port) == 0) ;
1043 fid->u.tx.fid = awc_Tx_Allocated_Fid(cmd.port);
1044 fid->u.tx.fid_size = dev->mtu + AWC_TX_HEAD_SIZE ;
1046 DEBUG(32,"allocated large tx fid %x ",fid->u.tx.fid);
1047 if(fid->u.tx.fid == 0
1048 || cmd.status != 0xA){
1049 printk(KERN_ERR "%s bad tx_alloc\n",dev->name);
1050 fid->busy =1;
1051 goto final;
1052 } else {
1053 fid->busy =0;
1054 tot++;
1056 awc_event_ack_Alloc(cmd.port);
1058 // shoudlnt goto final after that
1059 awc_fid_queue_push_tail(&cmd.priv->tx_large_ready,fid);
1061 k++;
1063 cmd.priv->tx_buffs_total = tot;
1064 DEBUG(32,"allocated %d large tx buffs\n",tot);
1066 cmd.par0 = AWC_TX_ALLOC_SMALL_SIZE ;
1067 k =0; tot = 0;
1069 while (k < cmd.priv->small_buff_no) {
1071 fid = kmalloc(sizeof(struct awc_fid),GFP_KERNEL );
1072 if (!fid) goto final;
1073 memset(fid, 0, sizeof(struct awc_fid));
1075 cmd.par0 = AWC_TX_ALLOC_SMALL_SIZE ;
1077 if (awc_issue_command_and_block(&cmd)) goto final;
1079 while ( awc_event_status_Alloc(cmd.port) == 0) ;
1080 fid->u.tx.fid = awc_Tx_Allocated_Fid(cmd.port);
1081 fid->u.tx.fid_size = AWC_TX_ALLOC_SMALL_SIZE;
1083 DEBUG(32,"allocated large tx fid %x ",fid->u.tx.fid);
1084 if(fid->u.tx.fid == 0
1085 || cmd.status != 0xA){
1086 printk(KERN_ERR "%s bad tx_alloc\n",dev->name);
1087 fid->busy =1;
1088 goto final;
1089 } else {
1090 fid->busy =0;
1091 tot++;
1093 awc_event_ack_Alloc(cmd.port);
1095 // shoudlnt goto final after that
1096 awc_fid_queue_push_tail(&cmd.priv->tx_small_ready,fid);
1098 k++;
1101 cmd.priv->tx_small_buffs_total = tot;
1102 DEBUG(32,"allocated %d small tx buffs\n",tot);
1104 AWC_RELEASE_COMMAND(cmd);
1105 AWC_ENTRY_EXIT_DEBUG(" exit \n");
1106 return 0;
1108 final:
1109 if (fid )
1110 kfree(fid);
1111 printk(KERN_CRIT "%s awc tx prealloc failed \n",dev->name);
1112 AWC_RELEASE_COMMAND(cmd);
1113 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
1114 return -1; ;
1118 int
1119 awc_tx_dealloc_fid(struct NET_DEVICE * dev,struct awc_fid * fid){
1121 struct awc_command cmd;
1122 int fid_handle = 0;
1124 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x0C,0, 0,0,0,NULL);
1126 AWC_BAP_LOCK_NOT_CLI(cmd);
1128 if (fid->u.tx.fid){
1129 fid_handle = cmd.par0 = fid->u.tx.fid;
1130 fid->u.tx.fid = 0;
1131 fid->busy =0;
1132 kfree(fid);
1134 if (!cmd.priv->ejected)
1135 if (awc_issue_command_and_block(&cmd)) goto final;
1136 //awc_event_ack_Alloc(cmd.port);
1139 AWC_RELEASE_COMMAND(cmd);
1140 AWC_ENTRY_EXIT_DEBUG(" exit \n");
1141 return 0;
1143 final:
1144 printk(KERN_ERR "awc_tx_dealloc failed for fid %x \n",fid_handle);
1145 AWC_RELEASE_COMMAND(cmd);
1146 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
1147 return -1; ;
1153 awc_tx_dealloc(struct NET_DEVICE * dev){
1155 struct awc_private * priv = (struct awc_private *)dev->priv;
1159 // int k=0;
1160 struct awc_fid * fid;
1162 AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_dealloc ");
1164 while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_large_ready)))
1165 awc_tx_dealloc_fid(dev,fid);
1166 while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_small_ready)))
1167 awc_tx_dealloc_fid(dev,fid);
1168 while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_post_process)))
1169 awc_tx_dealloc_fid(dev,fid);
1170 while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_in_transmit)))
1171 awc_tx_dealloc_fid(dev,fid);
1173 return 0;
1179 inline struct awc_fid *
1180 awc_tx_fid_lookup_and_remove(struct NET_DEVICE * dev, u16 fid_handle){
1182 struct awc_private * priv = (struct awc_private *)dev->priv;
1183 // int k = 0;
1184 unsigned long flags;
1185 struct awc_fid * fid = NULL;
1186 int cnt=0;
1188 AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_fid_lookup ");
1190 my_spin_lock_irqsave(&(priv->queues_lock),flags);
1193 fid = priv->tx_in_transmit.head;
1194 cnt = 0;
1195 while (fid){
1196 if (fid->u.tx.fid == fid_handle){
1197 awc_fid_queue_remove(&priv->tx_in_transmit, fid);
1198 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1199 return fid;
1201 fid = fid->next;
1202 // printk("iT\n");
1203 if (cnt++ > 200) {
1204 // printk("bbb in awc_fid_queue\n");
1205 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1206 return 0;
1210 cnt=0;
1211 fid = priv->tx_post_process.head;
1212 while (fid){
1213 if (fid->u.tx.fid == fid_handle){
1214 awc_fid_queue_remove(&priv->tx_post_process, fid);
1215 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1216 return fid;
1218 fid = fid->next;
1219 // printk("pp\n");
1220 if (cnt++ > 200) {
1221 // printk("bbb in awc_fid_queue\n");
1222 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1223 return 0;
1228 cnt=0;
1229 fid = priv->tx_large_ready.head;
1230 while (fid){
1231 if (fid->u.tx.fid == fid_handle){
1232 awc_fid_queue_remove(&priv->tx_large_ready, fid);
1233 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1234 return fid;
1236 fid = fid->next;
1237 // printk("lr\n");
1238 if (cnt++ > 200) {
1239 // printk("bbb in awc_fid_queue\n");
1240 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1241 return 0;
1245 cnt=0;
1246 fid = priv->tx_small_ready.head;
1247 while (fid){
1248 if (fid->u.tx.fid == fid_handle){
1249 awc_fid_queue_remove(&priv->tx_small_ready, fid);
1250 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1251 return fid;
1253 fid = fid->next;
1254 // printk("sr\n");
1255 if (cnt++ > 200) {
1256 // printk("bbb in awc_fid_queue\n");
1257 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1258 return 0;
1263 my_spin_unlock_irqrestore(&(priv->queues_lock),flags);
1265 printk(KERN_ERR "%s tx fid %x not found \n",dev->name, fid_handle);
1266 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
1267 return NULL;
1274 int
1275 awc_queues_init(struct NET_DEVICE * dev){
1276 struct awc_private * priv = (struct awc_private *)dev->priv;
1277 struct awc_fid * fid = NULL;
1278 int retv =0;
1279 int k = 0;
1281 awc_fid_queue_init(&priv->tx_in_transmit);
1282 awc_fid_queue_init(&priv->tx_post_process);
1283 awc_fid_queue_init(&priv->tx_large_ready);
1284 awc_fid_queue_init(&priv->tx_small_ready);
1285 awc_fid_queue_init(&priv->rx_ready);
1286 awc_fid_queue_init(&priv->rx_post_process);
1288 retv = awc_tx_alloc(dev);
1290 k = 0;
1291 while (k < AWC_RX_BUFFS){
1292 fid = kmalloc(sizeof(struct awc_fid),GFP_KERNEL);
1293 if (!fid) return -1;
1294 awc_fid_queue_push_tail(&priv->rx_ready,fid);
1295 k++;
1298 if (retv) return retv;
1300 return 0;
1304 int
1305 awc_queues_destroy(struct NET_DEVICE * dev){
1306 struct awc_private * priv = (struct awc_private *)dev->priv;
1307 struct awc_fid * fid = NULL;
1308 int retv =0;
1312 while (NULL != (fid = awc_fid_queue_pop_head(&priv->rx_ready))){
1313 kfree(fid);
1315 while (NULL != (fid = awc_fid_queue_pop_head(&priv->rx_post_process))){
1316 kfree(fid);
1319 retv = awc_tx_dealloc(dev);
1321 return retv;
1326 /****************************** 802.11router ******************/
1327 inline int
1328 awc_802_11_copy_path_skb(struct NET_DEVICE * dev, struct awc_fid * rx_buff){
1330 struct awc_private * priv = (struct awc_private * )dev->priv;
1332 AWC_ENTRY_EXIT_DEBUG("awc_802_11_copy_path_skb");
1334 if (rx_buff->pkt_len < 22 ) rx_buff->pkt_len = 22;
1336 // if (!rx_buff->skb)
1337 rx_buff->skb = dev_alloc_skb(rx_buff->pkt_len + 12 +2);
1340 if (rx_buff->skb == NULL) {
1341 printk(KERN_CRIT "couldnt alloc rx_buff->skb in rx event \n");
1342 priv->stats.rx_dropped++;
1343 return -1;
1345 rx_buff->type |= p80211copy_path_skb;
1347 rx_buff->skb->dev = dev;
1349 // skb_reserve(rx_buff->skb, rx_buff->pkt_len + 12 );
1351 rx_buff->u.rx.payload = skb_put(rx_buff->skb, rx_buff->pkt_len + 12 ) ;
1352 rx_buff->u.rx.payload = ((char *)rx_buff->u.rx.payload ) +12;
1354 AWC_ENTRY_EXIT_DEBUG("exit\n");
1356 return 0;
1363 awc_802_11_find_copy_path(struct NET_DEVICE * dev, struct awc_fid * rx_buff){
1365 // struct awc_private * priv = (struct awc_private * )dev->priv;
1366 // u8 is_802_3 = 0;
1367 // int i = 0;
1369 rx_buff->type =0;
1371 return awc_802_11_copy_path_skb(dev,rx_buff);
1375 /* called from INTERRUPT context,
1377 must deliver the packet to where it was meant by
1378 awc_802_11_find_copy_path
1380 SHOULD be efficient and
1381 queue the packet if operations take longer
1386 int parse_not_8023= 0;
1388 void
1389 awc_802_11_router_rx(struct NET_DEVICE * dev,struct awc_fid * rx_buff){
1391 struct awc_private * priv = (struct awc_private * )dev->priv;
1392 struct sk_buff * skb = rx_buff->skb;
1393 u8 * payload = rx_buff->u.rx.payload;
1394 // u8 * p802_3_macs_place = payload -12;
1395 u16 pkt_len = rx_buff->pkt_len;
1396 struct ieee_802_11_802_1H_header * bridge = NULL;
1397 struct ieee_802_11_snap_header * snap = NULL;
1398 struct ieee_802_11_802_1H_header * bridge_tmp;
1399 struct ieee_802_11_snap_header * snap_tmp;
1401 u16 ptr = 0;
1402 u16 len;
1404 AWC_ENTRY_EXIT_DEBUG("awc_802_11_router_rx");
1406 // if (rx_buff->type & p80211_8023)
1407 rx_buff->mac = rx_buff->u.rx.ieee_802_3.dst_mac;
1408 // else
1409 // rx_buff->mac = rx_buff->u.rx.ieee_802_11.mac1;
1411 if ( rx_buff->u.rx.ieee_802_11.frame_control == 0x8 )
1412 memcpy(priv->bssid,rx_buff->u.rx.ieee_802_11.mac3,6);
1414 while ((ptr < pkt_len - 1 ) && payload && parse_not_8023){
1416 bridge_tmp = (struct ieee_802_11_802_1H_header*) &payload[ptr];
1417 snap_tmp = (struct ieee_802_11_snap_header*) &payload[ptr];
1418 len = ntohs( *((u16*)&payload[ptr]) );
1422 if ( len < 0x5DC) { // not a protocol
1424 if ( len != pkt_len-2 - ptr){
1425 printk(KERN_ERR "%s bad encapsulation lenght %x at pkt offset %x \n",dev->name,len,ptr);
1426 goto bad_packet;
1428 DEBUG(1,"parisng packet of size %x\n",len);
1429 ptr +=2;
1430 continue;
1433 DEBUG(1,"parisng packet of proto %x\n",len);
1435 if (snap_tmp->dsap == 0xaa && snap_tmp->ssap == 0xaa &&
1436 pkt_len - ptr > sizeof(struct ieee_802_11_snap_header) ){
1438 DEBUG(0x200,"%s SNAP ",dev->name);
1439 if (snap_tmp->ctrl != 0x03){
1440 printk(KERN_ERR "%s unknown snap ctrl %x \n",dev->name,snap_tmp->ctrl);
1441 goto bad_packet;
1443 if (snap_tmp->oui[0] == 0 && // LLC RFC1042
1444 snap_tmp->oui[1] == 0 &&
1445 snap_tmp->oui[2] == 0 ){
1446 snap = snap_tmp;
1447 ptr += sizeof(struct ieee_802_11_snap_header);
1448 DEBUG(0x200,"%s LLC RFC1042 \n",dev->name);
1449 continue;
1451 if (snap_tmp->oui[0] == 0 && // LLC 802.1H
1452 snap_tmp->oui[1] == 0 &&
1453 snap_tmp->oui[2] == 0x78){
1454 snap = snap_tmp;
1455 DEBUG(0x200,"%s LLC 802.1H \n",dev->name);
1456 ptr += sizeof(struct ieee_802_11_snap_header);
1457 continue;
1459 if (snap_tmp->oui[0] == 0x00 && // 802.1H itself
1460 snap_tmp->oui[1] == 0x40 &&
1461 snap_tmp->oui[2] == 0x96){
1462 ptr += sizeof(struct ieee_802_11_802_1H_header);
1463 if (ptr >= pkt_len){
1464 goto bad_packet;
1465 DEBUG(1,"%s invalid packet len in 802.1H SNAP OUI check \n",dev->name);
1467 DEBUG(0x200,"%s OUI 004096 \n",dev->name);
1468 DEBUG(0x200," 802.1H uknown1 %x ",ntohs(bridge_tmp->unknown1));
1469 DEBUG(0x200," 802.1H uknw type %x \n",0xf000 & ntohs(bridge_tmp->unknown2));
1470 DEBUG(0x200," 802.1H payloadsize %x \n",0x0fff & ntohs(bridge_tmp->unknown2));
1472 //goto bad_packet; // TODO
1474 bridge = bridge_tmp;
1475 if (bridge_tmp->unknown1 == 0x0000 &&
1476 ((ntohs(bridge_tmp->unknown2) & 0xf000) == 0x1000 ) ){
1477 rx_buff->type |= p80211_8021H;
1478 rx_buff->mac = &payload[ptr];
1479 DEBUG(0x200," 802.1H DATA packet of size %x\n",0xf000 & ntohs(bridge_tmp->unknown2) );
1480 memcpy(priv->p2p,rx_buff->u.rx.ieee_802_11.mac2, 6);
1481 ptr +=12;
1482 continue;
1484 DEBUG(0x200,"%s droping unknown 004096 packet \n ",dev->name);
1485 goto bad_packet;
1489 goto bad_packet;
1491 if ( len > 0x5DC){
1492 // packet without linklevel header for us
1494 if ( len == 0x8000 || len == 0x8006){
1496 DEBUG(0x200,"Non IP packet %x \n",ntohs(len));
1499 goto good_packet;
1503 goto good_packet;
1506 good_packet:
1508 if (ptr > pkt_len) goto bad_packet;
1510 if ( rx_buff->mac != (payload + ptr -12) )
1511 memcpy( payload +ptr -12, rx_buff->mac , 12);
1515 if (!payload || !skb || !rx_buff->skb || !rx_buff->u.rx.payload)
1516 return ;
1517 //skb->ip_summed = CHECKSUM_NONE;
1518 skb->data = payload + ptr -12;
1519 skb->len += ptr ;
1521 rx_buff->skb->protocol = eth_type_trans(rx_buff->skb,dev);
1522 DEBUG(0x200,"eth_type_trans decided: %x\n",rx_buff->skb->protocol);
1523 rx_buff->skb = NULL;
1524 rx_buff->u.rx.payload = NULL;
1525 priv->stats.rx_packets++;
1526 netif_rx(skb);
1527 AWC_ENTRY_EXIT_DEBUG("exit\n");
1528 return ;
1530 bad_packet:
1531 DEBUG(0x200,"%s packet dropped in packet hdr parse \n ",dev->name);
1532 if (rx_buff->skb && (rx_buff->type & p80211copy_path_skb)){
1534 FREE_SKB(rx_buff->skb);
1535 rx_buff->skb = NULL;
1536 rx_buff->u.rx.payload = NULL;
1539 AWC_ENTRY_EXIT_DEBUG("exit\n");
1543 void
1544 awc_802_11_failed_rx_copy(struct NET_DEVICE * dev,struct awc_fid * rx_buff){
1545 struct awc_private * priv = (struct awc_private * )dev->priv;
1548 AWC_ENTRY_EXIT_DEBUG("awc_802_11_failed_rx_copy");
1549 if (rx_buff->skb)
1550 FREE_SKB(rx_buff->skb);
1551 rx_buff->skb = NULL;
1552 rx_buff->u.rx.payload = NULL;
1553 priv->stats.rx_errors++;
1556 AWC_ENTRY_EXIT_DEBUG("exit\n");
1560 called from kernel->driver tx routine
1561 must decide where and how to post the packet
1562 must post the packet to wherever it decides
1563 either copy to card or enqueue to destination queue
1569 awc_802_11_tx_find_path_and_post(struct NET_DEVICE * dev,
1570 struct sk_buff * skb){
1573 struct awc_private * priv = (struct awc_private * )dev->priv;
1574 int i;
1575 int len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
1576 struct awc_fid * fid = NULL;
1577 // u16 saved_fid ;
1578 u16 p2p_direct =priv->p2p_found;
1579 // struct iphdr * ip_hdr;
1580 //buffer = skb->data;
1582 AWC_ENTRY_EXIT_DEBUG("awc_802_11_tx_find_path_and_post");
1584 DOWN(&priv->tx_buff_semaphore);
1585 if (len > dev->mtu + 16 ) {
1586 printk(KERN_ERR "%s packet size too large %d \n",dev->name, len);
1587 goto final;
1590 if (len + AWC_TX_HEAD_SIZE < AWC_TX_ALLOC_SMALL_SIZE )
1591 fid = awc_fid_queue_pop_head(&priv->tx_small_ready);
1593 if (!fid)
1594 fid = awc_fid_queue_pop_head(&priv->tx_large_ready);
1596 if (!fid) {
1597 DEBUG(32,"%s buffs in use \n",dev->name);
1598 goto no_space;
1601 if (fid->u.tx.fid_size < len + AWC_TX_HEAD_SIZE){
1602 awc_fid_queue_push_tail(&priv->tx_small_ready, fid);
1603 fid = awc_fid_queue_pop_head(&priv->tx_large_ready);
1606 if (!fid) {
1607 DEBUG(32,"%s buffs in use \n",dev->name);
1608 goto no_space;
1611 if (fid->u.tx.fid_size < len + AWC_TX_HEAD_SIZE - 14){
1612 printk(KERN_ERR "found too small tx fid size %d, pktlen %d \n",fid->u.tx.fid_size, len);
1614 memset(&fid->u.tx.radio_tx, 0,sizeof(struct aironet4500_radio_tx_header));
1615 memset(&fid->u.tx.ieee_802_11, 0,sizeof(struct ieee_802_11_header));
1616 memset(&fid->u.tx.ieee_802_3, 0,sizeof(struct ieee_802_3_header));
1617 fid->u.tx.payload =NULL;
1618 fid->u.tx.gap_length =0;
1619 fid->busy = 1;
1622 priv->tx_buffs_in_use++;
1623 DEBUG(32,"found large buff %x \n",fid->u.tx.fid);
1626 fid->type |= p80211_llc_snap;
1627 fid->snap.dsap = 0xaa;
1628 fid->snap.ssap = 0xaa;
1629 fid->snap.ctrl = 0x03;
1630 fid->snap.oui[0] = 0x0;
1631 fid->snap.oui[1] = 0x0;
1632 fid->snap.oui[2] = 0x0;
1634 fid->skb = skb;
1637 if (priv->p2p_uc && !priv->p2p_found){ // we go without encapsulation to neighbour;
1639 for (i=0; i < 6; i++)
1640 if (priv->p2p[i] != skb->data[i]){
1641 p2p_direct = 1;
1642 break;
1646 if (tx_rate == 2 || tx_rate == 4 || tx_rate== 20 || tx_rate == 22)
1647 fid->u.tx.radio_tx.tx_bit_rate = tx_rate;
1648 fid->u.tx.radio_tx.TX_Control =
1649 aironet4500_tx_control_tx_ok_event_enable |
1650 aironet4500_tx_control_tx_fail_event_enable |
1651 aironet4500_tx_control_no_release;
1653 /* if (len < 100){
1654 fid->u.tx.radio_tx.TX_Control |=
1655 aironet4500_tx_control_use_rts;
1658 /* ip_hdr = skb->data + 14;
1659 if (ip_hdr && skb->data[12] == 0x80 ){
1660 if (ip_hdr->tos & IPTOS_RELIABILITY)
1661 fid->u.tx.radio_tx.TX_Control |=
1662 aironet4500_tx_control_use_rts;
1663 if (ip_hdr->tos & IPTOS_THROUGHPUT)
1664 fid->u.tx.radio_tx.TX_Control |=
1665 aironet4500_tx_control_no_retries;
1668 if (priv->p802_11_send || memcmp(dev->dev_addr, skb->data +6, 6) ){
1669 fid->u.tx.radio_tx.TX_Control |=
1670 aironet4500_tx_control_header_type_802_11;
1671 DEBUG(0x200,"%s bridging, forcing 802_11 send \n ",dev->name);
1675 if (!priv->p2p_uc || p2p_direct) {
1676 if ((fid->u.tx.radio_tx.TX_Control &
1677 aironet4500_tx_control_header_type_802_11 )){
1679 // including 802.3 header into 802.11 packet
1680 fid->u.tx.radio_tx.PayloadLength = len -12;
1681 fid->u.tx.ieee_802_3.payload_length = len -12 ;
1682 fid->pkt_len = len -12;
1683 fid->u.tx.payload = skb->data +12;
1685 if (!memcmp(dev->dev_addr, skb->data +6, 6)){
1686 memcpy(fid->u.tx.ieee_802_11.mac1,skb->data,6);
1687 memcpy(fid->u.tx.ieee_802_11.mac2,skb->data +6,6);
1688 memcpy(fid->u.tx.ieee_802_11.mac3,priv->status.CurrentBssid ,6);
1689 memset(fid->u.tx.ieee_802_11.mac4,0,6);
1690 fid->u.tx.ieee_802_11.frame_control = 0x8;
1691 fid->u.tx.ieee_802_11.gapLen=6;
1692 } else {
1694 memcpy(fid->u.tx.ieee_802_11.mac1,skb->data,6);
1695 memcpy(fid->u.tx.ieee_802_11.mac2,dev->dev_addr,6);
1696 memcpy(fid->u.tx.ieee_802_11.mac3,skb->data +6 ,6);
1697 memset(fid->u.tx.ieee_802_11.mac4,0 ,6);
1698 fid->u.tx.ieee_802_11.frame_control = 0x108;
1699 fid->u.tx.ieee_802_11.gapLen=6;
1702 } else { // plain old 802.3, with hdr copied
1703 fid->u.tx.radio_tx.PayloadLength = len -12;
1704 fid->u.tx.ieee_802_3.payload_length = len -12;
1705 fid->pkt_len = len - 12;
1706 fid->u.tx.payload = skb->data +12;
1708 memcpy(fid->u.tx.ieee_802_3.dst_mac,skb->data, 12);
1709 DEBUG(0x200,"%s tx simply 802.3 type \n ",dev->name);
1711 } else {// 802.1H bridgeing
1712 fid->type |= p80211_8021H;
1713 fid->bridge_size = len + sizeof(fid->bridge) ;
1714 fid->bridge.dsap = 0xaa;
1715 fid->bridge.ssap = 0xaa;
1716 fid->bridge.ctrl = 0x03;
1717 fid->bridge.oui[0] = 0x0;
1718 fid->bridge.oui[1] = 0x40;
1719 fid->bridge.oui[2] = 0x96;
1720 fid->bridge.unknown1= 0x0000;
1721 fid->bridge.unknown2= htons((len) & 0x1000);
1722 fid->u.tx.radio_tx.PayloadLength = fid->bridge_size + 2;
1723 fid->u.tx.ieee_802_3.payload_length = fid->u.tx.radio_tx.PayloadLength ;
1726 fid->u.tx.payload = skb->data +12;
1727 if ((fid->u.tx.radio_tx.TX_Control &
1728 aironet4500_tx_control_header_type_802_11 )){
1730 memcpy(fid->u.tx.ieee_802_11.mac1,priv->p2p,6);
1731 memcpy(fid->u.tx.ieee_802_11.mac2,skb->data +6,6);
1732 memcpy(fid->u.tx.ieee_802_11.mac3,priv->bssid ,6);
1733 memset(fid->u.tx.ieee_802_11.mac4,0,6);
1734 fid->u.tx.ieee_802_11.gapLen=6;
1736 fid->u.tx.ieee_802_11.frame_control = 0x8;
1738 memcpy(fid->u.tx.ieee_802_3.dst_mac,priv->p2p, 6);
1739 memcpy(fid->u.tx.ieee_802_3.src_mac,dev->dev_addr, 6);
1740 fid->u.tx.payload = skb->data + 2 + sizeof(fid->bridge);
1741 fid->pkt_len = len ;
1743 DEBUG(0x200,"%s tx simply 802.1H type \n ",dev->name);
1749 awc_fid_queue_push_tail(&priv->tx_in_transmit,fid);
1750 udelay(1);
1751 awc_transmit_packet(dev,fid);
1752 UP(&priv->tx_buff_semaphore);
1753 if (priv->tx_large_ready.size > 0 ){
1754 dev->tbusy = 0;
1755 mark_bh(NET_BH);
1757 AWC_ENTRY_EXIT_DEBUG("exit\n");
1758 return 0;
1761 no_space:
1762 DEBUG(32,"%s tx buffs not found \n ",dev->name);
1763 #ifdef AWC_DEBUG
1764 // printk("s");
1765 #endif
1766 dev->tbusy = 1; //weell, here it must be set anyway and before
1767 //priv->stats.tx_fifo_errors++;
1768 UP(&priv->tx_buff_semaphore);
1769 AWC_ENTRY_EXIT_DEBUG("NoSpaceExit\n");
1770 return 1 ;
1771 final:
1772 priv->stats.tx_errors++;
1773 UP(&priv->tx_buff_semaphore);
1774 dev->tbusy = 0;
1775 FREE_SKB(skb);
1776 mark_bh(NET_BH);
1777 AWC_ENTRY_EXIT_DEBUG("BADExit\n");
1778 return -1;
1783 called from low level driver->card tx copy routine
1784 probably wants to free skbuf if failed transmits won't be
1785 resubmitted to another device (if more than one path)
1786 or tried again (if tx buffer in card needs to be filled again)
1790 void
1791 awc_802_11_after_tx_packet_to_card_write(struct NET_DEVICE * dev,
1792 struct awc_fid * tx_buff){
1795 AWC_ENTRY_EXIT_DEBUG("awc_802_11_after_tx_packet_to_card_write");
1797 if (!tx_buff){
1798 DEBUG(1,"%s no damn tx_buff in awc_802_11_after_tx_packet_to_card_write \n",dev->name);
1801 if(tx_buff->skb){
1802 FREE_SKB(tx_buff->skb);
1803 tx_buff->skb = NULL;
1805 mark_bh(NET_BH);
1807 AWC_ENTRY_EXIT_DEBUG("exit\n");
1811 called from low level driver->card tx copy routine
1812 probably wants to free skbuf if failed writes won't be
1813 resubmitted to another device (if more than one path)
1814 or tried again (if tx buffer in card needs to be filled again)
1817 void
1818 awc_802_11_after_failed_tx_packet_to_card_write(struct NET_DEVICE * dev,
1819 struct awc_fid * tx_buff){
1820 struct awc_private * priv = (struct awc_private *)dev->priv;
1823 AWC_ENTRY_EXIT_DEBUG("awc_802_11_after_failed_tx_packet_to_card_write");
1825 if (!tx_buff){
1826 DEBUG(1,"%s no damn tx_buff in awc_802_11_after_failed_tx_packet_to_card_write \n",dev->name);
1829 if(tx_buff->skb){
1830 FREE_SKB(tx_buff->skb);
1831 tx_buff->skb = NULL;
1832 tx_buff->busy =0;
1833 printk(KERN_ERR "%s packet to card write failed \n",dev->name);
1836 awc_fid_queue_remove(&priv->tx_in_transmit,tx_buff);
1838 if (tx_buff->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE)
1839 awc_fid_queue_push_tail(&priv->tx_small_ready,tx_buff);
1840 else
1841 awc_fid_queue_push_tail(&priv->tx_large_ready,tx_buff);
1843 AWC_ENTRY_EXIT_DEBUG("exit\n");
1847 void
1848 awc_802_11_after_tx_complete(struct NET_DEVICE * dev, struct awc_fid * tx_buff){
1850 struct awc_private * priv = (struct awc_private *)dev->priv;
1852 AWC_ENTRY_EXIT_DEBUG("awc_802_11_after_tx_complete");
1854 DEBUG(32,"tx complete status %x \n ",tx_buff->u.tx.radio_tx.Status);
1856 #ifdef AWC_DEBUG
1857 if (tx_buff->u.tx.radio_tx.Status)
1858 printk("tf%x ",tx_buff->u.tx.radio_tx.Status);
1859 #endif
1860 if (tx_buff->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE){
1861 awc_fid_queue_push_tail(&priv->tx_small_ready,tx_buff);
1862 priv->tx_small_buffs_in_use--;
1863 } else {
1864 awc_fid_queue_push_tail(&priv->tx_large_ready,tx_buff);
1865 priv->tx_buffs_in_use--;
1868 tx_buff->busy = 0;
1869 dev->tbusy = 0;
1870 mark_bh(NET_BH);
1872 AWC_ENTRY_EXIT_DEBUG("exit\n");
1878 /******************************** R X ***********************/
1882 inline int
1883 awc_receive_packet(struct NET_DEVICE * dev){
1885 struct awc_command cmd;
1886 u16 Fid;
1887 // struct sk_buff *skb = NULL;
1888 struct awc_fid * rx_buff;
1891 struct awc_private * priv ;
1892 int i;
1894 priv= (struct awc_private *)dev->priv;
1895 rx_buff = priv->rx_ready.head ;
1897 AWC_ENTRY_EXIT_DEBUG(" entry awc_receive_packet ");
1899 Fid = awc_Rx_Fid(dev->base_addr);
1901 DEBUG(128," RX FID %x \n",Fid);
1903 if (!Fid){
1904 printk(KERN_CRIT "No RxFid when rx event \n");
1905 return -1;
1910 if (!rx_buff){
1911 printk(KERN_CRIT "No rx_buff in rx event \n");
1912 return -1;
1915 rx_buff->type = 0;
1918 AWC_INIT_COMMAND(AWC_CLI,cmd,dev,0,0,
1919 Fid, 0, 0x14 , &(rx_buff->u.rx.radio_rx));
1922 // header reading , order is important
1923 AWC_BAP_LOCK_UNDER_CLI(cmd);
1925 if (awc_bap_setup(&cmd)) goto final;
1926 if (awc_bap_read(&cmd)) goto final;
1928 DEBUG(128, "rx receive radio header, length %x \n",rx_buff->u.rx.radio_rx.PayloadLength);
1930 cmd.buff = &(rx_buff->u.rx.ieee_802_11);
1931 cmd.len = 0x20;
1933 if (awc_bap_read(&cmd)) goto final;
1935 DEBUG(128, "rx receive 802_11 header, framecontrol %x \n",rx_buff->u.rx.ieee_802_11.frame_control);
1937 if (rx_buff->u.rx.ieee_802_11.gapLen > 8) {
1938 printk(KERN_ERR "%s: 802.11 gap lenght huge %d \n",dev->name,rx_buff->u.rx.ieee_802_11.gapLen);
1939 goto final;
1941 DEBUG(128,"SeqCtl %x, 802_11 macs: ",rx_buff->u.rx.ieee_802_11.SeqCtl);
1942 if (awc_debug & 0x7000){
1943 DEBUG(0x7000, " %s mac1 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac1[i] )) ;
1944 DEBUG(0x7000, " %s mac2 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac2[i] )) ;
1945 DEBUG(0x7000, " %s mac3 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac3[i] )) ;
1946 DEBUG(0x7000, " %s mac4 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac4[i] )) ;
1948 DEBUG(128,"\n GapLen %d ",rx_buff->u.rx.ieee_802_11.gapLen );
1950 if (rx_buff->u.rx.ieee_802_11.gapLen > 0) {
1951 cmd.buff = rx_buff->u.rx.ieee_802_11.gap;
1952 cmd.len = rx_buff->u.rx.ieee_802_11.gapLen;
1953 if (awc_bap_read(&cmd)) goto final;
1954 DEBUG(128, "rx receive gap header , gap length %x \n",rx_buff->u.rx.gap_length);
1956 for (i = 0; i < rx_buff->u.rx.ieee_802_11.gapLen ; i++) DEBUG(128,"%x",((unsigned char)rx_buff->u.rx.ieee_802_11.gap[i] )) ;
1959 if ( !(priv->config.ReceiveMode & RXMODE_DISABLE_802_3_HEADER )
1961 cmd.buff = &(rx_buff->u.rx.ieee_802_3);
1962 cmd.len = 0x10;
1963 rx_buff->type |= p80211_8023;
1964 if (awc_bap_read(&cmd)) goto final;
1965 DEBUG(128, "rx receive 802_3 header, payload length %x \n",rx_buff->u.rx.ieee_802_3.payload_length);
1966 DEBUG(128,"\n 802_3 status %x ",rx_buff->u.rx.ieee_802_3.status );
1967 DEBUG(128," RX payloadLen %x, dst,src: ",rx_buff->u.rx.ieee_802_3.payload_length);
1968 if (awc_debug & 0x7000){
1969 for (i = 0; i < 6; i++) printk("%02x:",((unsigned char)rx_buff->u.rx.ieee_802_3.dst_mac[i] )) ;
1970 for (i = 0; i < 6; i++) printk("%02x:",((unsigned char)rx_buff->u.rx.ieee_802_3.src_mac[i] )) ;
1974 rx_buff->pkt_len = rx_buff->u.rx.radio_rx.PayloadLength;
1976 if (priv->config.OperatingMode & MODE_LLC_HOST)
1977 rx_buff->type |= p80211_llc_snap;
1980 if (awc_802_11_find_copy_path(dev,rx_buff)) goto final;
1983 if (rx_buff->u.rx.payload ){
1984 cmd.buff = rx_buff->u.rx.payload;
1985 cmd.len = rx_buff->pkt_len;
1986 if (awc_bap_read(&cmd)) goto final;
1987 DEBUG(128, "rx payload read %x \n",rx_buff->u.rx.ieee_802_3.payload_length);
1990 AWC_RELEASE_COMMAND(cmd);
1992 DEBUG(128,"\n payload hdr %x ",rx_buff->u.rx.ieee_802_3.status );
1993 if (awc_debug && rx_buff->u.rx.payload)
1994 for (i = 0; i < 20; i++) DEBUG(128,"%x",((unsigned char)rx_buff->u.rx.payload[i] )) ;
1995 DEBUG(128,"%c",'\n');
1997 awc_802_11_router_rx(dev,rx_buff);
1999 AWC_ENTRY_EXIT_DEBUG(" exit \n");
2000 return 0;
2001 final:
2003 awc_802_11_failed_rx_copy(dev,rx_buff);
2004 // if (skb) dev_kfree_skb(skb, FREE_WRITE);
2005 AWC_RELEASE_COMMAND(cmd);
2006 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
2007 return -1; ;
2013 awc_transmit_packet(struct NET_DEVICE * dev, struct awc_fid * tx_buff) {
2015 struct awc_command cmd;
2016 u16 size ;
2017 // unsigned long flags;
2018 int i;
2019 struct awc_private * priv= (struct awc_private *)dev->priv;
2021 AWC_ENTRY_EXIT_DEBUG(" entry awc_transmit_packet ");
2023 if (priv->link_status_changed ){
2024 priv->link_status_changed =0;
2025 awc_readrid_dir(dev,&priv->rid_dir[7]);
2029 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0xB, tx_buff->u.tx.fid,
2030 tx_buff->u.tx.fid, 0, 0x14 , &(tx_buff->u.tx.radio_tx));
2032 AWC_BAP_LOCK_NOT_CLI(cmd);
2034 #ifdef AWC_BY_BOOK
2035 #warning By books is bad, AWC_BY_BOOK
2036 #error cli sti bad here
2037 if ( !(tx_buff->type &(p80211_llc_snap|p80211_8021H) )
2038 && !(tx_buff->u.tx.radio_tx.TX_Control &
2039 aironet4500_tx_control_header_type_802_11 )){
2041 cmd.buff=&(tx_buff->u.tx.radio_tx.TX_Control);
2042 cmd.len = 0x2 ;
2043 cmd.offset = 0x8;
2044 save_flags(flags);
2045 cli();
2046 if (awc_bap_setup(&cmd)) goto final;
2047 if (awc_bap_write(&cmd)) goto final;
2049 cmd.buff=&(tx_buff->u.tx.ieee_802_3.payload_length);
2050 cmd.len = 14;
2051 cmd.offset = 0x36;
2052 if (awc_bap_setup(&cmd)) goto final;
2053 if (awc_bap_write(&cmd)) goto final;
2054 restore_flags(flags);
2056 } else {
2057 #endif
2059 if (awc_bap_setup(&cmd)) goto final;
2060 if (awc_bap_write(&cmd)) goto final;
2062 DEBUG(64," wrote radio tx header for fid %x \n",tx_buff->u.tx.fid);
2064 // 802.11
2065 cmd.buff=&(tx_buff->u.tx.ieee_802_11);
2066 cmd.len = 0x20;
2067 if (awc_bap_write(&cmd)) goto final;
2069 // Gap
2070 if (tx_buff->u.tx.ieee_802_11.gapLen) {
2071 cmd.buff=&(tx_buff->u.tx.ieee_802_11.gap);
2072 cmd.len = tx_buff->u.tx.ieee_802_11.gapLen;
2073 if (awc_bap_write(&cmd)) goto final;
2075 // 802.3
2076 if ( ! (tx_buff->u.tx.radio_tx.TX_Control &
2077 aironet4500_tx_control_header_type_802_11 )){
2079 cmd.buff=&(tx_buff->u.tx.ieee_802_3);
2080 if (awc_debug & 0x7000){
2081 printk("%s TX dst ",dev->name);
2082 for (i=0; i < 6; i++) printk ("%02x:",(unsigned char) tx_buff->u.tx.ieee_802_3.dst_mac[i]);
2083 printk(" src ");
2084 for (i=0; i < 6; i++) printk ("%02x:",(unsigned char) tx_buff->u.tx.ieee_802_3.src_mac[i]);
2085 printk(" \n ");
2087 cmd.len = 0x10;
2088 if (awc_bap_write(&cmd)) goto final;
2091 if (tx_buff->type & p80211_llc_snap) {
2092 cmd.buff= & tx_buff->snap;
2093 cmd.len = sizeof(tx_buff->snap);
2094 if (awc_bap_write(&cmd)) goto final;
2097 if (tx_buff->type & p80211_8021H) {
2098 size = htons(tx_buff->bridge_size);
2099 // size = tx_buff->bridge_size;// to seasure raw speed of f** UC
2100 cmd.buff= & size;
2101 cmd.len = 2 ;
2102 if (awc_bap_write(&cmd)) goto final;
2104 cmd.buff= & tx_buff->bridge;
2105 cmd.len = sizeof(tx_buff->bridge);
2106 if (awc_bap_write(&cmd)) goto final;
2109 #ifdef AWC_BY_BOOK
2112 #endif
2113 cmd.buff= tx_buff->u.tx.payload;
2114 cmd.len = tx_buff->pkt_len;
2116 if (awc_bap_write(&cmd)) goto final;
2117 AWC_RELEASE_COMMAND(cmd);
2118 // locking probs, these two lines below and above, swithc order
2119 if (awc_issue_command_and_block(&cmd)) goto final_unlocked;
2122 tx_buff->transmit_start_time = jiffies;
2123 awc_802_11_after_tx_packet_to_card_write(dev,tx_buff);
2124 // issue the transmit command
2127 AWC_ENTRY_EXIT_DEBUG(" exit \n");
2128 return 0;
2129 final:
2130 awc_802_11_after_failed_tx_packet_to_card_write(dev,tx_buff);
2131 printk(KERN_CRIT "%s awc tx command failed \n",dev->name);
2132 AWC_RELEASE_COMMAND(cmd);
2133 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
2134 return -1; ;
2136 final_unlocked:
2137 awc_802_11_after_failed_tx_packet_to_card_write(dev,tx_buff);
2138 printk(KERN_CRIT "%s awc tx command failed \n",dev->name);
2139 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
2140 return -1; ;
2145 inline int
2146 awc_tx_complete_check(struct NET_DEVICE * dev){
2148 struct awc_fid * fid;
2149 struct awc_command cmd;
2152 AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_complete_check ");
2156 fid = awc_fid_queue_pop_head(&((struct awc_private *)dev->priv)->tx_post_process);
2158 if (!fid) {
2159 printk("awc_tx_complete_check with empty queue \n ");
2160 return -1;
2163 DEBUG(64," tx_complete fid %x \n",fid->u.tx.fid);
2165 AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0,0, fid->u.tx.fid,
2166 0, 0x14 , &(fid->u.tx.radio_tx));
2168 fid->state |= awc_tx_fid_complete_read;
2170 AWC_BAP_LOCK_NOT_CLI(cmd);
2171 if (awc_bap_setup(&cmd)) goto final;
2172 if (awc_bap_read(&cmd)) goto final;
2173 AWC_RELEASE_COMMAND(cmd);
2175 awc_802_11_after_tx_complete(dev,fid);
2178 AWC_ENTRY_EXIT_DEBUG(" exit \n");
2179 return 0;
2181 final:
2182 awc_802_11_after_tx_complete(dev,fid);
2183 printk(KERN_ERR "%s awc_tx_complete_check failed \n",dev->name);
2184 AWC_RELEASE_COMMAND(cmd);
2185 AWC_ENTRY_EXIT_DEBUG(" BAD exit \n");
2186 return -1; ;
2190 #define AWC_QUEUE_BH {\
2191 if (!priv->bh_active && !priv->bh_running){\
2192 priv->bh_active = 1;\
2193 queue_task(&priv->immediate_bh, &tq_immediate);\
2194 mark_bh(IMMEDIATE_BH);\
2199 void
2200 awc_bh(struct NET_DEVICE *dev){
2202 struct awc_private * priv = (struct awc_private *)dev->priv;
2203 int active_interrupts;
2204 int enabled_interrupts;
2205 // u16 tx_status;
2206 int multi_ints = 0;
2207 // u16 tx_fid = 0;
2208 // unsigned long flags;
2210 DEBUG(8, "awc_bh awoken on jiffie %ld \n",jiffies);
2212 priv->bh_running = 1;
2214 active_interrupts = awc_event_status(dev->base_addr);
2216 enabled_interrupts = awc_ints_enabled(dev->base_addr);
2218 DEBUG(8, "awc_bh active ints %x \n",active_interrupts);
2220 if (test_and_set_bit( 0, (void *) &priv->tx_chain_active) ) {
2221 // printk(KERN_ERR "tx chain active in bh \n");
2222 // queue_task(&priv->immediate_bh, &tq_immediate);
2223 goto bad_end;
2225 start:
2226 if (active_interrupts == 0xffff){
2228 printk(KERN_CRIT "%s device ejected in interrupt, disabling\n",dev->name);
2229 dev->tbusy = 1;
2230 dev->start = 0;
2231 if (priv->command_semaphore_on){
2232 priv->command_semaphore_on--;
2233 AWC_UNLOCK_COMMAND_ISSUING(priv);
2235 priv->tx_chain_active =0;
2236 goto bad_end;
2240 if (priv->unlock_command_postponed ){
2242 priv->unlock_command_postponed-- ;
2243 if( priv->command_semaphore_on ){
2245 awc_read_response((&priv->cmd));
2246 priv->async_command_start = 0;
2247 if (priv->command_semaphore_on){
2249 priv->command_semaphore_on--;
2250 AWC_UNLOCK_COMMAND_ISSUING(priv);
2255 /* if ( active_interrupts & 0x1 ){
2256 awc_receive_packet(dev) ;
2257 awc_event_ack_Rx(dev->base_addr);
2258 priv->waiting_interrupts &= ~0x1;
2261 while (priv->tx_post_process.size)
2262 if (awc_tx_complete_check(dev)) break;
2264 active_interrupts = awc_event_status(dev->base_addr);
2266 if (priv->command_semaphore_on || priv->tx_post_process.size){
2267 if (multi_ints++ < 10000){
2268 goto start;
2271 priv->bh_active = 0;
2272 priv->bh_running = 0;
2274 priv->tx_chain_active = 0;
2278 bad_end:
2279 // if (!priv->tx_chain_active)
2280 // wake_up(&priv->tx_chain_wait_queue);
2282 priv->bh_running = 0;
2283 priv->bh_active = 0;
2284 return ;
2288 inline int
2289 awc_interrupt_process(struct NET_DEVICE * dev){
2291 struct awc_private * priv ;
2292 int active_interrupts;
2293 int enabled_interrupts;
2294 u16 tx_status;
2295 int multi_ints = 0;
2296 u16 tx_fid = 0;
2297 // u16 ints_to_ack =0;
2298 struct awc_fid * fid = NULL;
2299 // int interrupt_reenter = 0;
2300 // unsigned long flags;
2302 // save_flags(flags);
2303 // cli();
2304 // disable_irq(dev->irq);
2306 DEBUG(2," entering interrupt handler %s ",dev->name);
2308 if (!dev) {
2309 printk(KERN_ERR "No dev in interrupt \n");
2310 goto bad_end;
2313 priv = (struct awc_private *)dev->priv;
2315 if (!priv) {
2316 printk(KERN_ERR "No PRIV in interrupt \n");
2317 goto bad_end;
2321 enabled_interrupts = awc_ints_enabled(dev->base_addr);
2322 active_interrupts = awc_event_status(dev->base_addr);
2324 DEBUG(2,"entry: processing interrupts waiting %x \n",priv->waiting_interrupts);
2325 DEBUG(2,"entry: processing interrupts active %x \n",active_interrupts);
2326 DEBUG(2,"entry: processing interrupts enabled %x \n",enabled_interrupts);
2327 // printk("ikka interruptis\n");
2330 if (test_and_set_bit( 0, (void *) &dev->interrupt) ) {
2331 printk("RI\n");
2332 goto reenter_end_here;
2334 priv->interrupt_count++;
2335 if (priv->interrupt_count > 1 )
2336 printk(" interrupt count on\n ");
2340 if (priv->waiting_interrupts & active_interrupts)
2341 printk(KERN_ERR "double interrupt waiting %x active %x \n",
2342 priv->waiting_interrupts, active_interrupts);
2344 // priv->waiting_interrupts |= active_interrupts;
2350 start:
2351 DEBUG(2,"Start processing int, times %d\n",multi_ints);
2353 if (active_interrupts == 0xffff){
2355 printk(KERN_CRIT "%s device ejected, got interrupt, disabling\n",dev->name);
2356 //priv->
2357 dev->tbusy = 1;
2358 dev->start = 0;
2359 priv->ejected = 1;
2360 if (priv->bh_active || priv->bh_running){
2361 priv->interrupt_count--;
2362 dev->interrupt = 0;
2363 goto bad_end;
2364 } else if (priv->command_semaphore_on){
2366 printk(KERN_ERR "ejected, last BH fired \n");
2368 AWC_QUEUE_BH;
2370 priv->interrupt_count--;
2371 dev->interrupt = 0;
2372 goto bad_end;
2377 if (active_interrupts & 0x100 ){
2378 awc_event_ack_Awaken(dev->base_addr);
2379 udelay(10);
2380 DEBUG(1,"%s device awoke \n",dev->name);
2381 priv->waiting_interrupts &= ~0x100;
2383 if (active_interrupts & 0x80 ){
2385 priv->link_status = awc_Link_Status(dev->base_addr);
2386 DEBUG(1,"link status changed %x \n",priv->link_status);
2387 awc_event_ack_Link(dev->base_addr);
2388 priv->waiting_interrupts &= ~0x80;
2389 if(priv->link_status == 0x400)
2390 printk(KERN_INFO "%s Associated\n",dev->name );
2391 else {
2392 printk(KERN_INFO "%s Link status change : %s \n",dev->name, awc_print_string(awc_link_status_names, priv->link_status) );
2393 if ( priv->link_status & 0x8100 ||
2394 priv->link_status & 0x0100 ||
2395 priv->link_status & 0x8200 ||
2396 priv->link_status & 0x8400 ||
2397 priv->link_status & 0x0300 )
2398 printk(KERN_INFO "%s Link status change reason : %s \n",dev->name, awc_print_string(awc_link_failure_reason_names, priv->link_status & 0xff) );
2404 if (active_interrupts & 0x10 & enabled_interrupts ){
2406 // printk(KERN_ERR "cmd int shouldnt be active in interrupt routine\n");
2408 awc_event_ack_Cmd(priv->cmd.port);
2410 if ( priv->enabled_interrupts & 0x10)
2411 priv->enabled_interrupts &= ~0x10;
2413 enabled_interrupts = awc_ints_enabled(dev->base_addr);
2415 if (enabled_interrupts & 0x10){
2416 awc_ints_enable(dev->base_addr, enabled_interrupts & ~0x10);
2419 if (priv->command_semaphore_on){
2420 priv->unlock_command_postponed++;
2422 AWC_QUEUE_BH;
2426 if ((active_interrupts & 0x10) && !(0x10 & enabled_interrupts) ){
2428 // printk(KERN_ERR "%s: aironet4500: cmd int shouldnt be active in interrupt routine\n",dev->name);
2430 //awc_event_ack_Cmd(priv->cmd.port);
2434 // active_interrupts = awc_event_status(dev->base_addr);
2436 tx_status = active_interrupts & 0x6 ;
2440 if (tx_status) {
2442 tx_fid = awc_Tx_Compl_Fid(dev->base_addr);
2443 if (!tx_fid){
2444 udelay(10);
2445 tx_fid = awc_Tx_Compl_Fid(dev->base_addr);
2447 if (!tx_fid)
2448 printk(KERN_ERR "No tx fid when tx int active\n");
2450 fid = awc_tx_fid_lookup_and_remove(dev, tx_fid);
2452 if (fid) {
2453 if (priv->process_tx_results) {
2454 awc_fid_queue_push_tail(&priv->tx_post_process,fid);
2455 AWC_QUEUE_BH;
2456 }else {
2457 if (fid->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE)
2458 awc_fid_queue_push_tail(&priv->tx_small_ready,fid);
2459 else
2460 awc_fid_queue_push_tail(&priv->tx_large_ready,fid);
2461 dev->tbusy = 0;
2462 mark_bh(NET_BH);
2464 } else
2465 printk(KERN_ERR "awc fid %x not found\n",tx_fid);
2468 if (tx_status & 2){
2469 awc_event_ack_Tx(dev->base_addr);
2470 priv->stats.tx_packets++;
2471 priv->waiting_interrupts &= ~0x2;
2473 if (tx_status & 4){
2474 priv->stats.tx_errors++;
2475 awc_event_ack_TxExc(dev->base_addr);
2476 priv->waiting_interrupts &= ~0x4;
2478 if ((tx_status&6) == 6)
2479 printk(KERN_NOTICE "%s: both tx and txExc up\n",dev->name);
2484 // active_interrupts = awc_event_status(dev->base_addr);
2486 if ( active_interrupts & 0x1 ){
2487 awc_receive_packet(dev);
2488 awc_event_ack_Rx(dev->base_addr);
2489 priv->waiting_interrupts &= ~0x1;
2492 active_interrupts = awc_event_status(dev->base_addr);
2494 if ((active_interrupts & 0x7) &&
2495 !priv->bh_active &&
2496 !priv->bh_running ){
2497 if (multi_ints++ < 5)
2498 goto start;
2500 if (multi_ints >=5 )
2501 printk(KERN_ERR "%s multi_ints > 5 interrupts still active %x\n",dev->name,active_interrupts);
2504 priv->interrupt_count--;
2505 dev->interrupt = 0;
2507 awc_ints_enable(dev->base_addr, 0x0000);
2510 DEBUG(0x8, " enabling ints in interrupt_process %x \n",
2511 priv->enabled_interrupts & ~priv->waiting_interrupts);
2515 AWC_ENTRY_EXIT_DEBUG(" exit \n");
2517 awc_ints_enable(dev->base_addr,
2518 priv->enabled_interrupts);
2520 //end_here:
2522 // enable_irq(dev->irq);
2523 // restore_flags(flags);
2525 return 0;
2526 reenter_end_here:
2528 AWC_ENTRY_EXIT_DEBUG(" reenter-bad end exit \n");
2529 // enable_irq(dev->irq);
2530 // restore_flags(flags);
2531 return 0;
2533 bad_end:
2534 dev->interrupt = 0;
2535 AWC_ENTRY_EXIT_DEBUG(" bad_end exit \n");
2536 // enable_irq(dev->irq);
2537 // restore_flags(flags);
2538 return -1;
2543 static const char *aironet4500_core_version =
2544 "aironet4500.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n";
2546 struct NET_DEVICE * aironet4500_devices[MAX_AWCS] = {NULL,NULL,NULL,NULL};
2548 static int awc_debug = 0; // 0xffffff;
2549 static int p802_11_send = 0; // 1
2551 static int awc_process_tx_results = 0;
2552 int tx_queue_len = 10;
2553 int tx_rate = 0;
2554 static int channel = 5;
2555 //static int tx_full_rate = 0;
2556 static int max_mtu = 2312;
2557 static int adhoc = 0;
2558 static int large_buff_mem = 1700 * 10;
2559 static int small_buff_no = 20;
2560 static int awc_full_stats = 0;
2561 static char SSID[33] = {0};
2562 static int master= 0;
2563 static int slave = 0;
2564 // int debug =0;
2566 #if LINUX_VERSION_CODE >= 0x20100
2568 MODULE_PARM(awc_debug,"i");
2569 MODULE_PARM(rx_queue_len,"i");
2570 MODULE_PARM(tx_rate,"i");
2571 MODULE_PARM(channel,"i");
2572 MODULE_PARM(tx_full_rate,"i");
2573 MODULE_PARM(adhoc,"i");
2574 MODULE_PARM(master,"i");
2575 MODULE_PARM(slave,"i");
2576 MODULE_PARM(max_mtu,"i");
2577 MODULE_PARM(large_buff_mem,"i");
2578 MODULE_PARM(small_buff_no,"i");
2579 MODULE_PARM(SSID,"1-4c31");
2580 #endif
2582 /*EXPORT_SYMBOL(tx_queue_len);
2583 EXPORT_SYMBOL(awc_debug);
2585 EXPORT_SYMBOL(awc_init);
2586 EXPORT_SYMBOL(awc_open);
2587 EXPORT_SYMBOL(awc_close);
2588 EXPORT_SYMBOL(awc_reset);
2589 EXPORT_SYMBOL(awc_config);
2591 EXPORT_SYMBOL(aironet4500_devices);
2592 EXPORT_SYMBOL(awc_debug);
2593 //EXPORT_SYMBOL();
2595 EXPORT_SYMBOL(awc_private_init);
2596 EXPORT_SYMBOL(awc_tx_timeout);
2597 EXPORT_SYMBOL(awc_start_xmit);
2598 EXPORT_SYMBOL(awc_tx_done);
2599 EXPORT_SYMBOL(awc_rx);
2600 EXPORT_SYMBOL(awc_interrupt);
2601 EXPORT_SYMBOL(awc_get_stats);
2602 EXPORT_SYMBOL(awc_change_mtu);
2603 EXPORT_SYMBOL(awc_set_multicast_list);
2605 EXPORT_SYMBOL(awc_proc_set_fun);
2606 EXPORT_SYMBOL(awc_proc_unset_fun);
2607 EXPORT_SYMBOL(awc_register_proc);
2608 EXPORT_SYMBOL(awc_unregister_proc);
2611 /*************************** RESET INIT CONFIG ***********************/
2614 void awc_reset(struct NET_DEVICE *dev)
2617 long long jiff;
2619 DEBUG(2, " awc_reset dev %x \n", (int)dev);
2620 DEBUG(2, "%s: awc_reset \n", dev->name);
2622 awc_issue_soft_reset(dev);
2624 jiff = jiffies;
2625 udelay(1000);
2626 while (awc_command_read(dev->base_addr)){
2627 udelay(1000);
2628 if (jiffies - jiff > 5*HZ){
2629 printk(KERN_CRIT "%s bad reset\n",dev->name);
2630 break;
2636 int awc_config(struct NET_DEVICE *dev)
2638 // struct awc_private *priv = (struct awc_private *)dev->priv;
2640 DEBUG(2, "%s: awc_config \n", dev->name);
2643 if( awc_disable_MAC(dev)) goto final;
2644 udelay(100);
2645 if( awc_write_all_rids(dev) ) goto final;
2646 udelay(100);
2647 if( awc_enable_MAC(dev)) goto final;
2649 return 0;
2650 final:
2651 return -1;
2655 char name[] = "ElmerLinux";
2657 int awc_init(struct NET_DEVICE *dev){
2658 struct awc_private *priv = (struct awc_private *)dev->priv;
2659 int i;
2660 const char * radioType;
2662 DEBUG(2, "%s: awc_init \n", dev->name);
2664 /* both_bap_lock decreases performance about 15%
2665 * but without it card gets screwed up
2667 #ifdef CONFIG_SMP
2668 if(smp_num_cpus > 1){
2669 both_bap_lock = 1;
2670 bap_setup_spinlock = 1;
2672 #endif
2673 //awc_dump_registers(dev);
2675 if (adhoc & !max_mtu)
2676 max_mtu= 2250;
2677 else if (!max_mtu)
2678 max_mtu= 1500;
2680 priv->sleeping_bap = 1;
2683 priv->enabled_interrupts = awc_ints_enabled(dev->base_addr);
2685 if( awc_issue_noop(dev) ) goto final;
2687 awc_ints_enable(dev->base_addr,0);
2689 if( awc_disable_MAC(dev) ) goto final;
2692 // awc_rids_setup(dev);
2693 i=0;
2694 while ( i < AWC_NOF_RIDS){
2695 if (awc_rids_temp[i].selector)
2696 memcpy(&priv->rid_dir[i],&awc_rids_temp[i],sizeof(priv->rid_dir[0]) );
2697 else priv->rid_dir[i].selector = NULL;
2698 i++;
2701 // following MUST be consistent with awc_rids !!!
2702 priv->rid_dir[0].buff = &priv->config; // card RID mirrors
2703 priv->rid_dir[1].buff = &priv->SSIDs;
2704 priv->rid_dir[2].buff = &priv->fixed_APs;
2705 priv->rid_dir[3].buff = &priv->driver_name;
2706 priv->rid_dir[4].buff = &priv->enc_trans;
2707 priv->rid_dir[5].buff = &priv->general_config; //
2708 priv->rid_dir[6].buff = &priv->capabilities;
2709 priv->rid_dir[7].buff = &priv->status;
2710 priv->rid_dir[8].buff = &priv->AP;
2711 priv->rid_dir[9].buff = &priv->statistics;
2712 priv->rid_dir[10].buff = &priv->statistics_delta;
2713 priv->rid_dir[11].buff = &priv->statistics_delta_clear;
2714 priv->rid_dir[12].buff = &priv->wep_volatile;
2715 priv->rid_dir[13].buff = &priv->wep_nonvolatile;
2716 priv->rid_dir[14].buff = &priv->modulation;
2718 priv->rid_dir[15].buff = &priv->statistics16;
2719 priv->rid_dir[16].buff = &priv->statistics16_delta;
2720 priv->rid_dir[17].buff = &priv->statistics16_delta_clear;
2722 priv->rid_dir[0].bufflen = sizeof(priv->config); // card RID mirrors
2723 priv->rid_dir[1].bufflen = sizeof(priv->SSIDs);
2724 priv->rid_dir[2].bufflen = sizeof(priv->fixed_APs);
2725 priv->rid_dir[3].bufflen = sizeof(priv->driver_name);
2726 priv->rid_dir[4].bufflen = sizeof(priv->enc_trans);
2727 priv->rid_dir[5].bufflen = sizeof(priv->general_config); //
2728 priv->rid_dir[6].bufflen = sizeof(priv->capabilities);
2729 priv->rid_dir[7].bufflen = sizeof(priv->status);
2730 priv->rid_dir[8].bufflen = sizeof(priv->AP);
2731 priv->rid_dir[9].bufflen = sizeof(priv->statistics);
2732 priv->rid_dir[10].bufflen = sizeof(priv->statistics_delta);
2733 priv->rid_dir[11].bufflen = sizeof(priv->statistics_delta_clear);
2734 priv->rid_dir[12].bufflen = sizeof(priv->wep_volatile);
2735 priv->rid_dir[13].bufflen = sizeof(priv->wep_nonvolatile);
2736 priv->rid_dir[14].bufflen = sizeof(priv->modulation);
2738 priv->rid_dir[15].bufflen = sizeof(priv->statistics16);
2739 priv->rid_dir[16].bufflen = sizeof(priv->statistics16_delta);
2740 priv->rid_dir[17].bufflen = sizeof(priv->statistics16_delta_clear);
2743 if( awc_read_all_rids(dev) ) goto final;
2746 priv->config.OperatingMode = 0;// MODE_LLC_HOST;
2747 DEBUG(1,"ReceiveMode %x \n",priv->config.ReceiveMode);
2748 // priv->config.ReceiveMode = RXMODE_DISABLE_802_3_HEADER;
2750 if (!adhoc)
2751 priv->config.OperatingMode = MODE_STA_ESS;
2752 // priv->config.OperatingMode = MODE_AP;
2753 // priv->config.Rates[0] =0x82;
2754 // priv->config.Rates[1] =0x4;
2755 // priv->config.Rates[2] =tx_full_rate;
2756 // priv->config.Rates[3] =0;
2757 // priv->config.Rates[4] =0;
2758 // priv->config.Rates[5] =0;
2759 // priv->config.Rates[6] =0;
2760 // priv->config.Rates[7] =0;
2761 priv->config.Channel = channel;
2762 if (adhoc && master){
2763 priv->config.JoinNetTimeout = 0x1;//0 is facotry default
2764 } else if (adhoc && slave){
2765 priv->config.JoinNetTimeout = 0xffff;
2767 // priv->config.AuthenticationType = 1;
2768 priv->config.Stationary =1;
2769 // priv->config.ScanMode = 1;
2770 // priv->config.LinkLossDelay = 100;
2771 priv->config.FragmentThreshold = 1700;
2772 priv->config.RtsThreshold = 1700;
2773 memcpy(priv->config.NodeName, name, 10);
2775 DEBUG(1,"%s supported Rates \n",dev->name);
2776 for (i=0; i< 8; i++)
2777 DEBUG(1,"%x ",priv->capabilities.SupportedRates[i]);
2778 DEBUG(1,"%c",'\n');
2779 DEBUG(1,"%s default Rates \n",dev->name);
2780 for (i=0; i< 8; i++)
2781 DEBUG(1,"%x ",priv->config.Rates[i]);
2782 DEBUG(1,"%c",'\n');
2785 // here we go, bad aironet
2786 memset(&priv->SSIDs,0,sizeof(priv->SSIDs));
2788 my_spin_lock_init(&priv->queues_lock);
2790 priv->SSIDs.ridLen =0;
2791 if (!SSID) {
2792 priv->SSIDs.SSID[0].SSID[0] ='a';
2793 priv->SSIDs.SSID[0].SSID[1] ='b';
2794 priv->SSIDs.SSID[0].SSID[2] ='c';
2795 priv->SSIDs.SSID[0].lenght =3;
2796 } else {
2797 int sidlen = strlen(SSID);
2798 memcpy(priv->SSIDs.SSID[0].SSID,SSID,sidlen);
2799 priv->SSIDs.SSID[0].lenght = sidlen;
2802 priv->SSIDs.SSID[1].lenght =0;
2803 priv->SSIDs.SSID[1].SSID[0] =0;
2804 priv->SSIDs.SSID[1].SSID[1] =0;
2805 priv->SSIDs.SSID[2].lenght =0;
2806 priv->SSIDs.SSID[2].SSID[0] =0;
2807 priv->SSIDs.SSID[2].SSID[1] =0;
2810 // priv->enc_trans.rules[0].etherType= 0x0008;
2811 // priv->enc_trans.rules[0].Action = 1;
2813 memcpy( priv->config.StationMacAddress,
2814 priv->capabilities.FactoryAddress, 6 );
2816 memcpy(dev->dev_addr, priv->config.StationMacAddress, 6);
2818 DEBUG(2, "%s: awc_init success \n", dev->name);
2820 if (priv->capabilities.RadioType == 1) radioType = "802.11 Frequency Hoping";
2821 else if (priv->capabilities.RadioType == 2) radioType = "802.11 Direct Sequence";
2822 else if (priv->capabilities.RadioType == 4) radioType = "LM2000";
2823 else radioType = "Multiple Radio Types";
2825 printk("%s: %s %s found @ 0x%lx irq %d firmwareVersion %d \n",dev->name,
2826 priv->capabilities.ProductName,radioType,
2827 dev->base_addr,dev->irq,
2828 priv->capabilities.SoftwareVersion);
2830 return 0;
2831 final:
2832 printk(KERN_ERR "aironet init failed \n");
2833 return NODEV;
2837 int awc_private_init(struct NET_DEVICE * dev){
2838 struct awc_private * priv = (struct awc_private *) dev->priv;
2839 int i = 0;
2841 DEBUG(2, "%s: awc_private_init \n", dev->name);
2844 memset(priv, 0, sizeof(struct awc_private));
2846 my_spin_lock_init(&priv->queues_lock);
2848 priv->bap0.select = dev->base_addr + awc_Select0_register;
2849 priv->bap0.offset = dev->base_addr + awc_Offset0_register;
2850 priv->bap0.data = dev->base_addr + awc_Data0_register;
2851 priv->bap0.lock = 0;
2852 priv->bap0.status = 0;
2853 my_spin_lock_init(&priv->bap0.spinlock);
2854 init_MUTEX(&priv->bap0.sem);
2855 priv->bap1.select = dev->base_addr + awc_Select1_register;
2856 priv->bap1.offset = dev->base_addr + awc_Offset1_register;
2857 priv->bap1.data = dev->base_addr + awc_Data1_register;
2858 priv->bap1.lock = 0;
2859 priv->bap1.status = 0;
2860 my_spin_lock_init(&priv->bap1.spinlock);
2861 init_MUTEX(&priv->bap1.sem);
2862 priv->sleeping_bap = 1;
2864 //spinlock now init_MUTEX(&priv->command_semaphore);
2865 my_spin_lock_init(&priv->command_issuing_spinlock);
2866 my_spin_lock_init(&priv->both_bap_spinlock);
2867 my_spin_lock_init(&priv->bap_setup_spinlock);
2869 priv->command_semaphore_on = 0;
2870 priv->unlock_command_postponed = 0;
2871 priv->immediate_bh.next = NULL;
2872 priv->immediate_bh.sync = 0;
2873 priv->immediate_bh.routine = (void *)(void *)awc_bh;
2874 priv->immediate_bh.data = dev;
2875 priv->bh_running = 0;
2876 priv->bh_active = 0;
2877 priv->tx_chain_active = 0;
2878 priv->enabled_interrupts= 0x00;
2879 priv->waiting_interrupts= 0x00;
2882 init_MUTEX(&priv->tx_buff_semaphore);
2883 priv->tx_buffs_in_use = 0;
2884 priv->tx_small_buffs_in_use = 0;
2885 priv->mac_enabled =0;
2886 priv->link_status =0;
2887 priv->large_buff_mem = large_buff_mem;
2888 if (priv->large_buff_mem < max_mtu + AWC_TX_HEAD_SIZE + 10 )
2889 priv->large_buff_mem = max_mtu + AWC_TX_HEAD_SIZE + 10;
2890 priv->small_buff_no = small_buff_no;
2891 if (priv->small_buff_no < 1 )
2892 priv->small_buff_no = 1 ;
2894 priv->process_tx_results = awc_process_tx_results;
2896 //init_waitqueue(&priv->tx_chain_wait_queue);
2898 for (i=0; i< 6 ; i++ ) {
2899 priv->p2p[i] = 0xff;
2900 priv->bssid[i] =0;
2902 // priv->p2p_uc =1;
2903 priv->p2p_found =0;
2905 priv->p802_11_send =p802_11_send;
2908 priv->ejected =0;
2909 dev->interrupt =0;
2910 priv->interrupt_count =0;
2912 return 0;
2916 /**************************** OPEN CLOSE **********************/
2919 int awc_open(struct NET_DEVICE *dev)
2921 struct awc_private *priv = (struct awc_private *)dev->priv;
2925 DEBUG(2, "%s: awc_open \n", dev->name);
2927 dev->interrupt = 0; dev->tbusy = 1; dev->start = 0;
2930 if( awc_queues_init(dev) ) goto final;
2931 if( awc_config(dev) ) goto final;
2933 memcpy(dev->dev_addr, priv->config.StationMacAddress, 6);
2935 priv->enabled_interrupts = 0x87;
2936 awc_ints_enable(dev->base_addr,priv->enabled_interrupts);
2938 // priv->p8022_client = register_8022_client;
2939 // priv->snap_client = register_snap_client;
2940 DEBUG(2, "%s: opened \n", dev->name);
2942 priv->sleeping_bap = 0;
2945 MOD_INC_USE_COUNT;
2946 // kernel_thread(awc_thread,dev,0);
2948 dev->tbusy = 0; dev->start = 1;
2949 return 0; /* Always succeed */
2951 final:
2952 dev->tbusy = 0; dev->start = 0;
2953 printk(KERN_ERR "aironet open failed \n");
2954 return -1;
2958 int awc_close(struct NET_DEVICE *dev)
2960 struct awc_private * priv = (struct awc_private *) dev->priv;
2962 DEBUG(2, "%s: closing device.\n", dev->name);
2964 dev->start = 0;
2965 dev->tbusy=1;
2967 awc_disable_MAC(dev);
2968 awc_queues_destroy(dev);
2970 awc_reset(dev);
2972 udelay(10000);
2974 AWC_LOCK_COMMAND_ISSUING(priv);
2976 MOD_DEC_USE_COUNT;
2978 AWC_UNLOCK_COMMAND_ISSUING(priv);
2980 return 0;
2985 /****************************** TX RX STUFF ******************/
2989 void awc_tx_timeout(struct NET_DEVICE *dev)
2991 struct awc_private *priv = (struct awc_private *)dev->priv;
2993 DEBUG(2, "%s: awc_tx_timeout \n", dev->name);
2995 printk(KERN_NOTICE "%s: Transmit timed out , buffs %d %d, queues tx %d pp %d lrg %d sm %d \n ",
2996 dev->name,priv->tx_small_buffs_total ,priv->tx_buffs_total,
2997 priv->tx_in_transmit.size,priv->tx_post_process.size,
2998 priv->tx_large_ready.size,priv->tx_small_ready.size);
2999 priv->stats.tx_errors++;
3001 dev->trans_start = jiffies;
3002 dev->tbusy = 0;
3005 long long last_tx_q_hack = 0;
3006 int direction = 1;
3008 int awc_start_xmit(struct sk_buff *skb, struct NET_DEVICE *dev) {
3010 struct awc_private *priv = (struct awc_private *)dev->priv;
3011 int retval = 0;
3012 // unsigned long flags;
3013 struct awc_fid * fid = NULL;
3014 int cnt=0;
3016 DEBUG(2, "%s: awc_start_xmit \n", dev->name);
3019 if (!dev) {
3020 DEBUG(1, " xmit dev=NULL, jiffie %ld \n",jiffies);
3021 return -1;
3024 /* Transmitter timeout, serious problems. */
3025 if (test_and_set_bit( 0, (void *) &dev->tbusy) ) {
3026 if (jiffies - dev->trans_start > 3* HZ ){
3027 // save_flags(flags);
3028 // cli();
3029 fid = priv->tx_in_transmit.head;
3030 cnt = 0;
3031 while (fid){
3032 if (jiffies - fid->transmit_start_time > (HZ)){
3033 // printk(KERN_ERR "%s staled tx_buff found, age %uld jiffies\n",dev->name,
3034 // jiffies - fid->transmit_start_time );
3035 awc_fid_queue_remove(&priv->tx_in_transmit, fid);
3036 if (fid->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE)
3037 awc_fid_queue_push_tail(&priv->tx_small_ready,fid);
3038 else
3039 awc_fid_queue_push_tail(&priv->tx_large_ready,fid);
3040 dev->tbusy = 0;
3042 fid = fid->next;
3043 if (cnt++ > 200) {
3044 printk("bbb in awc_fid_queue\n");
3045 // restore_flags(flags);
3046 return -1;
3050 //restore_flags(flags);
3051 //debug =0x8;
3053 if (jiffies - dev->trans_start >= (5* HZ) ) {
3054 awc_tx_timeout(dev);
3056 return 1;
3059 if (!skb) {
3060 DEBUG(1, " xmit skb=NULL, jiffie %ld \n",jiffies);
3061 return -1;
3064 if (test_and_set_bit( 0, (void *) &priv->tx_chain_active) ) {
3065 dev->tbusy=0;
3066 return 1;
3069 dev->trans_start = jiffies;
3070 retval = awc_802_11_tx_find_path_and_post(dev,skb);
3071 priv->tx_chain_active = 0;
3072 // wake_up_interruptible(&priv->tx_chain_wait_queue);
3074 // if (!dev->tbusy) dev_tint(dev);
3075 return retval;
3078 int awc_tx_done(struct awc_fid * rx_fid){
3080 // dev->tbusy = 0;
3081 mark_bh(NET_BH);
3083 return 0;
3086 int awc_rx(struct NET_DEVICE *dev, struct awc_fid * rx_fid) {
3088 // struct awc_private *lp = (struct awc_private *)dev->priv;
3090 DEBUG(3, "%s: in rx_packet \n",dev->name);
3092 if (!rx_fid ){
3093 DEBUG(3, "%s: not rx_buff in rx_packet \n",dev->name);
3094 return -1;
3096 if ( !rx_fid->skb){
3097 DEBUG(3, "%s: not rx_buff->skb in rx_packet \n",dev->name);
3098 return -1;
3102 rx_fid->skb->protocol = eth_type_trans(rx_fid->skb,dev);
3103 netif_rx(rx_fid->skb);
3104 rx_fid = NULL;
3106 return 0;
3110 void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
3112 struct NET_DEVICE *dev = (struct NET_DEVICE *)dev_id;
3113 // struct awc_private *lp;
3114 // unsigned long flags;
3116 // if ((dev == NULL)) return;
3118 // lp = (struct awc_private *)dev->priv;
3123 DEBUG(2, "%s: awc_interrupt \n", dev->name);
3125 awc_interrupt_process(dev);
3127 return;
3132 /************************ STATS, MULTICAST & STUFF ****************/
3136 struct enet_statistics *awc_get_stats(struct NET_DEVICE *dev)
3138 struct awc_private *priv = (struct awc_private *)dev->priv;
3139 // unsigned long flags;
3140 // int cnt = 0;
3141 // int unlocked_stats_in_interrupt=0;
3143 DEBUG(2, "%s: awc_get_stats \n", dev->name);
3145 if (!dev->start) {
3146 return 0;
3148 // save_flags(flags);
3149 // cli();
3150 if (awc_full_stats)
3151 awc_readrid_dir(dev, &priv->rid_dir[9]);
3152 // restore_flags(flags);
3154 // the very following is the very wrong very probably
3155 if (awc_full_stats){
3156 priv->stats.rx_fifo_errors = priv->statistics.RxOverrunErr ;
3157 priv->stats.rx_crc_errors = priv->statistics.RxPlcpCrcErr + priv->statistics.RxMacCrcErr ;
3158 priv->stats.rx_frame_errors = priv->statistics.RxPlcpFormat ;
3159 priv->stats.rx_length_errors = priv->statistics.RxPlcpLength ;
3160 priv->stats.rx_missed_errors = priv->statistics.RxAged ;
3161 priv->stats.rx_over_errors = priv->statistics.RxOverrunErr ;
3163 priv->stats.collisions = priv->statistics.TxSinColl;
3164 priv->stats.tx_aborted_errors = priv->statistics.TxAged ;
3165 priv->stats.tx_fifo_errors = priv->statistics.HostTxFail ;
3166 priv->stats.tx_window_errors = priv->statistics.TxMulColl ;
3167 priv->stats.tx_heartbeat_errors = priv->statistics.DefersProt +priv->statistics.DefersEngy ;
3168 priv->stats.tx_carrier_errors = priv->statistics.RetryLong +priv->statistics.RetryShort ;
3169 priv->stats.multicast = priv->statistics.HostRxMc;
3173 // printk("rx_packets %d\n",priv->stats.rx_packets);
3174 return &(priv->stats);
3178 int awc_change_mtu(struct NET_DEVICE *dev, int new_mtu){
3180 // struct awc_private *priv = (struct awc_private *)dev->priv;
3181 // unsigned long flags;
3183 if ((new_mtu < 256 ) || (new_mtu > 2312) || (max_mtu && new_mtu > max_mtu) )
3184 return -EINVAL;
3186 if (dev->start) {
3187 printk("PLEASE, ifconfig %s down for mtu change\n",dev->name);
3190 if (dev->mtu != new_mtu) {
3191 // save_flags(flags);
3192 // cli();
3193 awc_disable_MAC(dev);
3194 awc_tx_dealloc(dev);
3195 dev->mtu = new_mtu;
3196 awc_tx_alloc(dev);
3197 awc_enable_MAC(dev);
3198 // restore_flags(flags);
3200 printk("%s mtu has been changed to %d \n ",dev->name,dev->mtu);
3204 return 0;
3209 void
3210 awc_set_multicast_list(struct NET_DEVICE *dev) {
3211 // int ioaddr = dev->base_addr;
3213 /* if (dev->flags & IFF_PROMISC)
3214 promisc
3215 else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
3216 allmulti
3217 else
3218 normal
3226 int (* awc_proc_set_fun) (int) = NULL;
3227 int (* awc_proc_unset_fun) (int) = NULL;
3230 int awc_register_proc(int (*awc_proc_set_device)(int),int (*awc_proc_unset_device)(int)){
3232 AWC_ENTRY_EXIT_DEBUG("awc_register_proc");
3233 awc_proc_set_fun = awc_proc_set_device;
3234 awc_proc_unset_fun = awc_proc_unset_device;
3235 AWC_ENTRY_EXIT_DEBUG("exit");
3236 return 0;
3239 int awc_unregister_proc(void){
3241 AWC_ENTRY_EXIT_DEBUG("awc_unregister_proc");
3243 awc_proc_set_fun = NULL;
3244 awc_proc_unset_fun = NULL;
3245 AWC_ENTRY_EXIT_DEBUG("exit");
3246 return 0;
3249 #ifdef MODULE
3251 int init_module(void)
3253 // unsigned long flags;
3256 printk(KERN_INFO"%s", aironet4500_core_version);
3257 return 0;
3262 void cleanup_module(void)
3264 printk(KERN_INFO "aironet4500 unloading core module \n");
3268 #endif