patch-2.2.15 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 --new-file --recursive --exclude-from ../../exclude v2.2.14/net/irda/irda_device.c linux/net/irda/irda_device.c
@@ -1,28 +1,35 @@
 /*********************************************************************
  *                
  * Filename:      irda_device.c
- * Version:       0.5
- * Description:   Abstract device driver layer and helper functions
+ * Version:       0.9
+ * Description:   Utility functions used by the device drivers
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Tue Jun  1 09:05:13 1999
+ * Created at:    Sat Oct  9 09:22:27 1999
+ * Modified at:   Wed Mar  1 11:00:34 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- *      
+ *     Copyright (c) 1999-2000 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 
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
- *  
- *     Neither Dag Brattli nor University of Tromsų admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License 
+ *     along with this program; if not, write to the Free Software 
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
  *     
  ********************************************************************/
 
 #include <linux/config.h>
+#include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
 #include <linux/if.h>
@@ -33,59 +40,75 @@
 #include <linux/tty.h>
 #include <linux/kmod.h>
 #include <linux/wireless.h>
+#include <asm/spinlock.h>
 
 #include <asm/ioctls.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
-#include <asm/spinlock.h>
+#include <asm/io.h>
 
 #include <net/pkt_sched.h>
 
 #include <net/irda/irda_device.h>
-#include <net/irda/irlap_frame.h>
+#include <net/irda/irlap.h>
 #include <net/irda/timer.h>
 #include <net/irda/wrapper.h>
 
 extern int irtty_init(void);
-extern int pc87108_init(void);
+extern int nsc_ircc_init(void);
+extern int ircc_init(void);
 extern int w83977af_init(void);
 extern int esi_init(void);
 extern int tekram_init(void);
 extern int actisys_init(void);
 extern int girbil_init(void);
 
-static hashbin_t *irda_device = NULL;
+static void __irda_task_delete(struct irda_task *task);
+
 static hashbin_t *dongles = NULL;
+static hashbin_t *tasks = NULL;
+
+const char *infrared_mode[] = {
+	"IRDA_IRLAP",
+	"IRDA_RAW",
+	"SHARP_ASK",
+	"TV_REMOTE",
+};
+
+static const char *task_state[] = {
+	"IRDA_TASK_INIT",
+	"IRDA_TASK_DONE", 
+	"IRDA_TASK_WAIT",
+	"IRDA_TASK_WAIT1",
+	"IRDA_TASK_WAIT2",
+	"IRDA_TASK_WAIT3",
+	"IRDA_TASK_CHILD_INIT",
+	"IRDA_TASK_CHILD_WAIT",
+	"IRDA_TASK_CHILD_DONE",
+};
+
+static void irda_task_timer_expired(void *data);
 
-/* Netdevice functions */
-static int irda_device_net_rebuild_header(struct sk_buff *skb);
-static int irda_device_net_hard_header(struct sk_buff *skb, 
-				       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_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);
+int irda_device_proc_read(char *buf, char **start, off_t offset, int len, 
+			  int unused);
 
 #endif /* CONFIG_PROC_FS */
 
-__initfunc(int irda_device_init( void))
+int __init irda_device_init( void)
 {
-	/* Allocate master array */
-	irda_device = hashbin_new( HB_LOCAL);
-	if (irda_device == NULL) {
-		WARNING("IrDA: Can't allocate irda_device hashbin!\n");
+	dongles = hashbin_new(HB_GLOBAL);
+	if (dongles == NULL) {
+		printk(KERN_WARNING 
+		       "IrDA: Can't allocate dongles hashbin!\n");
 		return -ENOMEM;
 	}
 
-	dongles = hashbin_new(HB_LOCAL);
-	if (dongles == NULL) {
+	tasks = hashbin_new(HB_GLOBAL);
+	if (tasks == NULL) {
 		printk(KERN_WARNING 
-		       "IrDA: Can't allocate dongles hashbin!\n");
+		       "IrDA: Can't allocate tasks hashbin!\n");
 		return -ENOMEM;
 	}
 
@@ -100,7 +123,7 @@
 	w83977af_init();
 #endif
 #ifdef CONFIG_NSC_FIR
-	pc87108_init();
+	nsc_ircc_init();
 #endif
 #ifdef CONFIG_TOSHIBA_FIR
 	toshoboe_init();
@@ -123,289 +146,263 @@
 #ifdef CONFIG_LITELINK_DONGLE
 	litelink_init();
 #endif
-
+#ifdef CONFIG_OLD_BELKIN
+ 	old_belkin_init();
+#endif
 	return 0;
 }
 
 void irda_device_cleanup(void)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(irda_device != NULL, return;);
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
+	hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
 	hashbin_delete(dongles, NULL);
-	hashbin_delete(irda_device, (FREE_FUNC) irda_device_close);
 }
 
 /*
- * Function irda_device_open (self)
- *
- *    Open a new IrDA port device
+ * Function irda_device_set_media_busy (self, status)
  *
+ *    Called when we have detected that another station is transmiting
+ *    in contention mode.
  */
-int irda_device_open(struct irda_device *self, char *name, void *priv)
-{        
-	int result;
-	int i=0;
+void irda_device_set_media_busy(struct device *dev, int status) 
+{
+	struct irlap_cb *self;
 
-	/* Allocate memory if needed */
-	if (self->rx_buff.truesize > 0) {
-		self->rx_buff.head = ( __u8 *) kmalloc(self->rx_buff.truesize,
-						       self->rx_buff.flags);
-		if (self->rx_buff.head == NULL)
-			return -ENOMEM;
+	IRDA_DEBUG(4, __FUNCTION__ "(%s)\n", status ? "TRUE" : "FALSE");
 
-		memset(self->rx_buff.head, 0, self->rx_buff.truesize);
-	}
-	if (self->tx_buff.truesize > 0) {
-		self->tx_buff.head = ( __u8 *) kmalloc(self->tx_buff.truesize, 
-						       self->tx_buff.flags);
-		if (self->tx_buff.head == NULL)
-			return -ENOMEM;
+	self = (struct irlap_cb *) dev->atalk_ptr;
 
-		memset(self->tx_buff.head, 0, self->tx_buff.truesize);
-	}
-	
-      	self->magic = IRDA_DEVICE_MAGIC;
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	self->rx_buff.in_frame = FALSE;
-	self->rx_buff.state = OUTSIDE_FRAME;
-	self->tx_buff.data = self->tx_buff.head;
-	self->rx_buff.data = self->rx_buff.head;
+	if (status) {
+		self->media_busy = TRUE;
+		irlap_start_mbusy_timer(self);
+		IRDA_DEBUG( 4, "Media busy!\n");
+	} else {
+		self->media_busy = FALSE;
+		del_timer(&self->media_busy_timer);
+	}
+}
 
-	/* Initialize timers */
-	init_timer(&self->media_busy_timer);	
+int irda_device_set_dtr_rts(struct device *dev, int dtr, int rts)
+{	
+	struct if_irda_req req;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
+		      "device driver\n");
+		return -1;
+	}
 
-	self->lock = SPIN_LOCK_UNLOCKED;
+	req.ifr_dtr = dtr;
+	req.ifr_rts = rts;
 
-	/* A pointer to the low level implementation */
-	self->priv = priv;
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSDTRRTS);
 
-	/* Initialize IrDA net device */
-	do {
-		sprintf(self->name, "%s%d", "irda", i++);
-	} while (dev_get(self->name) != NULL);
-	
-	self->netdev.name = self->name;
-	self->netdev.priv = (void *) self;
-	self->netdev.next = NULL;
+	return ret;
+}
 
-	if ((result = register_netdev(&self->netdev)) != 0) {
-		DEBUG(0, __FUNCTION__ "(), register_netdev() failed!\n");
+int irda_device_change_speed(struct device *dev, __u32 speed)
+{	
+	struct if_irda_req req;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
+		      "device driver\n");
 		return -1;
 	}
-	
-	/* 
-	 * Make the description for the device. self->netdev.name will get
-	 * a name like "irda0" and the self->descriptin will get a name
-	 * like "irda0 <-> irtty0" 
-	 */
-	strncpy(self->description, self->name, 5);
-	strcat(self->description, " <-> ");
-	strncat(self->description, name, 23);
-	
-	hashbin_insert(irda_device, (QUEUE *) self, (int) self, NULL);
-	
-	/* Open network device */
-	dev_open(&self->netdev);
 
-	MESSAGE("IrDA: Registered device %s\n", self->name);
+	req.ifr_baudrate = speed;
 
-	irda_device_set_media_busy(self, FALSE);
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSBANDWIDTH);
 
-	/* 
-	 * Open new IrLAP layer instance, now that everything should be
-	 * initialized properly 
-	 */
-	self->irlap = irlap_open(self);
-        
-	/* It's now safe to initilize the saddr */
-	memcpy(self->netdev.dev_addr, &self->irlap->saddr, 4);
-
-	return 0;
+	return ret;
 }
 
 /*
- * Function irda_device_close (self)
+ * Function irda_device_is_receiving (dev)
  *
- *    Close this instance of the irda_device, just deallocate buffers
+ *    Check if the device driver is currently receiving data
  *
  */
-void __irda_device_close(struct irda_device *self)
+int irda_device_is_receiving(struct device *dev)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
+	struct if_irda_req req;
+	int ret;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	/* We do this test to know if the device has been registered at all */
-	if (self->netdev.type == ARPHRD_IRDA) {
-		dev_close(&self->netdev);
-		
-		/* Remove netdevice */
-		unregister_netdev(&self->netdev);
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
+		      "device driver\n");
+		return -1;
 	}
 
-	/* Stop timers */
-	del_timer(&self->media_busy_timer);
-
-	if (self->tx_buff.head)
-		kfree(self->tx_buff.head);
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCGRECEIVING);
+	if (ret < 0)
+		return ret;
 
-	if (self->rx_buff.head)
-		kfree(self->rx_buff.head);
-
-	self->magic = 0;
+	return req.ifr_receiving;
 }
 
-/*
- * Function irda_device_close (self)
- *
- *    Close the device
- *
- */
-void irda_device_close(struct irda_device *self)
+void irda_task_next_state(struct irda_task *task, TASK_STATE state)
 {
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+	IRDA_DEBUG(2, __FUNCTION__ "(), state = %s\n", task_state[state]);
 
-	/* 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);
-	self->irlap = NULL;
-
-	hashbin_remove(irda_device, (int) self, NULL);
-
-	__irda_device_close(self);
+	task->state = state;
 }
 
-/*
- * Function irda_device_set_media_busy (self, status)
- *
- *    Called when we have detected that another station is transmiting
- *    in contention mode.
- */
-void irda_device_set_media_busy(struct irda_device *self, int status) 
+static void __irda_task_delete(struct irda_task *task)
 {
-	DEBUG(4, __FUNCTION__ "(%s)\n", status ? "TRUE" : "FALSE");
+	del_timer(&task->timer);
+	
+	kfree(task);
+}
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+void irda_task_delete(struct irda_task *task)
+{
+	/* Unregister task */
+	hashbin_remove(tasks, (int) task, NULL);
 
-	if (status) {
-		self->media_busy = TRUE;
-		irda_device_start_mbusy_timer(self);
-		DEBUG( 4, "Media busy!\n");
-	} else {
-		self->media_busy = FALSE;
-		del_timer(&self->media_busy_timer);
-	}
+	__irda_task_delete(task);
 }
 
 /*
- * Function __irda_device_change_speed (self, speed)
+ * Function irda_task_kick (task)
  *
- *    When this function is called, we will have a process context so its
- *    possible for us to sleep, wait or whatever :-)
+ *    Tries to execute a task possible multiple times until the task is either
+ *    finished, or askes for a timeout. When a task is finished, we do post
+ *    processing, and notify the parent task, that is waiting for this task
+ *    to complete.
  */
-static void __irda_device_change_speed(struct irda_device *self, int speed)
+int irda_task_kick(struct irda_task *task)
 {
-	int n = 0;
+	int finished = TRUE;
+	int count = 0;
+	int timeout;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
-	
-	/*
-	 *  Is is possible to change speed yet? Wait until the last byte 
-	 *  has been transmitted.
-	 */
-	if (!self->wait_until_sent) {
-		ERROR("IrDA: wait_until_sent() "
-		      "has not implemented by the IrDA device driver!\n");
-		return;
-	}
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	/* Make sure all transmitted data has actually been sent */
-	self->wait_until_sent(self);
+	ASSERT(task != NULL, return -1;);
+	ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
 
-	/* 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;
-		}
-	}
-	
-	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;
+	/* Execute task until it's finished, or askes for a timeout */
+	do {
+		timeout = task->function(task);
+		if (count++ > 100) {
+			ERROR(__FUNCTION__ "(), error in task handler!\n");
+			irda_task_delete(task);
+			return TRUE;
+		}			
+	} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
+
+	if (timeout < 0) {
+		ERROR(__FUNCTION__ "(), Error executing task!\n");
+		irda_task_delete(task);
+		return TRUE;
+	}
+
+	/* Check if we are finished */
+	if (task->state == IRDA_TASK_DONE) {
+		del_timer(&task->timer);
+
+		/* Do post processing */
+		if (task->finished)
+			task->finished(task);
+
+		/* Notify parent */
+		if (task->parent) {
+			/* Check if parent is waiting for us to complete */
+			if (task->parent->state == IRDA_TASK_CHILD_WAIT) {
+				task->parent->state = IRDA_TASK_CHILD_DONE;
+
+				/* Stop timer now that we are here */
+				del_timer(&task->parent->timer);
+
+				/* Kick parent task */
+				irda_task_kick(task->parent);
+			}
+		}		
+		irda_task_delete(task);
+	} else if (timeout > 0) {
+		irda_start_timer(&task->timer, timeout, (void *) task, 
+				 irda_task_timer_expired);
+		finished = FALSE;
+	} else {
+		IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), not finished, and no timeout!\n");
+		finished = FALSE;
 	}
-	self->netdev.tbusy = FALSE;
+
+	return finished;
 }
 
 /*
- * Function irda_device_change_speed (self, speed)
- *
- *    Change the speed of the currently used irda_device
+ * Function irda_task_execute (instance, function, finished)
  *
+ *    This function registers and tries to execute tasks that may take some
+ *    time to complete. We do it this hairy way since we may have been
+ *    called from interrupt context, so it's not possible to use
+ *    schedule_timeout() 
  */
-inline void irda_device_change_speed(struct irda_device *self, int speed)
+struct irda_task *irda_task_execute(void *instance, TASK_CALLBACK function, 
+				    TASK_CALLBACK finished, 
+				    struct irda_task *parent, void *param)
 {
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+	struct irda_task *task;
+	int ret;
 
-	irda_execute_as_process(self, 
-				(TODO_CALLBACK) __irda_device_change_speed, 
-				speed);
-}
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-inline int irda_device_is_media_busy( struct irda_device *self)
-{
-	ASSERT(self != NULL, return FALSE;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
-	
-	return self->media_busy;
-}
+	task = kmalloc(sizeof(struct irda_task), GFP_ATOMIC);
+	if (!task)
+		return NULL;
 
-inline int irda_device_is_receiving( struct irda_device *self)
-{
-	ASSERT(self != NULL, return FALSE;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	task->state    = IRDA_TASK_INIT;
+	task->instance = instance;
+	task->function = function;
+	task->finished = finished;
+	task->parent   = parent;
+	task->param    = param;	
+	task->magic    = IRDA_TASK_MAGIC;
+
+	init_timer(&task->timer);
+
+	/* Register task */
+	hashbin_insert(tasks, (queue_t *) task, (int) task, NULL);
 
-	if (self->is_receiving)
-		return self->is_receiving(self);
+	/* No time to waste, so lets get going! */
+	ret = irda_task_kick(task);
+	if (ret)
+		return NULL;
 	else
-		return FALSE;
+		return task;
 }
 
-inline struct qos_info *irda_device_get_qos(struct irda_device *self)
+/*
+ * Function irda_task_timer_expired (data)
+ *
+ *    Task time has expired. We now try to execute task (again), and restart
+ *    the timer if the task has not finished yet
+ */
+static void irda_task_timer_expired(void *data)
 {
-	ASSERT(self != NULL, return NULL;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return NULL;);
+	struct irda_task *task;
 
-	return &self->qos;
-}
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-static struct enet_statistics *irda_device_get_stats( struct device *dev)
-{
-	struct irda_device *priv = (struct irda_device *) dev->priv;
+	task = (struct irda_task *) data;
 
-	return &priv->stats;
+	irda_task_kick(task);
 }
 
 /*
@@ -416,24 +413,14 @@
  */
 int irda_device_setup(struct device *dev) 
 {
-	struct irda_device *self;
-
 	ASSERT(dev != NULL, return -1;);
 
-	self = (struct irda_device *) dev->priv;
-
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);	
-
-	dev->get_stats	     = irda_device_get_stats;
-	dev->rebuild_header  = irda_device_net_rebuild_header;
-	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;
 
+	/* dev->new_style       = 1; */
+	/* dev->destructor      = irda_device_destructor; */
+
         dev->type            = ARPHRD_IRDA;
         dev->tx_queue_len    = 8; /* Window size + 1 s-frame */
  
@@ -450,254 +437,73 @@
 }
 
 /*
- * Function irda_device_net_rebuild_header (buff, dev, dst, skb)
- *
- *    
- *
- */
-static int irda_device_net_rebuild_header( struct sk_buff *skb)
-{
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	return 0;
-}
-
-static int irda_device_net_hard_header(struct sk_buff *skb, struct device *dev,
-				       unsigned short type, void *daddr, 
-				       void *saddr, unsigned len)
-{
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-	skb->mac.raw = skb->data;
-        /* skb_push(skb,PPP_HARD_HDR_LEN); */
-        /* return PPP_HARD_HDR_LEN; */
-	
-	return 0;
-}
-
-static int irda_device_net_set_config( struct device *dev, struct ifmap *map)
-{
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-	return 0;
-}
-
-static int irda_device_net_change_mtu( struct device *dev, int new_mtu)
-{
-     DEBUG( 0, __FUNCTION__ "()\n");
-     
-     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.disabled) {
-			
-		} break;
-	case SIOCGIWNWID:
-		/* Read domain*/
-/* 		wrq->u.nwid.nwid = domain; */
-/* 		wrq->u.nwid.disabled = 0; */
-		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)
+ * Function irda_device_txqueue_empty (dev)
  *
  *    Check if there is still some frames in the transmit queue for this
  *    device. Maybe we should use: q->q.qlen == 0.
  *
  */
-int irda_device_txqueue_empty(struct irda_device *self)
+int irda_device_txqueue_empty(struct device *dev)
 {
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);	
-
-	if (skb_queue_len(&self->netdev.qdisc->q))
+	if (skb_queue_len(&dev->qdisc->q))
 		return FALSE;
 
 	return TRUE;
 }
 
 /*
- * Function irda_device_init_dongle (self, type)
+ * Function irda_device_init_dongle (self, type, qos)
  *
- *    Initialize attached dongle. Warning, must be called with a process
- *    context!
+ *    Initialize attached dongle.
  */
-void irda_device_init_dongle(struct irda_device *self, int type)
+dongle_t *irda_device_dongle_init(struct device *dev, int type)
 {
-	struct dongle_q *node;
+	struct dongle_reg *reg;
+	char modname[32];
+	dongle_t *dongle;
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(dev != NULL, return NULL;);
 
 #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;
-	}
+	sprintf(modname, "irda-dongle-%d", type);
+	request_module(modname);
 #endif /* CONFIG_KMOD */
 
-	node = hashbin_find(dongles, type, NULL);
-	if (!node) {
+	if (!(reg = hashbin_find(dongles, type, NULL))) {
 		ERROR("IrDA: Unable to find requested dongle\n");
-		return;
-	}
-	
-	/* Check if we're already using a dongle */
-	if (self->dongle) {
-		self->dongle->close(self);
+		return NULL;
 	}
 
-	/* Set the dongle to be used by this driver */
-	self->dongle = node->dongle;
+	/* Allocate dongle info for this instance */
+	dongle = kmalloc(sizeof(dongle_t), GFP_KERNEL);
+	if (!dongle)
+		return NULL;
 
-	/* Now initialize the dongle!  */
-	node->dongle->open(self, type);
-	node->dongle->qos_init(self, &self->qos);
-	
-	/* Reset dongle */
-	node->dongle->reset(self);
+	memset(dongle, 0, sizeof(dongle_t));
+
+	/* Bind the registration info to this particular instance */
+	dongle->issue = reg;
+	dongle->dev = dev;
+
+	return dongle;
+}
+
+/*
+ * Function irda_device_dongle_cleanup (dongle)
+ *
+ *    
+ *
+ */
+int irda_device_dongle_cleanup(dongle_t *dongle)
+{
+	ASSERT(dongle != NULL, return -1;);
+
+	dongle->issue->close(dongle);
+
+	kfree(dongle);
 
-	/* Set to default baudrate */
-	irda_device_change_speed(self, 9600);
+	return 0;
 }
 
 /*
@@ -706,26 +512,16 @@
  *    
  *
  */
-int irda_device_register_dongle(struct dongle *dongle)
+int irda_device_register_dongle(struct dongle_reg *new)
 {
-	struct dongle_q *new;
-	
 	/* Check if this dongle has been registred before */
-	if (hashbin_find(dongles, dongle->type, NULL)) {
+	if (hashbin_find(dongles, new->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);
+	hashbin_insert(dongles, (queue_t *) new, new->type, NULL);
 	
         return 0;
 }
@@ -733,25 +529,51 @@
 /*
  * Function irda_device_unregister_dongle (dongle)
  *
- *    
+ *    Unregister dongle, and remove dongle from list of registred dongles
  *
  */
-void irda_device_unregister_dongle(struct dongle *dongle)
+void irda_device_unregister_dongle(struct dongle_reg *dongle)
 {
-	struct dongle_q *node;
+	struct dongle *node;
 
 	node = hashbin_remove(dongles, dongle->type, NULL);
 	if (!node) {
 		ERROR(__FUNCTION__ "(), dongle not found!\n");
 		return;
 	}
-	kfree(node);
+}
+
+/*
+ * Function irda_device_set_mode (self, mode)
+ *
+ *    Set the Infrared device driver into mode where it sends and receives
+ *    data without using IrLAP framing. Check out the particular device
+ *    driver to find out which modes it support.
+ */
+int irda_device_set_mode(struct device* dev, int mode)
+{	
+	struct if_irda_req req;
+	int ret;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	if (!dev->do_ioctl) {
+		ERROR(__FUNCTION__ "(), set_raw_mode not impl. by "
+		      "device driver\n");
+		return -1;
+	}
+	
+	req.ifr_mode = mode;
+
+	ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSMODE);
+	
+	return ret;
 }
 
 /*
  * Function setup_dma (idev, buffer, count, mode)
  *
- *    Setup the DMA channel
+ *    Setup the DMA channel. Commonly used by ISA FIR drivers
  *
  */
 void setup_dma(int channel, char *buffer, int count, int mode)
@@ -769,88 +591,3 @@
 
 	release_dma_lock(flags);
 }
-
-#ifdef CONFIG_PROC_FS
-
-int irda_device_print_flags(struct irda_device *idev, char *buf)
-{
-	int len=0;
-
-	len += sprintf( buf+len, "\t");
-
-	if (idev->netdev.flags & IFF_UP)
-		len += sprintf( buf+len, "UP ");
-	if (!idev->netdev.tbusy)
-		len += sprintf( buf+len, "RUNNING ");
-
-	if (idev->flags & IFF_SIR)
-		len += sprintf( buf+len, "SIR ");
-	if (idev->flags & IFF_MIR)
-		len += sprintf( buf+len, "MIR ");
-	if (idev->flags & IFF_FIR)
-		len += sprintf( buf+len, "FIR ");
-	if (idev->flags & IFF_PIO)
-		len += sprintf( buf+len, "PIO ");
-	if (idev->flags & IFF_DMA)
-		len += sprintf( buf+len, "DMA ");
-	if (idev->flags & IFF_SHM)
-		len += sprintf( buf+len, "SHM ");
-	if (idev->flags & IFF_DONGLE)
-		len += sprintf( buf+len, "DONGLE ");
-
-	len += sprintf( buf+len, "\n");
-
-	return len;
-}
-
-/*
- * Function irda_device_proc_read (buf, start, offset, len, unused)
- *
- *    Give some info to the /proc file system
- *
- */
-int irda_device_proc_read(char *buf, char **start, off_t offset, int len, 
-			  int unused)
-{
-	struct irda_device *self;
-	unsigned long flags;
-     
-	save_flags(flags);
-	cli();
-
-	len = 0;
-
-	self = (struct irda_device *) hashbin_get_first(irda_device);
-	while ( self != NULL) {
-		len += sprintf(buf+len, "\n%s,", self->name);
-		len += sprintf(buf+len, "\tbinding: %s\n", 
-			       self->description);
-		
-		len += irda_device_print_flags(self, buf+len);
-		len += sprintf(buf+len, "\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\n");
-		
-		len += sprintf(buf+len, "\t%d\t", 
-			       self->qos.baud_rate.value);
-		len += sprintf(buf+len, "%d\t", 
-			       self->qos.max_turn_time.value);
-		len += sprintf(buf+len, "%d\t",
-			       self->qos.data_size.value);
-		len += sprintf(buf+len, "%d\t",
-			       self->qos.window_size.value);
-		len += sprintf(buf+len, "%d\t",
-			       self->qos.additional_bofs.value);
-		len += sprintf(buf+len, "%d\t", 
-			       self->qos.min_turn_time.value);
-		len += sprintf(buf+len, "%d", 
-			       self->qos.link_disc_time.value);
-		len += sprintf(buf+len, "\n");
-		
-		self = (struct irda_device *) hashbin_get_next(irda_device);
-	}
-	restore_flags(flags);
-
-	return len;
-}
-
-#endif /* CONFIG_PROC_FS */
-

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