patch-2.3.31 linux/drivers/net/aironet4500_proc.c

Next file: linux/drivers/net/aironet4500_rid.c
Previous file: linux/drivers/net/aironet4500_core.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.30/linux/drivers/net/aironet4500_proc.c linux/drivers/net/aironet4500_proc.c
@@ -0,0 +1,553 @@
+/*
+ *	 Aironet 4500 Pcmcia driver
+ *
+ *		Elmer Joandi, Januar 1999
+ *	Copyright Elmer Joandi, all rights restricted
+ *	
+ *
+ *	Revision 0.1 ,started  30.12.1998
+ *
+ *
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#include <linux/version.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+
+#ifdef CONFIG_PROC_FS
+
+#ifdef CONFIG_PROC_FS
+#include <linux/sysctl.h>
+#else
+#error awc driver needs CONFIG_PROC_FS
+#endif
+
+
+
+#include "aironet4500_rid.c"
+
+
+#define AWC_STR_SIZE 	0x2ff0
+#define DEV_AWC_INFO 	1
+#define DEV_AWC 	1
+
+struct awc_proc_private{
+	struct ctl_table_header *	sysctl_header;
+  	struct ctl_table	*	proc_table;
+  	struct ctl_table		proc_table_device_root[2];
+  	struct ctl_table		proc_table_sys_root[2];
+	char 				proc_name[10];
+};	        
+static char awc_drive_info[AWC_STR_SIZE]="Zcom \n\0";
+static char awc_proc_buff[AWC_STR_SIZE]="\0";
+static int  awc_int_buff;
+static struct awc_proc_private awc_proc_priv[MAX_AWCS]; 
+
+extern int awc_proc_unset_device(int device_number);
+
+int awc_proc_format_array(int write,char * buff, size_t * len, struct awc_rid_dir * rid_dir, struct aironet4500_RID * rid){
+
+  u8 * data = rid_dir->buff + rid->offset;
+  int pos = 0;
+  int null_past = 0;
+  int hex = ((rid->mask == 0xff) && (rid->value == 0x0 ));
+  int string = ((rid->mask == 0) && (rid->value == 0 ));
+  u32 val =0;
+  int bytes = (rid->bits / 8);
+  int ch =0;
+  int i,k;
+  int array_len = rid->array;
+  int nullX = 0;
+
+ 
+  	AWC_ENTRY_EXIT_DEBUG("awc_proc_format_array");
+
+      if (rid->bits %8 ) bytes +=1;
+     
+     if (bytes > 4 && rid->array == 1){
+     	array_len = bytes;
+     	bytes = 1;
+     	hex = 1;
+     };
+     if (bytes < 1 || bytes > 4){
+     	printk(KERN_ERR " weird number of bytes %d in aironet rid \n",bytes);
+     	return -1;
+     };    	
+     DEBUG(0x20000,"awc proc array  bytes %d",bytes);
+     DEBUG(0x20000," hex %d",hex);
+     DEBUG(0x20000," string %d",string);
+
+     DEBUG(0x20000," array_len %d \n",array_len);
+     DEBUG(0x20000," offset %d \n",rid->offset);
+
+     if (!write){
+	for (i=0; i < array_len ; i++){
+	
+		if 	(bytes <= 1 ) val = data[i*bytes];
+		else if (bytes <= 2 ) val = *((u16 *)&data[i*bytes]);
+		else if (bytes <= 4 ) val = *((u32 *)&data[i*bytes]);
+		
+		if (rid->null_terminated && !val)
+			null_past =1;
+			 
+		if (hex && !string)
+			for (k=0; k <bytes; k++)
+				pos += sprintf(buff+pos, "%02x",(unsigned char ) data[i*bytes +k]);
+		else if (string)
+			pos += sprintf(buff+pos, "%c",val);
+		else	pos += sprintf(buff+pos, "%c",val);
+
+		DEBUG(0x20000, "awcproc %x %x \n",data[i], val);
+	};
+	
+     } else {
+     	for (i=0; i < array_len ; i++){
+     	
+     		DEBUG(0x20000, "awcproc %x %x \n",data[i], buff[i]);
+
+     		if (hex && ! string){
+     			
+     			val = 0;
+     			
+     			for (k=0; k < bytes; k++){
+     				val <<= 8;
+       				ch = *(buff + 2*i*bytes +k + nullX);
+     				if (ch >= '0' && ch <='9')
+     					ch -= '0';
+     				if (ch >= 'A' && ch <='F')
+     					ch -= 'A'+ 0xA;
+     				if (ch >= 'a' && ch <='f')
+     					ch -= 'a'+ 0xA;
+				val += ch <<4;
+				k++;
+				
+     				ch = *(buff + 2*i*bytes +k + nullX);
+     				if (val == 0 && (ch == 'X' || ch == 'x')){
+     					nullX=2;
+     					val = 0;
+     					k = -1;
+     					continue;
+     				};
+     				if (ch >= '0' && ch <='9')
+     					ch -= '0';
+     				if (ch >= 'A' && ch <='F')
+     					ch -= 'A'+ 0xA;
+     				if (ch >= 'a' && ch <='f')
+     					ch -= 'a'+ 0xA;
+     					
+     				val += ch;
+     				if (i*bytes > *len )
+     					val = 0;	
+     			}
+			if (rid->bits <=8 ) 	            data[i*bytes]  = val;
+			else if (rid->bits <=16 ) *((u16 *)&data[i*bytes]) = val;
+			else if (rid->bits <=32 ) *((u32 *)&data[i*bytes]) = val;
+     			if (!val) null_past=1;	
+     			
+     		} else {
+     			for (k=0; k < bytes; k++){
+     				data[i*bytes +k] = *(buff + i*bytes +k);
+     				if (i*bytes +k > *len || !data[i*bytes +k])
+     					null_past = 1;;
+     			}
+     	
+     		}
+     		if (null_past){
+     			if (rid->bits <=8 ) 	            data[i*bytes]  = 0;
+			else if (rid->bits <=16 ) *((u16 *)&data[i*bytes]) = 0;
+			else if (rid->bits <=32 ) *((u32 *)&data[i*bytes]) = 0;
+		}
+
+     	}
+     	
+     };
+     
+	
+//     *len = pos;
+ 
+  	AWC_ENTRY_EXIT_DEBUG("awc_proc_format_array");
+     return 0;	
+};
+
+
+int awc_proc_format_bits(int write,u32 * buff, size_t* lenp, struct awc_rid_dir * rid_dir, struct aironet4500_RID * rid){
+
+  u8 * data = rid_dir->buff + rid->offset;
+  u32 val = 0;
+  int not_bool = 0;
+ 
+  	AWC_ENTRY_EXIT_DEBUG("awc_proc_format_bits");
+
+	if ((rid->bits == 8 && rid->mask == 0xff) 	|| 
+	    (rid->bits == 16 && rid->mask == 0xffff) 	|| 
+	    (rid->bits == 32 && rid->mask == 0xffffffff)   )
+	    not_bool = 1;
+	    
+	if (rid->bits <=8 ) 		val = 		*data;
+	else if (rid->bits <=16 ) 	val = *((u16 *)data);
+	else if (rid->bits <=32 ) 	val = *((u32 *)data);
+
+	DEBUG(0x20000,"awc proc int enter data %x \n",val);
+	DEBUG(0x20000,"awc proc int enter buff %x \n",*buff);
+	DEBUG(0x20000,"awc proc int enter intbuff %x \n",awc_int_buff);
+	DEBUG(0x20000,"awc proc int enter lenp  %x \n",*lenp);
+
+
+
+	if (!write){
+		if (rid->mask)
+			val &= rid->mask;
+
+		if (!not_bool && rid->mask && 
+		    ((val & rid->mask) == (rid->value & rid->mask)))
+			*buff = 1;
+		else if (!not_bool) *buff = 0;
+		else *buff = val;
+	} else {
+		if (not_bool){
+			val &= ~rid->mask; 
+			val |= (*buff & rid->mask);
+		} else {
+			if (*buff){
+				val &= ~rid->mask;
+				if (rid->value)
+					val |= rid->mask & rid->value;
+				else 	val |= rid->mask & ~rid->value;
+			} else val &= ~rid->mask;
+		};
+		if (rid->bits == 8) *data = val & 0xff;
+		if (rid->bits == 16) *((u16*)data) = val &0xffff;
+		if (rid->bits == 32) *((u32*)data) = val &0xffffffff; 
+	
+	}
+	DEBUG(0x20000,"awc proc int buff %x \n",awc_int_buff);
+	if (rid->bits <=8 ) 		val = 		*data;
+	else if (rid->bits <=16 ) 	val = *((u16 *)data);
+	else if (rid->bits <=32 ) 	val = *((u32 *)data);
+
+	DEBUG(0x20000,"awc proc int data %x \n",val);
+	
+//	*lenp = sizeof(int);
+ 	*lenp += 1;
+ 	
+  	AWC_ENTRY_EXIT_DEBUG("exit");
+	return 0;
+
+};
+
+int awc_proc_fun(ctl_table *ctl, int write, struct file * filp,
+                           void *buffer, size_t *lenp)
+{
+        int retv =-1;
+   	struct awc_private *priv = NULL;
+	unsigned long  flags;
+//	int device_number = (int ) ctl->extra1;
+
+	struct awc_rid_dir * rid_dir;
+
+	struct NET_DEVICE * dev= NULL;
+	struct aironet4500_RID * rid = (struct aironet4500_RID * ) ctl->extra2;
+	
+ 
+  	AWC_ENTRY_EXIT_DEBUG("awc_proc_fun");
+
+	if (!write && filp)
+	 if (filp->f_pos){
+//	 	printk(KERN_CRIT "Oversize read\n");
+		*lenp = 0;// hack against reading til eof
+	  	return	0;
+	 }
+ 
+	MOD_INC_USE_COUNT;
+
+	rid_dir = ((struct awc_rid_dir *)ctl->extra1);
+	dev = rid_dir->dev;
+	
+	if (!dev){
+		printk(KERN_ERR " NO device here \n");
+		goto final;
+	}
+
+	if(ctl->procname == NULL || awc_drive_info == NULL ){
+		printk(KERN_WARNING " procname is NULL in sysctl_table or awc_mib_info is NULL \n at awc module\n ");
+		MOD_DEC_USE_COUNT;
+		return -1;
+	}
+	priv = (struct awc_private * ) dev->priv; 
+
+	if ((rid->selector->read_only || rid->read_only) && write){
+		printk(KERN_ERR "This value is read-only \n");
+		goto final;
+	};
+
+	if (!write && rid->selector->may_change) {
+		save_flags(flags);
+		cli();	
+		awc_readrid(dev,rid,rid_dir->buff + rid->offset);
+		restore_flags(flags);
+	};
+	
+	if (rid->array > 1 || rid->bits > 32){
+		if (write){
+        		retv = proc_dostring(ctl, write, filp, buffer, lenp);
+        		if (retv) goto final;
+			retv = awc_proc_format_array(write, awc_proc_buff, lenp, rid_dir, rid);
+			if (retv) goto final;
+		} else {
+			retv = awc_proc_format_array(write, awc_proc_buff, lenp, rid_dir, rid);
+			if (retv) goto final;
+        		retv = proc_dostring(ctl, write, filp, buffer, lenp);
+			if (retv) goto final;
+        	}
+        } else {
+        	if (write){
+        		retv = proc_dointvec(ctl, write, filp, buffer, lenp);        
+			if (retv) goto final;	
+			retv = awc_proc_format_bits(write, &awc_int_buff, lenp, rid_dir, rid);
+			if (retv) goto final;	
+		} else {
+			retv = awc_proc_format_bits(write, &awc_int_buff, lenp,rid_dir, rid);
+			if (retv) goto final;	
+        		retv = proc_dointvec(ctl, write, filp, buffer, lenp);        
+			if (retv) goto final;	
+		}
+        }
+	if (write) {
+		save_flags(flags);
+		cli();	
+
+		if (rid->selector->MAC_Disable_at_write){
+			awc_disable_MAC(dev);
+		};
+		awc_writerid(dev,rid,rid_dir->buff + rid->offset);
+		if (rid->selector->MAC_Disable_at_write){
+			awc_enable_MAC(dev);
+		};
+		restore_flags(flags);
+
+	};
+
+       	DEBUG(0x20000,"awc proc ret  %x \n",retv);
+       	DEBUG(0x20000,"awc proc lenp  %x \n",*lenp);
+ 
+	MOD_DEC_USE_COUNT;
+	return retv;
+  
+final:
+ 
+  	AWC_ENTRY_EXIT_DEBUG("exit");
+	MOD_DEC_USE_COUNT;
+        return -1 ;
+}
+
+
+char  conf_reset_result[200];
+
+
+ctl_table awc_exdev_table[] = {
+       {0, NULL, NULL,0, 0400, NULL},
+       {0}
+};
+ctl_table awc_exroot_table[] = {
+        {254, "aironet4500", NULL, 0, 0555, NULL},
+        {0}
+};
+
+ctl_table awc_driver_proc_table[] = {
+        {1, "debug"			, &awc_debug, sizeof(awc_debug), 0600,NULL, proc_dointvec},
+        {2, "bap_sleep"			, &bap_sleep, sizeof(bap_sleep), 0600,NULL, proc_dointvec},
+        {3, "bap_sleep_after_setup"	, &bap_sleep_after_setup, sizeof(bap_sleep_after_setup), 0600,NULL, proc_dointvec},
+        {4, "sleep_before_command"	, &sleep_before_command, sizeof(sleep_before_command), 0600,NULL, proc_dointvec},
+        {5, "bap_sleep_before_write"	, &bap_sleep_before_write, sizeof(bap_sleep_before_write), 0600,NULL, proc_dointvec},
+        {6, "sleep_in_command"		, &sleep_in_command	, sizeof(sleep_in_command), 0600,NULL, proc_dointvec},
+        {0}
+};
+
+ctl_table awc_root_table[] = {
+        {254, "aironet4500", NULL, 0, 0555, awc_driver_proc_table},
+        {0}
+};
+
+struct ctl_table_header * awc_driver_sysctl_header = NULL;
+
+const char awc_procname[]= "awc5";
+
+
+int awc_proc_set_device(int device_number){
+  int group =0;
+  int rid = 0;
+  struct awc_priv * priv;
+
+ 
+  AWC_ENTRY_EXIT_DEBUG("awc_proc_set_device");  
+  if (!aironet4500_devices[device_number] || (awc_nof_rids <=0 )) return -1 ;
+  priv = (struct awc_priv * )aironet4500_devices[device_number]->priv;
+
+  awc_rids_setup(aironet4500_devices[device_number]);
+
+  memcpy(&(awc_proc_priv[device_number].proc_table_sys_root[0]), awc_exroot_table,sizeof(struct ctl_table)*2);
+  awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name = 254 - device_number;
+  memcpy(awc_proc_priv[device_number].proc_table_device_root, awc_exdev_table,sizeof(awc_exdev_table) );
+  awc_proc_priv[device_number].proc_table_device_root[0].ctl_name = device_number+1;
+
+  awc_proc_priv[device_number].proc_table_sys_root->child = awc_proc_priv[device_number].proc_table_device_root;
+  memcpy(awc_proc_priv[device_number].proc_name,(struct awc_priv * )aironet4500_devices[device_number]->name,5);
+  awc_proc_priv[device_number].proc_name[4]=0;
+ // awc_proc_priv[device_number].proc_name[3]=48+device_number;
+  awc_proc_priv[device_number].proc_table_device_root[0].procname = &(awc_proc_priv[device_number].proc_name[0]);
+  awc_proc_priv[device_number].proc_table = kmalloc(sizeof(struct ctl_table) * (awc_nof_rids+2),GFP_KERNEL);
+  if (!awc_proc_priv[device_number].proc_table){
+   printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n");
+   return -1;
+  }
+  awc_proc_priv[device_number].proc_table_device_root[0].child=awc_proc_priv[device_number].proc_table;
+  
+
+ if (awc_debug) printk("device  %d of %d proc interface setup ",device_number, awc_nof_rids);
+
+
+  while (awc_rids[group].selector && group < awc_nof_rids){
+     	if (awc_debug & 0x20000)
+     		printk(KERN_CRIT "ridgroup %s  size %d \n", awc_rids[group].selector->name,awc_rids[group].size);
+
+  	awc_proc_priv[device_number].proc_table[group].ctl_name = group +1;
+  	awc_proc_priv[device_number].proc_table[group+1].ctl_name = 0;
+  	awc_proc_priv[device_number].proc_table[group].procname = awc_rids[group].selector->name;
+  	awc_proc_priv[device_number].proc_table[group].data	= awc_proc_buff;
+  	awc_proc_priv[device_number].proc_table[group].maxlen  = sizeof(awc_proc_buff) -1;
+  	awc_proc_priv[device_number].proc_table[group].mode	= 0600;
+  	awc_proc_priv[device_number].proc_table[group].child	= kmalloc(sizeof(struct ctl_table) * (awc_rids[group].size +2), GFP_KERNEL);
+  	awc_proc_priv[device_number].proc_table[group].proc_handler = NULL;
+  	awc_proc_priv[device_number].proc_table[group].strategy = NULL;
+  	awc_proc_priv[device_number].proc_table[group].de	= NULL;
+  	awc_proc_priv[device_number].proc_table[group].extra1	= NULL;
+  	awc_proc_priv[device_number].proc_table[group].extra2	= NULL;
+  	if (!awc_proc_priv[device_number].proc_table[group].child) {
+  		awc_proc_priv[device_number].proc_table[group].ctl_name = 0;
+   		printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n");
+  		return 0;
+  	}
+  	rid=0;
+  	while (awc_rids[group].rids[rid].selector && (rid < awc_rids[group].size -1)){
+
+//  	   	DEBUG(0x20000,"rid %s  \n", awc_rids[group].rids[rid].name);
+
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].ctl_name 	= rid +1;
+	  	awc_proc_priv[device_number].proc_table[group].child[rid+1].ctl_name 	= 0;
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].procname 	= awc_rids[group].rids[rid].name;
+	  	if (awc_rids[group].rids[rid].array > 1 ||
+	  	    awc_rids[group].rids[rid].bits  > 32 ){
+	  		awc_proc_priv[device_number].proc_table[group].child[rid].data		= awc_proc_buff;
+	  		awc_proc_priv[device_number].proc_table[group].child[rid].maxlen  	= sizeof(awc_proc_buff) -1;		
+	  	} else {
+	  	 	awc_proc_priv[device_number].proc_table[group].child[rid].data		= &awc_int_buff;
+	  		awc_proc_priv[device_number].proc_table[group].child[rid].maxlen  	= sizeof(awc_int_buff);
+	  
+	  	}
+	  		if ( awc_rids[group].rids[rid].read_only ||
+	  	     awc_rids[group].rids[rid].selector->read_only )
+	  		awc_proc_priv[device_number].proc_table[group].child[rid].mode		= 0400;
+	  	else
+	  		awc_proc_priv[device_number].proc_table[group].child[rid].mode          = 0600;
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].child		= NULL;
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].proc_handler 	= awc_proc_fun;
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].strategy 	= NULL;
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].de		= NULL;
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].extra1	= (void *) &(((struct awc_private* )aironet4500_devices[device_number]->priv)->rid_dir[group]);
+	  	awc_proc_priv[device_number].proc_table[group].child[rid].extra2	= (void *) &(awc_rids[group].rids[rid]);
+
+  		rid++;	
+  	}
+  	
+  	group++;
+
+  };
+
+	awc_proc_priv[device_number].sysctl_header = 
+		register_sysctl_table(awc_proc_priv[device_number].proc_table_sys_root,0);
+ 
+	AWC_ENTRY_EXIT_DEBUG("exit");
+
+	if (awc_proc_priv[device_number].sysctl_header)
+		return 0;
+	return 1;  
+
+};
+
+int awc_proc_unset_device(int device_number){
+  int k;
+
+ AWC_ENTRY_EXIT_DEBUG("awc_proc_unset_device");
+  if (awc_proc_priv[device_number].sysctl_header){
+  	unregister_sysctl_table(awc_proc_priv[device_number].sysctl_header);
+	awc_proc_priv[device_number].sysctl_header = NULL;
+  }
+  if (awc_proc_priv[device_number].proc_table){
+	  for (k=0; awc_proc_priv[device_number].proc_table[k].ctl_name ; k++ ){
+	  	if (awc_proc_priv[device_number].proc_table[k].child)
+	  		kfree(awc_proc_priv[device_number].proc_table[k].child);
+	  }
+	  kfree(awc_proc_priv[device_number].proc_table);
+	  awc_proc_priv[device_number].proc_table = NULL;
+  }
+  if (awc_proc_priv[device_number].proc_table_device_root[0].ctl_name)
+          awc_proc_priv[device_number].proc_table_device_root[0].ctl_name = 0;
+  if (awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name)
+          awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name = 0;
+  
+	AWC_ENTRY_EXIT_DEBUG("exit");
+   return 0;
+};
+
+int init_module(void) {
+	int i=0;
+
+	AWC_ENTRY_EXIT_DEBUG("init_module");
+
+
+	for (i=0; i < MAX_AWCS;  i++){
+		awc_proc_set_device(i);
+	}
+
+	awc_register_proc(awc_proc_set_device, awc_proc_unset_device);
+
+	awc_driver_sysctl_header = register_sysctl_table(awc_root_table,0);
+
+	AWC_ENTRY_EXIT_DEBUG("exit");
+	return 0;
+
+};
+
+void cleanup_module(void){
+
+	int i=0;
+	AWC_ENTRY_EXIT_DEBUG("cleanup_module");
+	awc_unregister_proc();
+	for (i=0; i < MAX_AWCS;  i++){
+		awc_proc_unset_device(i);
+	}
+	if (awc_driver_sysctl_header)
+		unregister_sysctl_table(awc_driver_sysctl_header);
+	AWC_ENTRY_EXIT_DEBUG("exit");
+};
+
+#endif // whole proc system styff
\ No newline at end of file

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)