aironet4500_proc.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:19k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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