diff -u -p -r linux/include/net/irda-d6/irtty.h linux/include/net/irda/irtty.h
--- linux/include/net/irda-d6/irtty.h	Sat Jun  8 22:31:17 2002
+++ linux/include/net/irda/irtty.h	Fri Aug 23 13:40:59 2002
@@ -62,6 +62,9 @@ struct irtty_cb {
 	struct qos_info qos;       /* QoS capabilities for this device */
 	dongle_t *dongle;          /* Dongle driver */
 
+
+	spinlock_t lock;           /* For serializing operations */
+
 	__u32 new_speed;
  	__u32 flags;               /* Interface flags */
 
diff -u -p -r linux/include/net/irda-d6/smc-ircc.h linux/include/net/irda/smc-ircc.h
--- linux/include/net/irda-d6/smc-ircc.h	Sat Jun  8 22:27:46 2002
+++ linux/include/net/irda/smc-ircc.h	Fri Aug 23 15:21:45 2002
@@ -165,7 +165,9 @@ struct ircc_cb {
 
 	struct irport_cb *irport;
 
-	spinlock_t lock;           /* For serializing operations */
+	/* Locking : half of our operations are done with irport, so we
+	 * use the irport spinlock to make sure *everything* is properly
+	 * synchronised - Jean II */
 	
 	__u32 new_speed;
 	__u32 flags;               /* Interface flags */
diff -u -p -r linux/include/net/irda-d6/w83977af_ir.h linux/include/net/irda/w83977af_ir.h
--- linux/include/net/irda-d6/w83977af_ir.h	Sat Jun  8 22:26:53 2002
+++ linux/include/net/irda/w83977af_ir.h	Fri Aug 23 11:56:39 2002
@@ -179,6 +179,11 @@ struct w83977af_ir {
 	chipio_t io;               /* IrDA controller information */
 	iobuff_t tx_buff;          /* Transmit buffer */
 	iobuff_t rx_buff;          /* Receive buffer */
+
+	/* Note : currently locking is *very* incomplete, but this
+	 * will get you started. Check in nsc-ircc.c for a proper
+	 * locking strategy. - Jean II */
+	spinlock_t lock;           /* For serializing operations */
 	
 	__u32 flags;               /* Interface flags */
 	__u32 new_speed;
diff -u -p -r linux/drivers/net/irda-d6/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- linux/drivers/net/irda-d6/irda-usb.c	Mon Aug 19 14:43:27 2002
+++ linux/drivers/net/irda/irda-usb.c	Wed Aug 21 16:27:54 2002
@@ -1171,7 +1171,7 @@ static inline int irda_usb_open(struct i
 	irda_usb_init_qos(self);
 	
 	/* Initialise list of skb beeing curently transmitted */
-	self->tx_list = hashbin_new(HB_GLOBAL);
+	self->tx_list = hashbin_new(HB_NOLOCK);	/* unused */
 
 	/* Allocate the buffer for speed changes */
 	/* Don't change this buffer size and allocation without doing
diff -u -p -r linux/drivers/net/irda-d6/irport.c linux/drivers/net/irda/irport.c
--- linux/drivers/net/irda-d6/irport.c	Mon Aug 19 14:41:00 2002
+++ linux/drivers/net/irda/irport.c	Thu Aug 29 10:20:47 2002
@@ -140,7 +140,7 @@ irport_open(int i, unsigned int iobase, 
 	void *ret;
 	int err;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	/*
 	 *  Allocate new instance of the driver
@@ -284,14 +284,13 @@ int irport_close(struct irport_cb *self)
 
 void irport_start(struct irport_cb *self)
 {
-	unsigned long flags;
 	int iobase;
 
 	iobase = self->io.sir_base;
 
 	irport_stop(self);
 	
-	spin_lock_irqsave(&self->lock, flags);
+	/* We can't lock, we may be called from a FIR driver - Jean II */
 
 	/* Initialize UART */
 	outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
@@ -299,26 +298,21 @@ void irport_start(struct irport_cb *self
 	
 	/* Turn on interrups */
 	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
-
-	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 void irport_stop(struct irport_cb *self)
 {
-	unsigned long flags;
 	int iobase;
 
 	iobase = self->io.sir_base;
 
-	spin_lock_irqsave(&self->lock, flags);
+	/* We can't lock, we may be called from a FIR driver - Jean II */
 
 	/* Reset UART */
 	outb(0, iobase+UART_MCR);
 	
 	/* Turn off interrupts */
 	outb(0, iobase+UART_IER);
-
-	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*
@@ -339,27 +333,28 @@ int irport_probe(int iobase)
  *
  *    Set speed of IrDA port to specified baudrate
  *
+ * This function should be called with irq off and spin-lock.
  */
 void irport_change_speed(void *priv, __u32 speed)
 {
 	struct irport_cb *self = (struct irport_cb *) priv;
-	unsigned long flags;
 	int iobase; 
 	int fcr;    /* FIFO control reg */
 	int lcr;    /* Line control reg */
 	int divisor;
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
-
 	ASSERT(self != NULL, return;);
 
+	IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n",
+		    __FUNCTION__, speed, self->io.sir_base);
+
+	/* We can't lock, we may be called from a FIR driver - Jean II */
+
 	iobase = self->io.sir_base;
 	
 	/* Update accounting for new speed */
 	self->io.speed = speed;
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Turn off interrupts */
 	outb(0, iobase+UART_IER); 
 
@@ -387,9 +382,9 @@ void irport_change_speed(void *priv, __u
 	outb(fcr,		  iobase+UART_FCR); /* Enable FIFO's */
 
 	/* Turn on interrups */
-	outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
-
-	spin_unlock_irqrestore(&self->lock, flags);
+	/* This will generate a fata interrupt storm.
+	 * People calling us will do that properly - Jean II */
+	//outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
 }
 
 /*
@@ -397,11 +392,14 @@ void irport_change_speed(void *priv, __u
  *
  *    State machine for changing speed of the device. We do it this way since
  *    we cannot use schedule_timeout() when we are in interrupt context
+ *
  */
 int __irport_change_speed(struct irda_task *task)
 {
 	struct irport_cb *self;
 	__u32 speed = (__u32) task->param;
+	unsigned long flags = 0;
+	int wasunlocked = 0;
 	int ret = 0;
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); 
@@ -410,6 +408,17 @@ int __irport_change_speed(struct irda_ta
 
 	ASSERT(self != NULL, return -1;);
 
+	/* Locking notes : this function may be called from irq context with
+	 * spinlock, via irport_write_wakeup(), or from non-interrupt without
+	 * spinlock (from the task timer). Yuck !
+	 * This is ugly, and unsafe is the spinlock is not already aquired.
+	 * This will be fixed when irda-task get rewritten.
+	 * Jean II */
+	if (!spin_is_locked(&self->lock)) {
+		spin_lock_irqsave(&self->lock, flags);
+		wasunlocked = 1;
+	}
+
 	switch (task->state) {
 	case IRDA_TASK_INIT:
 	case IRDA_TASK_WAIT:
@@ -462,6 +471,11 @@ int __irport_change_speed(struct irda_ta
 		ret = -1;
 		break;
 	}	
+	/* Put stuff in the sate we found them - Jean II */
+	if(wasunlocked) {
+		spin_unlock_irqrestore(&self->lock, flags);
+	}
+
 	return ret;
 }
 
@@ -491,6 +505,9 @@ static void irport_write_wakeup(struct i
 				      self->tx_buff.data, self->tx_buff.len);
 		self->tx_buff.data += actual;
 		self->tx_buff.len  -= actual;
+
+		/* Turn on transmit finished interrupt. */
+		outb(UART_IER_THRI, iobase+UART_IER); 
 	} else {
 		/* 
 		 *  Now serial buffer is almost free & we can start 
@@ -498,11 +515,12 @@ static void irport_write_wakeup(struct i
 		 *  if we need to change the speed of the hardware
 		 */
 		if (self->new_speed) {
-			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
+			IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__);
 			irda_task_execute(self, __irport_change_speed, 
 					  irport_change_speed_complete, 
 					  NULL, (void *) self->new_speed);
 			self->new_speed = 0;
+			IRDA_DEBUG(5, "%s(), Speed changed!\n", __FUNCTION__ );
 		} else {
 			/* Tell network layer that we want more frames */
 			netif_wake_queue(self->netdev);
@@ -563,7 +581,7 @@ static int irport_change_speed_complete(
 {
 	struct irport_cb *self;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	self = (struct irport_cb *) task->instance;
 
@@ -589,13 +607,19 @@ static void irport_timeout(struct net_de
 {
 	struct irport_cb *self;
 	int iobase;
+	unsigned long flags;
 
 	self = (struct irport_cb *) dev->priv;
 	iobase = self->io.sir_base;
 	
 	WARNING("%s: transmit timed out\n", dev->name);
+	spin_lock_irqsave(&self->lock, flags);
 	irport_start(self);
 	self->change_speed(self->priv, self->io.speed);
+	/* This will re-enable irqs */
+	outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
 }
@@ -614,7 +638,7 @@ int irport_hard_xmit(struct sk_buff *skb
 	int iobase;
 	s32 speed;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	ASSERT(dev != NULL, return 0;);
 	
@@ -625,22 +649,25 @@ int irport_hard_xmit(struct sk_buff *skb
 
 	netif_stop_queue(dev);
 	
+	/* Make sure tests *& speed change are atomic */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Check if we need to change the speed */
 	speed = irda_get_next_speed(skb);
 	if ((speed != self->io.speed) && (speed != -1)) {
 		/* Check for empty frame */
 		if (!skb->len) {
+			/* Better go there already locked - Jean II */
 			irda_task_execute(self, __irport_change_speed, 
 					  irport_change_speed_complete, 
 					  NULL, (void *) speed);
+			spin_unlock_irqrestore(&self->lock, flags);
 			dev_kfree_skb(skb);
 			return 0;
 		} else
 			self->new_speed = speed;
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Init tx buffer */
 	self->tx_buff.data = self->tx_buff.head;
 
@@ -771,8 +798,9 @@ int irport_net_open(struct net_device *d
 	struct irport_cb *self;
 	int iobase;
 	char hwname[16];
+	unsigned long flags;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 	
 	ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
@@ -786,7 +814,9 @@ int irport_net_open(struct net_device *d
 		return -EAGAIN;
 	}
 
+	spin_lock_irqsave(&self->lock, flags);
 	irport_start(self);
+	spin_unlock_irqrestore(&self->lock, flags);
 
 
 	/* Give self a hardware name */
@@ -818,6 +848,7 @@ int irport_net_close(struct net_device *
 {
 	struct irport_cb *self;
 	int iobase;
+	unsigned long flags;
 
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
@@ -836,7 +867,9 @@ int irport_net_close(struct net_device *
 		irlap_close(self->irlap);
 	self->irlap = NULL;
 
+	spin_lock_irqsave(&self->lock, flags);
 	irport_stop(self);
+	spin_unlock_irqrestore(&self->lock, flags);
 
 	free_irq(self->io.irq, dev);
 
@@ -951,10 +984,6 @@ static int irport_net_ioctl(struct net_d
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
-	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN))
@@ -979,14 +1008,16 @@ static int irport_net_ioctl(struct net_d
 		dongle->write       = irport_raw_write;
 		dongle->set_dtr_rts = irport_set_dtr_rts;
 		
-		self->dongle = dongle;
-
 		/* Now initialize the dongle!  */
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);	
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN)) {
@@ -1005,13 +1036,14 @@ static int irport_net_ioctl(struct net_d
 			break;
 		}
 
+		/* No real need to lock... */
+		spin_lock_irqsave(&self->lock, flags);
 		irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+		spin_unlock_irqrestore(&self->lock, flags);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-	
-	restore_flags(flags);
 	
 	return ret;
 }
diff -u -p -r linux/drivers/net/irda-d6/irtty.c linux/drivers/net/irda/irtty.c
--- linux/drivers/net/irda-d6/irtty.c	Mon Aug 19 14:41:00 2002
+++ linux/drivers/net/irda/irtty.c	Thu Aug 29 10:12:38 2002
@@ -74,8 +74,10 @@ char *driver_name = "irtty";
 int __init irtty_init(void)
 {
 	int status;
-	
-	irtty = hashbin_new( HB_LOCAL);
+
+	/* Probably no need to lock here because all operations done in
+	 * open()/close() which are already safe - Jean II */
+	irtty = hashbin_new( HB_NOLOCK);
 	if ( irtty == NULL) {
 		printk( KERN_WARNING "IrDA: Can't allocate irtty hashbin!\n");
 		return -ENOMEM;
@@ -163,6 +165,7 @@ static int irtty_open(struct tty_struct 
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct irtty_cb));
+	spin_lock_init(&self->lock);
 	
 	self->tty = tty;
 	tty->disc_data = self;
@@ -266,11 +269,12 @@ static int irtty_open(struct tty_struct 
 static void irtty_close(struct tty_struct *tty) 
 {
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
+	unsigned long flags;
 	
 	/* First make sure we're connected. */
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRTTY_MAGIC, return;);
-	
+
 	/* Stop tty */
 	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 	tty->disc_data = 0;
@@ -287,6 +291,11 @@ static void irtty_close(struct tty_struc
 		rtnl_unlock();
 	}
 	
+	self = hashbin_remove(irtty, (int) self, NULL);
+
+	/* Protect access to self->task and self->?x_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Remove speed changing task if any */
 	if (self->task)
 		irda_task_delete(self->task);
@@ -294,13 +303,12 @@ static void irtty_close(struct tty_struc
 	self->tty = NULL;
 	self->magic = 0;
 	
-	self = hashbin_remove(irtty, (int) self, NULL);
-
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
 	
 	if (self->rx_buff.head)
 		kfree(self->rx_buff.head);
+	spin_unlock_irqrestore(&self->lock, flags);
 	
 	kfree(self);
 	
@@ -326,6 +334,7 @@ static void irtty_stop_receiver(struct i
 	else
 		cflag |= CREAD;
 
+	/* This is unsafe, but currently under discussion - Jean II */
 	self->tty->termios->c_cflag = cflag;
 	self->tty->driver.set_termios(self->tty, &old_termios);
 }
@@ -378,6 +387,7 @@ static void __irtty_change_speed(struct 
 		break;
 	}	
 
+	/* This is unsafe, but currently under discussion - Jean II */
 	self->tty->termios->c_cflag = cflag;
 	self->tty->driver.set_termios(self->tty, &old_termios);
 
@@ -393,6 +403,7 @@ static void __irtty_change_speed(struct 
 static int irtty_change_speed(struct irda_task *task)
 {
 	struct irtty_cb *self;
+	unsigned long flags;
 	__u32 speed = (__u32) task->param;
 	int ret = 0;
 
@@ -401,12 +412,17 @@ static int irtty_change_speed(struct ird
 	self = (struct irtty_cb *) task->instance;
 	ASSERT(self != NULL, return -1;);
 
+	/* Protect access to self->task - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Check if busy */
 	if (self->task && self->task != task) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		spin_unlock_irqrestore(&self->lock, flags);
 		return MSECS_TO_JIFFIES(10);
 	} else
 		self->task = task;
+	spin_unlock_irqrestore(&self->lock, flags);
 
 	switch (task->state) {
 	case IRDA_TASK_INIT:
@@ -501,6 +517,7 @@ static int irtty_ioctl(struct tty_struct
 	switch (cmd) {
 	case TCGETS:
 	case TCGETA:
+		/* Unsure about locking here, to check - Jean II */
 		return n_tty_ioctl(tty, (struct file *) file, cmd, 
 				   (unsigned long) arg);
 		break;
@@ -516,15 +533,16 @@ static int irtty_ioctl(struct tty_struct
 		dongle->write       = irtty_raw_write;
 		dongle->set_dtr_rts = irtty_set_dtr_rts;
 		
-		/* Bind dongle */
-		self->dongle = dongle;
-		
 		/* Now initialize the dongle!  */
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);		
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case IRTTY_IOCGET:
 		ASSERT(self->netdev != NULL, return -1;);
@@ -559,6 +577,9 @@ static void irtty_receive_buf(struct tty
 		return;
 	}
 
+	// Are we in interrupt context ? What locking is done ? - Jean II
+	//spin_lock_irqsave(&self->lock, flags);
+
 	/* Read the characters out of the buffer */
  	while (count--) {
 		/* 
@@ -589,6 +610,7 @@ static void irtty_receive_buf(struct tty
 			break;
 		}
 	}
+	//spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*
@@ -626,11 +648,13 @@ static int irtty_hard_xmit(struct sk_buf
 	struct irtty_cb *self;
 	int actual = 0;
 	__s32 speed;
+	unsigned long flags;
 
 	self = (struct irtty_cb *) dev->priv;
 	ASSERT(self != NULL, return 0;);
 
-	/* Lock transmit buffer */
+	/* Lock transmit buffer
+	 * this serialise operations, no need to spinlock - Jean II */
 	netif_stop_queue(dev);
 	
 	/* Check if we need to change the speed */
@@ -647,6 +671,9 @@ static int irtty_hard_xmit(struct sk_buf
 			self->new_speed = speed;
 	}
 
+	/* Protect access to self->tx_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Init tx buffer*/
 	self->tx_buff.data = self->tx_buff.head;
 	
@@ -667,6 +694,8 @@ static int irtty_hard_xmit(struct sk_buf
 	self->tx_buff.data += actual;
 	self->tx_buff.len -= actual;
 
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	dev_kfree_skb(skb);
 
 	return 0;
@@ -695,6 +724,7 @@ static void irtty_write_wakeup(struct tt
 {
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
 	int actual = 0;
+	unsigned long flags;
 	
 	/* 
 	 *  First make sure we're connected. 
@@ -702,6 +732,11 @@ static void irtty_write_wakeup(struct tt
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
+	/* Protected via netif_stop_queue(dev); - Jean II */
+
+	/* Protect access to self->tx_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Finished with frame?  */
 	if (self->tx_buff.len > 0)  {
 		/* Write data left in transmit buffer */
@@ -710,6 +745,7 @@ static void irtty_write_wakeup(struct tt
 
 		self->tx_buff.data += actual;
 		self->tx_buff.len  -= actual;
+		spin_unlock_irqrestore(&self->lock, flags);
 	} else {		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
@@ -721,6 +757,9 @@ static void irtty_write_wakeup(struct tt
 
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
+		/* Don't change speed with irq off */
+		spin_unlock_irqrestore(&self->lock, flags);
+
 		if (self->new_speed) {
 			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
 			irda_task_execute(self, irtty_change_speed, 
@@ -755,12 +794,17 @@ static int irtty_set_dtr_rts(struct net_
 {
 	struct irtty_cb *self;
 	struct tty_struct *tty;
+	//unsigned long flags;
 	mm_segment_t fs;
 	int arg = 0;
 
 	self = (struct irtty_cb *) dev->priv;
 	tty = self->tty;
 
+	/* Was protected in ioctl handler, but the serial driver doesn't
+	 * like it. This may need to change. - Jean II */
+	//spin_lock_irqsave(&self->lock, flags);
+
 #ifdef TIOCM_OUT2 /* Not defined for ARM */
 	arg = TIOCM_OUT2;
 #endif
@@ -780,11 +824,14 @@ static int irtty_set_dtr_rts(struct net_
 	fs = get_fs();
 	set_fs(get_ds());
 	
+	/* This is probably unsafe, but currently under discussion - Jean II */
 	if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { 
 		IRDA_DEBUG(2, __FUNCTION__ "(), error doing ioctl!\n");
 	}
 	set_fs(fs);
 
+	//spin_unlock_irqrestore(&self->lock, flags);
+
 	return 0;
 }
 
@@ -799,13 +846,17 @@ static int irtty_set_dtr_rts(struct net_
 int irtty_set_mode(struct net_device *dev, int mode)
 {
 	struct irtty_cb *self;
+	unsigned long flags;
 
 	self = (struct irtty_cb *) dev->priv;
 
 	ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), mode=%s\n", infrared_mode[mode]);
-	
+
+	/* Protect access to self->rx_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* save status for driver */
 	self->mode = mode;
 	
@@ -814,6 +865,8 @@ int irtty_set_mode(struct net_device *de
 	self->rx_buff.len = 0;
 	self->rx_buff.state = OUTSIDE_FRAME;
 
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	return 0;
 }
 
@@ -955,7 +1008,6 @@ static int irtty_net_ioctl(struct net_de
 	struct if_irda_req *irq = (struct if_irda_req *) rq;
 	struct irtty_cb *self;
 	dongle_t *dongle;
-	unsigned long flags;
 	int ret = 0;
 
 	ASSERT(dev != NULL, return -1;);
@@ -971,8 +1023,7 @@ static int irtty_net_ioctl(struct net_de
 	 * irda_device_dongle_init() can't be locked.
 	 * irda_task_execute() doesn't need to be locked (but
 	 * irtty_change_speed() should protect itself).
-	 * As this driver doesn't have spinlock protection, keep
-	 * old fashion locking :-(
+	 * Other calls protect themselves.
 	 * Jean II
 	 */
 	
@@ -1025,20 +1076,14 @@ static int irtty_net_ioctl(struct net_de
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
 		else {
-			save_flags(flags);
-			cli();
 			irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
-			restore_flags(flags);
 		}
 		break;
 	case SIOCSMODE:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
 		else {
-			save_flags(flags);
-			cli();
 			irtty_set_mode(dev, irq->ifr_mode);
-			restore_flags(flags);
 		}
 		break;
 	default:
diff -u -p -r linux/drivers/net/irda-d6/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- linux/drivers/net/irda-d6/nsc-ircc.c	Fri Aug 23 11:07:06 2002
+++ linux/drivers/net/irda/nsc-ircc.c	Fri Aug 23 11:42:23 2002
@@ -870,7 +870,6 @@ static void nsc_ircc_init_dongle_interfa
  */
 static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
 {
-	unsigned long flags;
 	__u8 bank;
 
 	/* Save current bank */
@@ -916,11 +915,10 @@ static void nsc_ircc_change_dongle_speed
 		outb(0x01, iobase+4);
 
 		if (speed == 4000000) {
-			save_flags(flags);
-			cli();
+			/* There was a cli() there, but we now are already
+			 * under spin_lock_irqsave() - JeanII */
 			outb(0x81, iobase+4);
 			outb(0x80, iobase+4);
-			restore_flags(flags);
 		} else
 			outb(0x00, iobase+4);
 		break;
@@ -2013,33 +2011,30 @@ static int nsc_ircc_net_ioctl(struct net
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
-
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN)) {
 			ret = -EPERM;
-			goto out;
+			break;
 		}
+		spin_lock_irqsave(&self->lock, flags);
 		nsc_ircc_change_speed(self, irq->ifr_baudrate);
+		spin_unlock_irqrestore(&self->lock, flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN)) {
 			ret = -EPERM;
-			goto out;
+			break;
 		}
 		irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		/* This is already protected */
 		irq->ifr_receiving = nsc_ircc_is_receiving(self);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-out:
-	restore_flags(flags);
 	return ret;
 }
 
diff -u -p -r linux/drivers/net/irda-d6/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- linux/drivers/net/irda-d6/smc-ircc.c	Mon Aug 19 14:41:00 2002
+++ linux/drivers/net/irda/smc-ircc.c	Fri Aug 23 15:46:03 2002
@@ -431,6 +431,7 @@ static int __init ircc_open(unsigned int
 	struct ircc_cb *self;
         struct irport_cb *irport;
 	unsigned char low, high, chip, config, dma, irq, version;
+	unsigned long flags;
 
 
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
@@ -484,7 +485,6 @@ static int __init ircc_open(unsigned int
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct ircc_cb));
-	spin_lock_init(&self->lock);
 
 	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
 	self->rx_buff.truesize = 4000; 
@@ -555,6 +555,9 @@ static int __init ircc_open(unsigned int
 
 	request_region(self->io->fir_base, CHIP_IO_EXTENT, driver_name);
 
+	/* Don't allow irport to change under us - Jean II */
+	spin_lock_irqsave(&self->irport->lock, flags);
+
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&irport->qos);
 	
@@ -581,6 +584,7 @@ static int __init ircc_open(unsigned int
 	self->netdev->stop   = &ircc_net_close;
 
 	irport_start(self->irport);
+	spin_unlock_irqrestore(&self->irport->lock, flags);
 
         self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ircc_pmproc);
         if (self->pmdev)
@@ -598,6 +602,7 @@ static int __init ircc_open(unsigned int
  *
  *    Change the speed of the device
  *
+ * This function should be called with irq off and spin-lock.
  */
 static void ircc_change_speed(void *priv, u32 speed)
 {
@@ -658,6 +663,7 @@ static void ircc_change_speed(void *priv
 
 	/* Make special FIR init if necessary */
 	if (speed > 115200) {
+		/* No need to lock, already locked - Jean II */
 		irport_stop(self->irport);
 
 		/* Install FIR transmit handler */
@@ -674,6 +680,7 @@ static void ircc_change_speed(void *priv
 	} else {
 		/* Install SIR transmit handler */
 		dev->hard_start_xmit = &irport_hard_xmit;
+		/* No need to lock, already locked - Jean II */
 		irport_start(self->irport);
 		
 	        IRDA_DEBUG(0, __FUNCTION__ 
@@ -727,20 +734,26 @@ static int ircc_hard_xmit(struct sk_buff
 
 	netif_stop_queue(dev);
 
+	/* Make sure tests *& speed change are atomic */
+	spin_lock_irqsave(&self->irport->lock, flags);
+
+	/* Note : you should make sure that speed changes are not going
+	 * to corrupt any outgoing frame. Look at nsc-ircc for the gory
+	 * details - Jean II */
+
 	/* Check if we need to change the speed after this frame */
 	speed = irda_get_next_speed(skb);
 	if ((speed != self->io->speed) && (speed != -1)) {
 		/* Check for empty frame */
 		if (!skb->len) {
 			ircc_change_speed(self, speed); 
+			spin_unlock_irqrestore(&self->irport->lock, flags);
 			dev_kfree_skb(skb);
 			return 0;
 		} else
 			self->new_speed = speed;
 	}
 	
-	spin_lock_irqsave(&self->lock, flags);
-
 	memcpy(self->tx_buff.head, skb->data, skb->len);
 
 	self->tx_buff.len = skb->len;
@@ -763,7 +776,7 @@ static int ircc_hard_xmit(struct sk_buff
 		/* Transmit frame */
 		ircc_dma_xmit(self, iobase, 0);
 	}
-	spin_unlock_irqrestore(&self->lock, flags);
+	spin_unlock_irqrestore(&self->irport->lock, flags);
 	dev_kfree_skb(skb);
 
 	return 0;
@@ -985,12 +998,13 @@ static void ircc_interrupt(int irq, void
 
 	/* Check if we should use the SIR interrupt handler */
 	if (self->io->speed < 576000) {
+		/* Will spinlock itself - Jean II */
 		irport_interrupt(irq, dev_id, regs);
 		return;
 	}
 	iobase = self->io->fir_base;
 
-	spin_lock(&self->lock);	
+	spin_lock(&self->irport->lock);	
 
 	register_bank(iobase, 0);
 	iir = inb(iobase+IRCC_IIR);
@@ -1013,7 +1027,7 @@ static void ircc_interrupt(int irq, void
 	register_bank(iobase, 0);
 	outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
 
-	spin_unlock(&self->lock);
+	spin_unlock(&self->irport->lock);
 }
 
 #if 0 /* unused */
@@ -1128,17 +1142,15 @@ static void ircc_suspend(struct ircc_cb 
 
 static void ircc_wakeup(struct ircc_cb *self)
 {
-	unsigned long flags;
-
 	if (!self->io->suspended)
 		return;
 
-	save_flags(flags);
-	cli();
+	/* The code was doing a "cli()" here, but this can't be right.
+	 * If you need protection, do it in net_open with a spinlock
+	 * or give a good reason. - Jean II */
 
 	ircc_net_open(self->netdev);
 	
-	restore_flags(flags);
 	MESSAGE("%s, Waking up\n", driver_name);
 }
 
@@ -1174,6 +1186,7 @@ static int __exit ircc_close(struct ircc
 
         iobase = self->irport->io.fir_base;
 
+	/* This will destroy irport */
 	irport_close(self->irport);
 
 	/* Stop interrupts */
@@ -1187,6 +1200,7 @@ static int __exit ircc_close(struct ircc
         outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
         outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
 #endif
+
 	/* Release the PORT that this driver is using */
 	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", iobase);
 
diff -u -p -r linux/drivers/net/irda-d6/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- linux/drivers/net/irda-d6/w83977af_ir.c	Mon Aug 19 14:41:00 2002
+++ linux/drivers/net/irda/w83977af_ir.c	Fri Aug 23 12:00:44 2002
@@ -175,6 +175,7 @@ int w83977af_open(int i, unsigned int io
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct w83977af_ir));
+	spin_lock_init(&self->lock);
    
 	/* Need to store self somewhere */
 	dev_self[i] = self;
@@ -603,8 +604,7 @@ static void w83977af_dma_write(struct w8
 	switch_bank(iobase, SET2);
 	outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1);
 #ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->lock, flags);
 
 	disable_dma(self->io.dma);
 	clear_dma_ff(self->io.dma);
@@ -623,7 +623,7 @@ static void w83977af_dma_write(struct w8
 	hcr = inb(iobase+HCR);
 	outb(hcr | HCR_EN_DMA, iobase+HCR);
 	enable_dma(self->io.dma);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 #else	
 	outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR);
 #endif
@@ -761,8 +761,7 @@ int w83977af_dma_receive(struct w83977af
 	self->rx_buff.data = self->rx_buff.head;
 
 #ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->lock, flags);
 
 	disable_dma(self->io.dma);
 	clear_dma_ff(self->io.dma);
@@ -788,7 +787,7 @@ int w83977af_dma_receive(struct w83977af
 	hcr = inb(iobase+HCR);
 	outb(hcr | HCR_EN_DMA, iobase+HCR);
 	enable_dma(self->io.dma);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 #else	
 	outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);
 #endif
@@ -1334,10 +1333,8 @@ static int w83977af_net_ioctl(struct net
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
-	
+	spin_lock_irqsave(&self->lock, flags);
+
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN)) {
@@ -1360,7 +1357,7 @@ static int w83977af_net_ioctl(struct net
 		ret = -EOPNOTSUPP;
 	}
 out:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 	return ret;
 }
 
