1
2
3
4
5
6
7
8
9
10
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/config.h>
15#include <linux/kernel.h>
16
17#include <linux/version.h>
18
19#include <linux/sched.h>
20#include <linux/tqueue.h>
21#include <linux/slab.h>
22#include <linux/string.h>
23#include <linux/timer.h>
24#include <linux/interrupt.h>
25#include <linux/in.h>
26#include <asm/io.h>
27#include <asm/system.h>
28#include <asm/bitops.h>
29
30#include <linux/netdevice.h>
31#include <linux/etherdevice.h>
32#include <linux/skbuff.h>
33#include <linux/if_arp.h>
34#include <linux/ioport.h>
35
36#ifdef CONFIG_PROC_FS
37
38#include <linux/sysctl.h>
39#include <linux/fs.h>
40
41#include "aironet4500.h"
42#include "aironet4500_rid.c"
43
44
45#define AWC_STR_SIZE 0x2ff0
46#define DEV_AWC_INFO 1
47#define DEV_AWC 1
48
49struct awc_proc_private{
50 struct ctl_table_header * sysctl_header;
51 struct ctl_table * proc_table;
52 struct ctl_table proc_table_device_root[2];
53 struct ctl_table proc_table_sys_root[2];
54 char proc_name[10];
55};
56static char awc_drive_info[AWC_STR_SIZE]="Zcom \n\0";
57static char awc_proc_buff[AWC_STR_SIZE];
58static int awc_int_buff;
59static struct awc_proc_private awc_proc_priv[MAX_AWCS];
60
61extern int awc_proc_unset_device(int device_number);
62
63int awc_proc_format_array(int write,char * buff, size_t * len, struct awc_rid_dir * rid_dir, struct aironet4500_RID * rid){
64
65 u8 * data = rid_dir->buff + rid->offset;
66 int pos = 0;
67 int null_past = 0;
68 int hex = ((rid->mask == 0xff) && (rid->value == 0x0 ));
69 int string = ((rid->mask == 0) && (rid->value == 0 ));
70 u32 val =0;
71 int bytes = (rid->bits / 8);
72 int ch =0;
73 int i,k;
74 int array_len = rid->array;
75 int nullX = 0;
76
77
78 AWC_ENTRY_EXIT_DEBUG("awc_proc_format_array");
79
80 if (rid->bits %8 ) bytes +=1;
81
82 if (bytes > 4 && rid->array == 1){
83 array_len = bytes;
84 bytes = 1;
85 hex = 1;
86 };
87 if (bytes < 1 || bytes > 4){
88 printk(KERN_ERR " weird number of bytes %d in aironet rid \n",bytes);
89 return -1;
90 };
91 DEBUG(0x20000,"awc proc array bytes %d",bytes);
92 DEBUG(0x20000," hex %d",hex);
93 DEBUG(0x20000," string %d",string);
94
95 DEBUG(0x20000," array_len %d \n",array_len);
96 DEBUG(0x20000," offset %d \n",rid->offset);
97
98 if (!write){
99 for (i=0; i < array_len ; i++){
100
101 if (bytes <= 1 ) val = data[i*bytes];
102 else if (bytes <= 2 ) val = *((u16 *)&data[i*bytes]);
103 else if (bytes <= 4 ) val = *((u32 *)&data[i*bytes]);
104
105 if (rid->null_terminated && !val)
106 null_past =1;
107
108 if (hex && !string)
109 for (k=0; k <bytes; k++)
110 pos += sprintf(buff+pos, "%02x",(unsigned char ) data[i*bytes +k]);
111 else if (string)
112 pos += sprintf(buff+pos, "%c",val);
113 else pos += sprintf(buff+pos, "%c",val);
114
115 DEBUG(0x20000, "awcproc %x %x \n",data[i], val);
116 };
117
118 } else {
119 for (i=0; i < array_len ; i++){
120
121 DEBUG(0x20000, "awcproc %x %x \n",data[i], buff[i]);
122
123 if (hex && ! string){
124
125 val = 0;
126
127 for (k=0; k < bytes; k++){
128 val <<= 8;
129 ch = *(buff + 2*i*bytes +k + nullX);
130 if (ch >= '0' && ch <='9')
131 ch -= '0';
132 if (ch >= 'A' && ch <='F')
133 ch -= 'A'+ 0xA;
134 if (ch >= 'a' && ch <='f')
135 ch -= 'a'+ 0xA;
136 val += ch <<4;
137 k++;
138
139 ch = *(buff + 2*i*bytes +k + nullX);
140 if (val == 0 && (ch == 'X' || ch == 'x')){
141 nullX=2;
142 val = 0;
143 k = -1;
144 continue;
145 };
146 if (ch >= '0' && ch <='9')
147 ch -= '0';
148 if (ch >= 'A' && ch <='F')
149 ch -= 'A'+ 0xA;
150 if (ch >= 'a' && ch <='f')
151 ch -= 'a'+ 0xA;
152
153 val += ch;
154 if (i*bytes > *len )
155 val = 0;
156 }
157 if (rid->bits <=8 ) data[i*bytes] = val;
158 else if (rid->bits <=16 ) *((u16 *)&data[i*bytes]) = val;
159 else if (rid->bits <=32 ) *((u32 *)&data[i*bytes]) = val;
160 if (!val) null_past=1;
161
162 } else {
163 for (k=0; k < bytes; k++){
164 data[i*bytes +k] = *(buff + i*bytes +k);
165 if (i*bytes +k > *len || !data[i*bytes +k])
166 null_past = 1;;
167 }
168
169 }
170 if (null_past){
171 if (rid->bits <=8 ) data[i*bytes] = 0;
172 else if (rid->bits <=16 ) *((u16 *)&data[i*bytes]) = 0;
173 else if (rid->bits <=32 ) *((u32 *)&data[i*bytes]) = 0;
174 }
175
176 }
177
178 };
179
180
181
182
183 AWC_ENTRY_EXIT_DEBUG("awc_proc_format_array");
184 return 0;
185};
186
187
188int awc_proc_format_bits(int write,u32 * buff, size_t* lenp, struct awc_rid_dir * rid_dir, struct aironet4500_RID * rid){
189
190 u8 * data = rid_dir->buff + rid->offset;
191 u32 val = 0;
192 int not_bool = 0;
193
194 AWC_ENTRY_EXIT_DEBUG("awc_proc_format_bits");
195
196 if ((rid->bits == 8 && rid->mask == 0xff) ||
197 (rid->bits == 16 && rid->mask == 0xffff) ||
198 (rid->bits == 32 && rid->mask == 0xffffffff) )
199 not_bool = 1;
200
201 if (rid->bits <=8 ) val = *data;
202 else if (rid->bits <=16 ) val = *((u16 *)data);
203 else if (rid->bits <=32 ) val = *((u32 *)data);
204
205 DEBUG(0x20000,"awc proc int enter data %x \n",val);
206 DEBUG(0x20000,"awc proc int enter buff %x \n",*buff);
207 DEBUG(0x20000,"awc proc int enter intbuff %x \n",awc_int_buff);
208 DEBUG(0x20000,"awc proc int enter lenp %x \n",*lenp);
209
210
211
212 if (!write){
213 if (rid->mask)
214 val &= rid->mask;
215
216 if (!not_bool && rid->mask &&
217 ((val & rid->mask) == (rid->value & rid->mask)))
218 *buff = 1;
219 else if (!not_bool) *buff = 0;
220 else *buff = val;
221 } else {
222 if (not_bool){
223 val &= ~rid->mask;
224 val |= (*buff & rid->mask);
225 } else {
226 if (*buff){
227 val &= ~rid->mask;
228 if (rid->value)
229 val |= rid->mask & rid->value;
230 else val |= rid->mask & ~rid->value;
231 } else val &= ~rid->mask;
232 };
233 if (rid->bits == 8) *data = val & 0xff;
234 if (rid->bits == 16) *((u16*)data) = val &0xffff;
235 if (rid->bits == 32) *((u32*)data) = val &0xffffffff;
236
237 }
238 DEBUG(0x20000,"awc proc int buff %x \n",awc_int_buff);
239 if (rid->bits <=8 ) val = *data;
240 else if (rid->bits <=16 ) val = *((u16 *)data);
241 else if (rid->bits <=32 ) val = *((u32 *)data);
242
243 DEBUG(0x20000,"awc proc int data %x \n",val);
244
245
246
247
248
249 AWC_ENTRY_EXIT_DEBUG("exit");
250 return 0;
251
252};
253
254int awc_proc_fun(ctl_table *ctl, int write, struct file * filp,
255 void *buffer, size_t *lenp)
256{
257 int retv =-1;
258 struct awc_private *priv = NULL;
259 unsigned long flags;
260
261
262 struct awc_rid_dir * rid_dir;
263
264 struct net_device * dev= NULL;
265 struct aironet4500_RID * rid = (struct aironet4500_RID * ) ctl->extra2;
266
267
268 AWC_ENTRY_EXIT_DEBUG("awc_proc_fun");
269
270 if (!write && filp)
271 if (filp->f_pos){
272
273 *lenp = 0;
274 return 0;
275 }
276
277 MOD_INC_USE_COUNT;
278
279 rid_dir = ((struct awc_rid_dir *)ctl->extra1);
280 dev = rid_dir->dev;
281
282 if (!dev){
283 printk(KERN_ERR " NO device here \n");
284 goto final;
285 }
286
287 if(ctl->procname == NULL || awc_drive_info == NULL ){
288 printk(KERN_WARNING " procname is NULL in sysctl_table or awc_mib_info is NULL \n at awc module\n ");
289 MOD_DEC_USE_COUNT;
290 return -1;
291 }
292 priv = (struct awc_private * ) dev->priv;
293
294 if ((rid->selector->read_only || rid->read_only) && write){
295 printk(KERN_ERR "This value is read-only \n");
296 goto final;
297 };
298
299 if (!write && rid->selector->may_change) {
300 save_flags(flags);
301 cli();
302 awc_readrid(dev,rid,rid_dir->buff + rid->offset);
303 restore_flags(flags);
304 };
305
306 if (rid->array > 1 || rid->bits > 32){
307 if (write){
308 retv = proc_dostring(ctl, write, filp, buffer, lenp);
309 if (retv) goto final;
310 retv = awc_proc_format_array(write, awc_proc_buff, lenp, rid_dir, rid);
311 if (retv) goto final;
312 } else {
313 retv = awc_proc_format_array(write, awc_proc_buff, lenp, rid_dir, rid);
314 if (retv) goto final;
315 retv = proc_dostring(ctl, write, filp, buffer, lenp);
316 if (retv) goto final;
317 }
318 } else {
319 if (write){
320 retv = proc_dointvec(ctl, write, filp, buffer, lenp);
321 if (retv) goto final;
322 retv = awc_proc_format_bits(write, &awc_int_buff, lenp, rid_dir, rid);
323 if (retv) goto final;
324 } else {
325 retv = awc_proc_format_bits(write, &awc_int_buff, lenp,rid_dir, rid);
326 if (retv) goto final;
327 retv = proc_dointvec(ctl, write, filp, buffer, lenp);
328 if (retv) goto final;
329 }
330 }
331 if (write) {
332 save_flags(flags);
333 cli();
334
335 if (rid->selector->MAC_Disable_at_write){
336 awc_disable_MAC(dev);
337 };
338 awc_writerid(dev,rid,rid_dir->buff + rid->offset);
339 if (rid->selector->MAC_Disable_at_write){
340 awc_enable_MAC(dev);
341 };
342 restore_flags(flags);
343
344 };
345
346 DEBUG(0x20000,"awc proc ret %x \n",retv);
347 DEBUG(0x20000,"awc proc lenp %x \n",*lenp);
348
349 MOD_DEC_USE_COUNT;
350 return retv;
351
352final:
353
354 AWC_ENTRY_EXIT_DEBUG("exit");
355 MOD_DEC_USE_COUNT;
356 return -1 ;
357}
358
359
360char conf_reset_result[200];
361
362
363ctl_table awc_exdev_table[] = {
364 {0, NULL, NULL,0, 0400, NULL},
365 {0}
366};
367ctl_table awc_exroot_table[] = {
368 {254, "aironet4500", NULL, 0, 0555, NULL},
369 {0}
370};
371
372ctl_table awc_driver_proc_table[] = {
373 {1, "debug" , &awc_debug, sizeof(awc_debug), 0600,NULL, proc_dointvec},
374 {2, "bap_sleep" , &bap_sleep, sizeof(bap_sleep), 0600,NULL, proc_dointvec},
375 {3, "bap_sleep_after_setup" , &bap_sleep_after_setup, sizeof(bap_sleep_after_setup), 0600,NULL, proc_dointvec},
376 {4, "sleep_before_command" , &sleep_before_command, sizeof(sleep_before_command), 0600,NULL, proc_dointvec},
377 {5, "bap_sleep_before_write" , &bap_sleep_before_write, sizeof(bap_sleep_before_write), 0600,NULL, proc_dointvec},
378 {6, "sleep_in_command" , &sleep_in_command , sizeof(sleep_in_command), 0600,NULL, proc_dointvec},
379 {7, "both_bap_lock" , &both_bap_lock , sizeof(both_bap_lock), 0600,NULL, proc_dointvec},
380 {8, "bap_setup_spinlock" , &bap_setup_spinlock , sizeof(bap_setup_spinlock), 0600,NULL, proc_dointvec},
381 {0}
382};
383
384ctl_table awc_driver_level_ctable[] = {
385 {1, "force_rts_on_shorter" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
386 {2, "force_tx_rate" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
387 {3, "ip_tos_reliability_rts" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
388 {4, "ip_tos_troughput_no_retries", NULL, sizeof(int), 0600,NULL, proc_dointvec},
389 {5, "debug" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
390 {6, "simple_bridge" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
391 {7, "p802_11_send" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
392 {8, "full_stats" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
393 {0}
394};
395
396ctl_table awc_root_table[] = {
397 {254, "aironet4500", NULL, 0, 0555, awc_driver_proc_table},
398 {0}
399};
400
401struct ctl_table_header * awc_driver_sysctl_header;
402
403const char awc_procname[]= "awc5";
404
405
406int awc_proc_set_device(int device_number){
407 int group =0;
408 int rid = 0;
409 struct awc_private * priv;
410 ctl_table * tmp_table_ptr;
411
412 AWC_ENTRY_EXIT_DEBUG("awc_proc_set_device");
413 if (!aironet4500_devices[device_number] || (awc_nof_rids <=0 )) return -1 ;
414 priv = (struct awc_private * )aironet4500_devices[device_number]->priv;
415
416 awc_rids_setup(aironet4500_devices[device_number]);
417
418 memcpy(&(awc_proc_priv[device_number].proc_table_sys_root[0]), awc_exroot_table,sizeof(struct ctl_table)*2);
419 awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name = 254 - device_number;
420 memcpy(awc_proc_priv[device_number].proc_table_device_root, awc_exdev_table,sizeof(awc_exdev_table) );
421 awc_proc_priv[device_number].proc_table_device_root[0].ctl_name = device_number+1;
422
423 awc_proc_priv[device_number].proc_table_sys_root->child = awc_proc_priv[device_number].proc_table_device_root;
424 memcpy(awc_proc_priv[device_number].proc_name,(struct NET_DEVICE * )aironet4500_devices[device_number]->name,5);
425 awc_proc_priv[device_number].proc_name[4]=0;
426
427 awc_proc_priv[device_number].proc_table_device_root[0].procname = &(awc_proc_priv[device_number].proc_name[0]);
428 awc_proc_priv[device_number].proc_table = kmalloc(sizeof(struct ctl_table) * (awc_nof_rids+2),GFP_KERNEL);
429 if (!awc_proc_priv[device_number].proc_table){
430 printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n");
431 return -1;
432 }
433 awc_proc_priv[device_number].proc_table_device_root[0].child=awc_proc_priv[device_number].proc_table;
434
435
436 if (awc_debug) printk("device %d of %d proc interface setup ",device_number, awc_nof_rids);
437
438
439 while (awc_rids[group].selector && group < awc_nof_rids){
440 if (awc_debug & 0x20000)
441 printk(KERN_CRIT "ridgroup %s size %d \n", awc_rids[group].selector->name,awc_rids[group].size);
442
443 awc_proc_priv[device_number].proc_table[group].ctl_name = group +1;
444 awc_proc_priv[device_number].proc_table[group+1].ctl_name = 0;
445 awc_proc_priv[device_number].proc_table[group].procname = awc_rids[group].selector->name;
446 awc_proc_priv[device_number].proc_table[group].data = awc_proc_buff;
447 awc_proc_priv[device_number].proc_table[group].maxlen = sizeof(awc_proc_buff) -1;
448 awc_proc_priv[device_number].proc_table[group].mode = 0600;
449 awc_proc_priv[device_number].proc_table[group].child = kmalloc(sizeof(struct ctl_table) * (awc_rids[group].size +2), GFP_KERNEL);
450 awc_proc_priv[device_number].proc_table[group].proc_handler = NULL;
451 awc_proc_priv[device_number].proc_table[group].strategy = NULL;
452 awc_proc_priv[device_number].proc_table[group].de = NULL;
453 awc_proc_priv[device_number].proc_table[group].extra1 = NULL;
454 awc_proc_priv[device_number].proc_table[group].extra2 = NULL;
455 if (!awc_proc_priv[device_number].proc_table[group].child) {
456 awc_proc_priv[device_number].proc_table[group].ctl_name = 0;
457 printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n");
458 return 0;
459 }
460 rid=0;
461 while (awc_rids[group].rids[rid].selector && (rid < awc_rids[group].size -1)){
462
463
464
465 awc_proc_priv[device_number].proc_table[group].child[rid].ctl_name = rid +1;
466 awc_proc_priv[device_number].proc_table[group].child[rid+1].ctl_name = 0;
467 awc_proc_priv[device_number].proc_table[group].child[rid].procname = awc_rids[group].rids[rid].name;
468 if (awc_rids[group].rids[rid].array > 1 ||
469 awc_rids[group].rids[rid].bits > 32 ){
470 awc_proc_priv[device_number].proc_table[group].child[rid].data = awc_proc_buff;
471 awc_proc_priv[device_number].proc_table[group].child[rid].maxlen = sizeof(awc_proc_buff) -1;
472 } else {
473 awc_proc_priv[device_number].proc_table[group].child[rid].data = &awc_int_buff;
474 awc_proc_priv[device_number].proc_table[group].child[rid].maxlen = sizeof(awc_int_buff);
475
476 }
477 if ( awc_rids[group].rids[rid].read_only ||
478 awc_rids[group].rids[rid].selector->read_only )
479 awc_proc_priv[device_number].proc_table[group].child[rid].mode = 0400;
480 else
481 awc_proc_priv[device_number].proc_table[group].child[rid].mode = 0600;
482 awc_proc_priv[device_number].proc_table[group].child[rid].child = NULL;
483 awc_proc_priv[device_number].proc_table[group].child[rid].proc_handler = awc_proc_fun;
484 awc_proc_priv[device_number].proc_table[group].child[rid].strategy = NULL;
485 awc_proc_priv[device_number].proc_table[group].child[rid].de = NULL;
486 awc_proc_priv[device_number].proc_table[group].child[rid].extra1 = (void *) &(((struct awc_private* )aironet4500_devices[device_number]->priv)->rid_dir[group]);
487 awc_proc_priv[device_number].proc_table[group].child[rid].extra2 = (void *) &(awc_rids[group].rids[rid]);
488
489 rid++;
490 }
491
492 group++;
493
494 };
495
496 awc_proc_priv[device_number].proc_table[group].ctl_name = group +1;
497 awc_proc_priv[device_number].proc_table[group+1].ctl_name = 0;
498 awc_proc_priv[device_number].proc_table[group].procname = "driver-level";
499 awc_proc_priv[device_number].proc_table[group].data = awc_proc_buff;
500 awc_proc_priv[device_number].proc_table[group].maxlen = sizeof(awc_proc_buff) -1;
501 awc_proc_priv[device_number].proc_table[group].mode = 0600;
502 awc_proc_priv[device_number].proc_table[group].child = kmalloc(sizeof(awc_driver_level_ctable) , GFP_KERNEL);
503 awc_proc_priv[device_number].proc_table[group].proc_handler = NULL;
504 awc_proc_priv[device_number].proc_table[group].strategy = NULL;
505 awc_proc_priv[device_number].proc_table[group].de = NULL;
506 awc_proc_priv[device_number].proc_table[group].extra1 = NULL;
507 awc_proc_priv[device_number].proc_table[group].extra2 = NULL;
508 if (!awc_proc_priv[device_number].proc_table[group].child) {
509 awc_proc_priv[device_number].proc_table[group].ctl_name = 0;
510 printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n");
511 return 0;
512 }
513
514
515 tmp_table_ptr = awc_proc_priv[device_number].proc_table[group].child;
516 memcpy(tmp_table_ptr,awc_driver_level_ctable,sizeof(awc_driver_level_ctable));
517
518
519 tmp_table_ptr[0].data =
520 &(priv->force_rts_on_shorter);
521 tmp_table_ptr[1].data = &priv->force_tx_rate;
522 tmp_table_ptr[2].data = (void *) &priv->ip_tos_reliability_rts;
523 tmp_table_ptr[3].data = (void *) &priv->ip_tos_troughput_no_retries;
524 tmp_table_ptr[4].data = (void *) &priv->debug;
525 tmp_table_ptr[5].data = (void *) &priv->simple_bridge;
526 tmp_table_ptr[6].data = (void *) &priv->p802_11_send;
527 tmp_table_ptr[7].data = (void *) &priv->full_stats;
528
529
530 awc_proc_priv[device_number].sysctl_header =
531 register_sysctl_table(awc_proc_priv[device_number].proc_table_sys_root,0);
532
533 AWC_ENTRY_EXIT_DEBUG("exit");
534
535 if (awc_proc_priv[device_number].sysctl_header)
536 return 0;
537 return 1;
538
539};
540
541int awc_proc_unset_device(int device_number){
542 int k;
543
544 AWC_ENTRY_EXIT_DEBUG("awc_proc_unset_device");
545 if (awc_proc_priv[device_number].sysctl_header){
546 unregister_sysctl_table(awc_proc_priv[device_number].sysctl_header);
547 awc_proc_priv[device_number].sysctl_header = NULL;
548 }
549 if (awc_proc_priv[device_number].proc_table){
550 for (k=0; awc_proc_priv[device_number].proc_table[k].ctl_name ; k++ ){
551 if (awc_proc_priv[device_number].proc_table[k].child)
552 kfree(awc_proc_priv[device_number].proc_table[k].child);
553 }
554 kfree(awc_proc_priv[device_number].proc_table);
555 awc_proc_priv[device_number].proc_table = NULL;
556 }
557 if (awc_proc_priv[device_number].proc_table_device_root[0].ctl_name)
558 awc_proc_priv[device_number].proc_table_device_root[0].ctl_name = 0;
559 if (awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name)
560 awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name = 0;
561
562 AWC_ENTRY_EXIT_DEBUG("exit");
563 return 0;
564};
565
566static int aironet_proc_init(void) {
567 int i=0;
568
569 AWC_ENTRY_EXIT_DEBUG("init_module");
570
571
572 for (i=0; i < MAX_AWCS; i++){
573 awc_proc_set_device(i);
574 }
575
576 awc_register_proc(awc_proc_set_device, awc_proc_unset_device);
577
578 awc_driver_sysctl_header = register_sysctl_table(awc_root_table,0);
579
580 AWC_ENTRY_EXIT_DEBUG("exit");
581 return 0;
582
583};
584
585static void aironet_proc_exit(void){
586
587 int i=0;
588 AWC_ENTRY_EXIT_DEBUG("cleanup_module");
589 awc_unregister_proc();
590 for (i=0; i < MAX_AWCS; i++){
591 awc_proc_unset_device(i);
592 }
593 if (awc_driver_sysctl_header)
594 unregister_sysctl_table(awc_driver_sysctl_header);
595 AWC_ENTRY_EXIT_DEBUG("exit");
596};
597
598module_init(aironet_proc_init);
599module_exit(aironet_proc_exit);
600
601#else
602#error awc driver needs CONFIG_PROC_FS
603
604#endif
605MODULE_LICENSE("GPL");
606