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