patch-2.2.10 linux/net/irda/irda_device.c

Next file: linux/net/irda/iriap.c
Previous file: linux/net/irda/ircomm/irvtd_driver.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.9/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Wed Apr 21 09:48:19 1999
+ * Modified at:   Tue Jun  1 09:05:13 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -31,6 +31,8 @@
 #include <linux/netdevice.h>
 #include <linux/init.h>
 #include <linux/tty.h>
+#include <linux/kmod.h>
+#include <linux/wireless.h>
 
 #include <asm/ioctls.h>
 #include <asm/segment.h>
@@ -53,7 +55,8 @@
 extern int actisys_init(void);
 extern int girbil_init(void);
 
-hashbin_t *irda_device = NULL;
+static hashbin_t *irda_device = NULL;
+static hashbin_t *dongles = NULL;
 
 /* Netdevice functions */
 static int irda_device_net_rebuild_header(struct sk_buff *skb);
@@ -61,9 +64,9 @@
 				       struct device *dev,
 				       unsigned short type, void *daddr, 
 				       void *saddr, unsigned len);
-static int irda_device_net_set_config( struct device *dev, struct ifmap *map);
-static int irda_device_net_change_mtu( struct device *dev, int new_mtu);
-
+static int irda_device_net_set_config(struct device *dev, struct ifmap *map);
+static int irda_device_net_change_mtu(struct device *dev, int new_mtu);
+static int irda_device_net_ioctl(struct device *dev, struct ifreq *rq,int cmd);
 #ifdef CONFIG_PROC_FS
 int irda_device_proc_read( char *buf, char **start, off_t offset, int len, 
 			   int unused);
@@ -74,8 +77,15 @@
 {
 	/* Allocate master array */
 	irda_device = hashbin_new( HB_LOCAL);
-	if ( irda_device == NULL) {
-		printk( KERN_WARNING "IrDA: Can't allocate irda_device hashbin!\n");
+	if (irda_device == NULL) {
+		WARNING("IrDA: Can't allocate irda_device hashbin!\n");
+		return -ENOMEM;
+	}
+
+	dongles = hashbin_new(HB_LOCAL);
+	if (dongles == NULL) {
+		printk(KERN_WARNING 
+		       "IrDA: Can't allocate dongles hashbin!\n");
 		return -ENOMEM;
 	}
 
@@ -92,6 +102,12 @@
 #ifdef CONFIG_NSC_FIR
 	pc87108_init();
 #endif
+#ifdef CONFIG_TOSHIBA_FIR
+	toshoboe_init();
+#endif
+#ifdef CONFIG_SMC_IRCC_FIR
+	ircc_init();
+#endif
 #ifdef CONFIG_ESI_DONGLE
 	esi_init();
 #endif
@@ -104,6 +120,10 @@
 #ifdef CONFIG_GIRBIL_DONGLE
 	girbil_init();
 #endif
+#ifdef CONFIG_GIRBIL_DONGLE
+	litelink_init();
+#endif
+
 	return 0;
 }
 
@@ -113,6 +133,7 @@
 
 	ASSERT(irda_device != NULL, return;);
 
+	hashbin_delete(dongles, NULL);
 	hashbin_delete(irda_device, (FREE_FUNC) irda_device_close);
 }
 
@@ -155,6 +176,8 @@
 	/* Initialize timers */
 	init_timer(&self->media_busy_timer);	
 
+	self->lock = SPIN_LOCK_UNLOCKED;
+
 	/* A pointer to the low level implementation */
 	self->priv = priv;
 
@@ -186,7 +209,7 @@
 	/* Open network device */
 	dev_open(&self->netdev);
 
-	MESSAGE("IrDA: Registred device %s\n", self->name);
+	MESSAGE("IrDA: Registered device %s\n", self->name);
 
 	irda_device_set_media_busy(self, FALSE);
 
@@ -238,7 +261,7 @@
 /*
  * Function irda_device_close (self)
  *
- *    
+ *    Close the device
  *
  */
 void irda_device_close(struct irda_device *self)
@@ -248,6 +271,10 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
 
+	/* We are not using any dongle anymore! */
+	if (self->dongle)
+		self->dongle->close(self);
+
 	/* Stop and remove instance of IrLAP */
 	if (self->irlap)
 		irlap_close(self->irlap);
@@ -289,6 +316,8 @@
  */
 static void __irda_device_change_speed(struct irda_device *self, int speed)
 {
+	int n = 0;
+
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
 	
@@ -296,18 +325,37 @@
 	 *  Is is possible to change speed yet? Wait until the last byte 
 	 *  has been transmitted.
 	 */
-	if (self->wait_until_sent) {
-		self->wait_until_sent(self);
-		if (self->change_speed) {
-			self->change_speed(self, speed);
+	if (!self->wait_until_sent) {
+		ERROR("IrDA: wait_until_sent() "
+		      "has not implemented by the IrDA device driver!\n");
+		return;
+	}
+
+	/* Make sure all transmitted data has actually been sent */
+	self->wait_until_sent(self);
 
-			/* Update the QoS value only */
-			self->qos.baud_rate.value = speed;
+	/* Make sure nobody tries to transmit during the speed change */
+	while (irda_lock((void *) &self->netdev.tbusy) == FALSE) {
+		WARNING(__FUNCTION__ "(), device locked!\n");
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(MSECS_TO_JIFFIES(10));
+
+		if (n++ > 10) {
+			WARNING(__FUNCTION__ "(), breaking loop!\n");
+			break;
 		}
-	} else {
-		printk(KERN_WARNING "wait_until_sent() "
-		       "has not implemented by the IrDA device driver!\n");
 	}
+	
+	if (self->dongle)
+		self->dongle->change_speed(self, speed);
+	
+	if (self->change_speed) {
+		self->change_speed(self, speed);
+		
+		/* Update the QoS value only */
+		self->qos.baud_rate.value = speed;
+	}
+	self->netdev.tbusy = FALSE;
 }
 
 /*
@@ -318,8 +366,6 @@
  */
 inline void irda_device_change_speed(struct irda_device *self, int speed)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
-
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
 
@@ -330,27 +376,27 @@
 
 inline int irda_device_is_media_busy( struct irda_device *self)
 {
-	ASSERT( self != NULL, return FALSE;);
-	ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	ASSERT(self != NULL, return FALSE;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
 	
 	return self->media_busy;
 }
 
 inline int irda_device_is_receiving( struct irda_device *self)
 {
-	ASSERT( self != NULL, return FALSE;);
-	ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	ASSERT(self != NULL, return FALSE;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
 
-	if ( self->is_receiving)
-		return self->is_receiving( self);
+	if (self->is_receiving)
+		return self->is_receiving(self);
 	else
 		return FALSE;
 }
 
-inline struct qos_info *irda_device_get_qos( struct irda_device *self)
+inline struct qos_info *irda_device_get_qos(struct irda_device *self)
 {
-	ASSERT( self != NULL, return NULL;);
-	ASSERT( self->magic == IRDA_DEVICE_MAGIC, return NULL;);
+	ASSERT(self != NULL, return NULL;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return NULL;);
 
 	return &self->qos;
 }
@@ -372,8 +418,6 @@
 {
 	struct irda_device *self;
 
-	DEBUG(4, __FUNCTION__ "()\n");
-
 	ASSERT(dev != NULL, return -1;);
 
 	self = (struct irda_device *) dev->priv;
@@ -386,6 +430,7 @@
 	dev->set_config      = irda_device_net_set_config;
 	dev->change_mtu      = irda_device_net_change_mtu;
 /*  	dev->hard_header     = irda_device_net_hard_header; */
+	dev->do_ioctl        = irda_device_net_ioctl;
         dev->hard_header_len = 0;
         dev->addr_len        = 0;
 
@@ -444,6 +489,131 @@
      return 0;  
 }
 
+
+#define SIOCSDONGLE     SIOCDEVPRIVATE
+static int irda_device_net_ioctl(struct device *dev, /* ioctl device */
+				 struct ifreq *rq,   /* Data passed */
+				 int	cmd)	     /* Ioctl number */
+{
+	unsigned long flags;
+	int			ret = 0;
+#ifdef WIRELESS_EXT
+	struct iwreq *wrq = (struct iwreq *) rq;
+#endif
+	struct irda_device *self;
+
+	DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = (struct irda_device *) dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+	DEBUG(0, "%s: ->irda_device_net_ioctl(cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	/* Look what is the request */
+	switch (cmd) {
+#ifdef WIRELESS_EXT
+	case SIOCGIWNAME:
+		/* Get name */
+		strcpy(wrq->u.name, self->name);
+		break;
+	case SIOCSIWNWID:
+		/* Set domain */
+		if (wrq->u.nwid.on) {
+			
+		} break;
+	case SIOCGIWNWID:
+		/* Read domain*/
+/* 		wrq->u.nwid.nwid = domain; */
+/* 		wrq->u.nwid.on = 1; */
+		break;
+	case SIOCGIWENCODE:
+		/* Get scramble key */
+		/* 	wrq->u.encoding.code = scramble_key; */
+/* 		wrq->u.encoding.method = 1; */
+		break;
+	case SIOCSIWENCODE:
+		/* Set  scramble key */
+		/* scramble_key = wrq->u.encoding.code; */
+		break;
+	case SIOCGIWRANGE:
+		/* Basic checking... */
+		if(wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_range	range;
+			
+			/* Verify the user buffer */
+			ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
+					  sizeof(struct iw_range));
+			if(ret)
+				break;
+			
+			/* Set the length (useless : its constant...) */
+			wrq->u.data.length = sizeof(struct iw_range);
+			
+			/* Set information in the range struct */
+			range.throughput = 1.6 * 1024 * 1024;	/* don't argue on this ! */
+			range.min_nwid = 0x0000;
+			range.max_nwid = 0x01FF;
+			
+			range.num_channels = range.num_frequency = 0;
+			
+			range.sensitivity = 0x3F;
+			range.max_qual.qual = 255;
+			range.max_qual.level = 255;
+			range.max_qual.noise = 0;
+			
+			/* Copy structure to the user buffer */
+			copy_to_user(wrq->u.data.pointer, &range,
+				     sizeof(struct iw_range));
+		}
+		break;
+	case SIOCGIWPRIV:
+		/* Basic checking... */
+#if 0
+		if (wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_priv_args	priv[] =
+			{	/* cmd,		set_args,	get_args,	name */
+				{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, 
+				  sizeof(struct site_survey), 
+				  "getsitesurvey" },
+			};
+			
+			/* Verify the user buffer */
+			ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
+					  sizeof(priv));
+			if (ret)
+				break;
+			
+			/* Set the number of ioctl available */
+			wrq->u.data.length = 1;
+			
+			/* Copy structure to the user buffer */
+			copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+				     sizeof(priv));
+		}
+#endif 
+		break;
+#endif
+	case SIOCSDONGLE: /* Set dongle */
+		/* Initialize dongle */
+		irda_device_init_dongle(self, (int) rq->ifr_data);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
 /*
  * Function irda_device_transmit_finished (void)
  *
@@ -451,7 +621,7 @@
  *    device. Maybe we should use: q->q.qlen == 0.
  *
  */
-int irda_device_txqueue_empty( struct irda_device *self)
+int irda_device_txqueue_empty(struct irda_device *self)
 {
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);	
@@ -463,6 +633,122 @@
 }
 
 /*
+ * Function irda_device_init_dongle (self, type)
+ *
+ *    Initialize attached dongle. Warning, must be called with a process
+ *    context!
+ */
+void irda_device_init_dongle(struct irda_device *self, int type)
+{
+	struct dongle_q *node;
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+
+#ifdef CONFIG_KMOD
+	/* Try to load the module needed */
+	switch (type) {
+	case ESI_DONGLE:
+		MESSAGE("IrDA: Initializing ESI dongle!\n");
+		request_module("esi");
+		break;
+	case TEKRAM_DONGLE:
+		MESSAGE("IrDA: Initializing Tekram dongle!\n");
+		request_module("tekram");
+		break;
+	case ACTISYS_DONGLE:     /* FALLTHROUGH */
+	case ACTISYS_PLUS_DONGLE:
+		MESSAGE("IrDA: Initializing ACTiSYS dongle!\n");
+		request_module("actisys");
+		break;
+	case GIRBIL_DONGLE:
+		MESSAGE("IrDA: Initializing GIrBIL dongle!\n");
+		request_module("girbil");
+		break;
+	case LITELINK_DONGLE:
+		MESSAGE("IrDA: Initializing Litelink dongle!\n");
+		request_module("litelink");
+		break;
+	default:
+		ERROR("Unknown dongle type!\n");
+		return;
+	}
+#endif /* CONFIG_KMOD */
+
+	node = hashbin_find(dongles, type, NULL);
+	if (!node) {
+		ERROR("IrDA: Unable to find requested dongle\n");
+		return;
+	}
+	
+	/* Check if we're already using a dongle */
+	if (self->dongle) {
+		self->dongle->close(self);
+	}
+
+	/* Set the dongle to be used by this driver */
+	self->dongle = node->dongle;
+
+	/* Now initialize the dongle!  */
+	node->dongle->open(self, type);
+	node->dongle->qos_init(self, &self->qos);
+	
+	/* Reset dongle */
+	node->dongle->reset(self);
+
+	/* Set to default baudrate */
+	irda_device_change_speed(self, 9600);
+}
+
+/*
+ * Function irda_device_register_dongle (dongle)
+ *
+ *    
+ *
+ */
+int irda_device_register_dongle(struct dongle *dongle)
+{
+	struct dongle_q *new;
+	
+	/* Check if this dongle has been registred before */
+	if (hashbin_find(dongles, dongle->type, NULL)) {
+		MESSAGE(__FUNCTION__ "(), Dongle already registered\n");
+                return 0;
+        }
+	
+	/* Make new IrDA dongle */
+        new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
+        if (new == NULL)
+                return -1;
+		
+	memset(new, 0, sizeof( struct dongle_q));
+        new->dongle = dongle;
+
+	/* Insert IrDA dongle into hashbin */
+	hashbin_insert(dongles, (QUEUE *) new, dongle->type, NULL);
+	
+        return 0;
+}
+
+/*
+ * Function irda_device_unregister_dongle (dongle)
+ *
+ *    
+ *
+ */
+void irda_device_unregister_dongle(struct dongle *dongle)
+{
+	struct dongle_q *node;
+
+	node = hashbin_remove(dongles, dongle->type, NULL);
+	if (!node) {
+		ERROR(__FUNCTION__ "(), dongle not found!\n");
+		return;
+	}
+	kfree(node);
+}
+
+/*
  * Function setup_dma (idev, buffer, count, mode)
  *
  *    Setup the DMA channel
@@ -536,7 +822,7 @@
 
 	self = (struct irda_device *) hashbin_get_first(irda_device);
 	while ( self != NULL) {
-		len += sprintf(buf+len, "%s,", self->name);
+		len += sprintf(buf+len, "\n%s,", self->name);
 		len += sprintf(buf+len, "\tbinding: %s\n", 
 			       self->description);
 		

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