Commit 01166d96 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/jgarzik/irda-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents e71eb380 df3a5c9f
...@@ -289,16 +289,29 @@ config TOSHIBA_FIR ...@@ -289,16 +289,29 @@ config TOSHIBA_FIR
<file:Documentation/modules.txt>. <file:Documentation/modules.txt>.
The module will be called donauboe. The module will be called donauboe.
config SMC_IRCC_FIR config SMC_IRCC_OLD
tristate "SMC IrCC (EXPERIMENTAL)" tristate "SMC IrCC (old driver) (EXPERIMENTAL)"
depends on EXPERIMENTAL && IRDA depends on EXPERIMENTAL && IRDA
help help
Say Y here if you want to build support for the SMC Infrared Say Y here if you want to build support for the SMC Infrared
Communications Controller. It is used in the Fujitsu Lifebook 635t Communications Controller. It is used in the Fujitsu Lifebook 635t
and Sony PCG-505TX. If you want to compile it as a module, say M and Sony PCG-505TX. This driver is obsolete, will no more be
here and read <file:Documentation/modules.txt>. The module will be maintained and will be removed in favor of the new driver.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. The module will be
called smc-ircc. called smc-ircc.
config SMC_IRCC_FIR
tristate "SMSC IrCC (EXPERIMENTAL)"
depends on EXPERIMENTAL && IRDA
help
Say Y here if you want to build support for the SMC Infrared
Communications Controller. It is used in a wide variety of
laptops (Fujitsu, Sony, Compaq and some Toshiba).
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. The module will be
called smsc-ircc2.o.
config ALI_FIR config ALI_FIR
tristate "ALi M5123 FIR (EXPERIMENTAL)" tristate "ALi M5123 FIR (EXPERIMENTAL)"
depends on EXPERIMENTAL && IRDA depends on EXPERIMENTAL && IRDA
......
...@@ -15,13 +15,14 @@ obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o ...@@ -15,13 +15,14 @@ obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o
obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o
obj-$(CONFIG_TOSHIBA_OLD) += toshoboe.o obj-$(CONFIG_TOSHIBA_OLD) += toshoboe.o
obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o
obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o obj-$(CONFIG_SMC_IRCC_OLD) += smc-ircc.o irport.o
obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o
obj-$(CONFIG_ALI_FIR) += ali-ircc.o obj-$(CONFIG_ALI_FIR) += ali-ircc.o
obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o
# Old dongle drivers for old SIR drivers # Old dongle drivers for old SIR drivers
obj-$(CONFIG_ESI_OLD) += esi.o obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o
obj-$(CONFIG_TEKRAM_OLD) += tekram.o obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o
obj-$(CONFIG_ACTISYS_OLD) += actisys.o obj-$(CONFIG_ACTISYS_DONGLE_OLD) += actisys.o
obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o
obj-$(CONFIG_LITELINK_DONGLE) += litelink.o obj-$(CONFIG_LITELINK_DONGLE) += litelink.o
obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o
......
...@@ -1451,6 +1451,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1451,6 +1451,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */ /* Check for empty frame */
if (!skb->len) { if (!skb->len) {
ali_ircc_change_speed(self, speed); ali_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
...@@ -1560,6 +1561,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1560,6 +1561,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Restore bank register */ /* Restore bank register */
switch_bank(iobase, BANK0); switch_bank(iobase, BANK0);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -1974,6 +1976,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1974,6 +1976,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */ /* Check for empty frame */
if (!skb->len) { if (!skb->len) {
ali_ircc_change_speed(self, speed); ali_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
...@@ -1993,6 +1996,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1993,6 +1996,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Turn on transmit finished interrupt. Will fire immediately! */ /* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER); outb(UART_IER_THRI, iobase+UART_IER);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
......
...@@ -1051,7 +1051,9 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -1051,7 +1051,9 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
toshoboe_checkstuck (self); toshoboe_checkstuck (self);
/* Check if we need to change the speed */ dev->trans_start = jiffies;
/* Check if we need to change the speed */
/* But not now. Wait after transmission if mtt not required */ /* But not now. Wait after transmission if mtt not required */
speed=irda_get_next_speed(skb); speed=irda_get_next_speed(skb);
if ((speed != self->io.speed) && (speed != -1)) if ((speed != self->io.speed) && (speed != -1))
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* Sources: serial.c by Linus Torvalds * Sources: serial.c by Linus Torvalds
* *
* Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved. * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved.
* Copyright (c) 2000-2003 Jean Tourrilhes, All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -72,14 +74,14 @@ static unsigned int qos_mtt_bits = 0x03; ...@@ -72,14 +74,14 @@ static unsigned int qos_mtt_bits = 0x03;
static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL}; static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL};
static char *driver_name = "irport"; static char *driver_name = "irport";
static void irport_write_wakeup(struct irport_cb *self); static inline void irport_write_wakeup(struct irport_cb *self);
static int irport_write(int iobase, int fifo_size, __u8 *buf, int len); static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len);
static void irport_receive(struct irport_cb *self); static inline void irport_receive(struct irport_cb *self);
static int irport_net_init(struct net_device *dev); static int irport_net_init(struct net_device *dev);
static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq,
int cmd); int cmd);
static int irport_is_receiving(struct irport_cb *self); static inline int irport_is_receiving(struct irport_cb *self);
static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts); static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts);
static int irport_raw_write(struct net_device *dev, __u8 *buf, int len); static int irport_raw_write(struct net_device *dev, __u8 *buf, int len);
static struct net_device_stats *irport_net_get_stats(struct net_device *dev); static struct net_device_stats *irport_net_get_stats(struct net_device *dev);
...@@ -169,7 +171,7 @@ irport_open(int i, unsigned int iobase, unsigned int irq) ...@@ -169,7 +171,7 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
self->io.sir_base = iobase; self->io.sir_base = iobase;
self->io.sir_ext = IO_EXTENT; self->io.sir_ext = IO_EXTENT;
self->io.irq = irq; self->io.irq = irq;
self->io.fifo_size = 16; self->io.fifo_size = 16; /* 16550A and compatible */
/* Initialize QoS for this device */ /* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos); irda_init_max_qos_capabilies(&self->qos);
...@@ -181,39 +183,47 @@ irport_open(int i, unsigned int iobase, unsigned int irq) ...@@ -181,39 +183,47 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
irda_qos_bits_to_value(&self->qos); irda_qos_bits_to_value(&self->qos);
self->flags = IFF_SIR|IFF_PIO; self->flags = IFF_SIR|IFF_PIO;
self->mode = IRDA_IRLAP;
/* Bootstrap ZeroCopy Rx */
self->rx_buff.truesize = IRDA_SKB_MAX_MTU;
self->rx_buff.skb = __dev_alloc_skb(self->rx_buff.truesize,
GFP_KERNEL);
if (self->rx_buff.skb == NULL)
return NULL;
skb_reserve(self->rx_buff.skb, 1);
self->rx_buff.head = self->rx_buff.skb->data;
/* No need to memset the buffer, unless you are really pedantic */
/* Finish setup the Rx buffer descriptor */
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
self->rx_buff.data = self->rx_buff.head;
/* Specify how much memory we want */ /* Specify how much memory we want */
self->rx_buff.truesize = 4000;
self->tx_buff.truesize = 4000; self->tx_buff.truesize = 4000;
/* Allocate memory if needed */ /* Allocate memory if needed */
if (self->rx_buff.truesize > 0) {
self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
GFP_KERNEL);
if (self->rx_buff.head == NULL)
return NULL;
memset(self->rx_buff.head, 0, self->rx_buff.truesize);
}
if (self->tx_buff.truesize > 0) { if (self->tx_buff.truesize > 0) {
self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize,
GFP_KERNEL); GFP_KERNEL);
if (self->tx_buff.head == NULL) { if (self->tx_buff.head == NULL) {
kfree(self->rx_buff.head); kfree_skb(self->rx_buff.skb);
self->rx_buff.skb = NULL;
self->rx_buff.head = NULL;
return NULL; return NULL;
} }
memset(self->tx_buff.head, 0, self->tx_buff.truesize); memset(self->tx_buff.head, 0, self->tx_buff.truesize);
} }
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
self->tx_buff.data = self->tx_buff.head; self->tx_buff.data = self->tx_buff.head;
self->rx_buff.data = self->rx_buff.head;
self->mode = IRDA_IRLAP;
if (!(dev = dev_alloc("irda%d", &err))) { if (!(dev = dev_alloc("irda%d", &err))) {
ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
return NULL; return NULL;
} }
self->netdev = dev; self->netdev = dev;
/* Keep track of module usage */
SET_MODULE_OWNER(dev);
/* May be overridden by piggyback drivers */ /* May be overridden by piggyback drivers */
dev->priv = (void *) self; dev->priv = (void *) self;
...@@ -241,7 +251,8 @@ irport_open(int i, unsigned int iobase, unsigned int irq) ...@@ -241,7 +251,8 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
return NULL; return NULL;
} }
MESSAGE("IrDA: Registered device %s\n", dev->name); MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n",
dev->name, iobase, irq);
return self; return self;
} }
...@@ -270,8 +281,9 @@ int irport_close(struct irport_cb *self) ...@@ -270,8 +281,9 @@ int irport_close(struct irport_cb *self)
if (self->tx_buff.head) if (self->tx_buff.head)
kfree(self->tx_buff.head); kfree(self->tx_buff.head);
if (self->rx_buff.head) if (self->rx_buff.skb)
kfree(self->rx_buff.head); kfree_skb(self->rx_buff.skb);
self->rx_buff.skb = NULL;
/* Remove ourselves */ /* Remove ourselves */
dev_self[self->index] = NULL; dev_self[self->index] = NULL;
...@@ -306,6 +318,9 @@ void irport_stop(struct irport_cb *self) ...@@ -306,6 +318,9 @@ void irport_stop(struct irport_cb *self)
/* We can't lock, we may be called from a FIR driver - Jean II */ /* We can't lock, we may be called from a FIR driver - Jean II */
/* We are not transmitting any more */
self->transmitting = 0;
/* Reset UART */ /* Reset UART */
outb(0, iobase+UART_MCR); outb(0, iobase+UART_MCR);
...@@ -326,6 +341,33 @@ int irport_probe(int iobase) ...@@ -326,6 +341,33 @@ int irport_probe(int iobase)
return 0; return 0;
} }
/*
* Function irport_get_fcr (speed)
*
* Compute value of fcr
*
*/
static inline unsigned int irport_get_fcr(__u32 speed)
{
unsigned int fcr; /* FIFO control reg */
/* Enable fifos */
fcr = UART_FCR_ENABLE_FIFO;
/*
* Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
* almost 1,7 ms at 19200 bps. At speeds above that we can just forget
* about this timeout since it will always be fast enough.
*/
if (speed < 38400)
fcr |= UART_FCR_TRIGGER_1;
else
//fcr |= UART_FCR_TRIGGER_14;
fcr |= UART_FCR_TRIGGER_8;
return(fcr);
}
/* /*
* Function irport_change_speed (self, speed) * Function irport_change_speed (self, speed)
* *
...@@ -337,11 +379,12 @@ void irport_change_speed(void *priv, __u32 speed) ...@@ -337,11 +379,12 @@ void irport_change_speed(void *priv, __u32 speed)
{ {
struct irport_cb *self = (struct irport_cb *) priv; struct irport_cb *self = (struct irport_cb *) priv;
int iobase; int iobase;
int fcr; /* FIFO control reg */ unsigned int fcr; /* FIFO control reg */
int lcr; /* Line control reg */ unsigned int lcr; /* Line control reg */
int divisor; int divisor;
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(speed != 0, return;);
IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n", IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n",
__FUNCTION__, speed, self->io.sir_base); __FUNCTION__, speed, self->io.sir_base);
...@@ -358,18 +401,9 @@ void irport_change_speed(void *priv, __u32 speed) ...@@ -358,18 +401,9 @@ void irport_change_speed(void *priv, __u32 speed)
divisor = SPEED_MAX/speed; divisor = SPEED_MAX/speed;
fcr = UART_FCR_ENABLE_FIFO; /* Get proper fifo configuration */
fcr = irport_get_fcr(speed);
/*
* Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
* almost 1,7 ms at 19200 bps. At speeds above that we can just forget
* about this timeout since it will always be fast enough.
*/
if (self->io.speed < 38400)
fcr |= UART_FCR_TRIGGER_1;
else
fcr |= UART_FCR_TRIGGER_14;
/* IrDA ports use 8N1 */ /* IrDA ports use 8N1 */
lcr = UART_LCR_WLEN8; lcr = UART_LCR_WLEN8;
...@@ -380,7 +414,7 @@ void irport_change_speed(void *priv, __u32 speed) ...@@ -380,7 +414,7 @@ void irport_change_speed(void *priv, __u32 speed)
outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
/* Turn on interrups */ /* Turn on interrups */
/* This will generate a fata interrupt storm. /* This will generate a fatal interrupt storm.
* People calling us will do that properly - Jean II */ * People calling us will do that properly - Jean II */
//outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); //outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
} }
...@@ -467,8 +501,8 @@ int __irport_change_speed(struct irda_task *task) ...@@ -467,8 +501,8 @@ int __irport_change_speed(struct irda_task *task)
irda_task_next_state(task, IRDA_TASK_DONE); irda_task_next_state(task, IRDA_TASK_DONE);
ret = -1; ret = -1;
break; break;
} }
/* Put stuff in the sate we found them - Jean II */ /* Put stuff in the state we found them - Jean II */
if(wasunlocked) { if(wasunlocked) {
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
} }
...@@ -476,98 +510,6 @@ int __irport_change_speed(struct irda_task *task) ...@@ -476,98 +510,6 @@ int __irport_change_speed(struct irda_task *task)
return ret; return ret;
} }
/*
* Function irport_write_wakeup (tty)
*
* Called by the driver when there's room for more data. If we have
* more packets to send, we send them here.
*
*/
static void irport_write_wakeup(struct irport_cb *self)
{
int actual = 0;
int iobase;
int fcr;
ASSERT(self != NULL, return;);
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
iobase = self->io.sir_base;
/* Finished with frame? */
if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
actual = irport_write(iobase, self->io.fifo_size,
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
* transmission of another packet. But first we must check
* if we need to change the speed of the hardware
*/
if (self->new_speed) {
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);
}
self->stats.tx_packets++;
/*
* Reset Rx FIFO to make sure that all reflected transmit data
* is discarded. This is needed for half duplex operation
*/
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
if (self->io.speed < 38400)
fcr |= UART_FCR_TRIGGER_1;
else
fcr |= UART_FCR_TRIGGER_14;
outb(fcr, iobase+UART_FCR);
/* Turn on receive interrupts */
outb(UART_IER_RDI, iobase+UART_IER);
}
}
/*
* Function irport_write (driver)
*
* Fill Tx FIFO with transmit data
*
*/
static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
{
int actual = 0;
/* Tx FIFO should be empty! */
if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__);
return 0;
}
/* Fill FIFO with current frame */
while ((fifo_size-- > 0) && (actual < len)) {
/* Transmit next byte */
outb(buf[actual], iobase+UART_TX);
actual++;
}
return actual;
}
/* /*
* Function irport_change_speed_complete (task) * Function irport_change_speed_complete (task)
* *
...@@ -604,23 +546,79 @@ static void irport_timeout(struct net_device *dev) ...@@ -604,23 +546,79 @@ static void irport_timeout(struct net_device *dev)
{ {
struct irport_cb *self; struct irport_cb *self;
int iobase; int iobase;
int iir, lsr;
unsigned long flags; unsigned long flags;
self = (struct irport_cb *) dev->priv; self = (struct irport_cb *) dev->priv;
ASSERT(self != NULL, return;);
iobase = self->io.sir_base; iobase = self->io.sir_base;
WARNING("%s: transmit timed out\n", dev->name); WARNING("%s: transmit timed out, jiffies = %ld, trans_start = %ld\n",
dev->name, jiffies, dev->trans_start);
spin_lock_irqsave(&self->lock, flags); spin_lock_irqsave(&self->lock, flags);
/* Debug what's happening... */
/* Get interrupt status */
lsr = inb(iobase+UART_LSR);
/* Read interrupt register */
iir = inb(iobase+UART_IIR);
IRDA_DEBUG(0, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
__FUNCTION__, iir, lsr, iobase);
IRDA_DEBUG(0, "%s(), transmitting=%d, remain=%d, done=%d\n",
__FUNCTION__, self->transmitting, self->tx_buff.len,
self->tx_buff.data - self->tx_buff.head);
/* Now, restart the port */
irport_start(self); irport_start(self);
self->change_speed(self->priv, self->io.speed); self->change_speed(self->priv, self->io.speed);
/* This will re-enable irqs */ /* This will re-enable irqs */
outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev->trans_start = jiffies;
netif_wake_queue(dev); netif_wake_queue(dev);
} }
/*
* Function irport_wait_hw_transmitter_finish ()
*
* Wait for the real end of HW transmission
*
* The UART is a strict FIFO, and we get called only when we have finished
* pushing data to the FIFO, so the maximum amount of time we must wait
* is only for the FIFO to drain out.
*
* We use a simple calibrated loop. We may need to adjust the loop
* delay (udelay) to balance I/O traffic and latency. And we also need to
* adjust the maximum timeout.
* It would probably be better to wait for the proper interrupt,
* but it doesn't seem to be available.
*
* We can't use jiffies or kernel timers because :
* 1) We are called from the interrupt handler, which disable softirqs,
* so jiffies won't be increased
* 2) Jiffies granularity is usually very coarse (10ms), and we don't
* want to wait that long to detect stuck hardware.
* Jean II
*/
static void irport_wait_hw_transmitter_finish(struct irport_cb *self)
{
int iobase;
int count = 1000; /* 1 ms */
iobase = self->io.sir_base;
/* Calibrated busy loop */
while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
udelay(1);
if(count == 0)
IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
}
/* /*
* Function irport_hard_start_xmit (struct sk_buff *skb, struct net_device *dev) * Function irport_hard_start_xmit (struct sk_buff *skb, struct net_device *dev)
* *
...@@ -645,8 +643,8 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -645,8 +643,8 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
iobase = self->io.sir_base; iobase = self->io.sir_base;
netif_stop_queue(dev); netif_stop_queue(dev);
/* Make sure tests *& speed change are atomic */ /* Make sure tests & speed change are atomic */
spin_lock_irqsave(&self->lock, flags); spin_lock_irqsave(&self->lock, flags);
/* Check if we need to change the speed */ /* Check if we need to change the speed */
...@@ -654,10 +652,21 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -654,10 +652,21 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
if ((speed != self->io.speed) && (speed != -1)) { if ((speed != self->io.speed) && (speed != -1)) {
/* Check for empty frame */ /* Check for empty frame */
if (!skb->len) { if (!skb->len) {
/*
* We send frames one by one in SIR mode (no
* pipelining), so at this point, if we were sending
* a previous frame, we just received the interrupt
* telling us it is finished (UART_IIR_THRI).
* Therefore, waiting for the transmitter to really
* finish draining the fifo won't take too long.
* And the interrupt handler is not expected to run.
* - Jean II */
irport_wait_hw_transmitter_finish(self);
/* Better go there already locked - Jean II */ /* Better go there already locked - Jean II */
irda_task_execute(self, __irport_change_speed, irda_task_execute(self, __irport_change_speed,
irport_change_speed_complete, irport_change_speed_complete,
NULL, (void *) speed); NULL, (void *) speed);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
...@@ -674,9 +683,13 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -674,9 +683,13 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self->stats.tx_bytes += self->tx_buff.len; self->stats.tx_bytes += self->tx_buff.len;
/* We are transmitting */
self->transmitting = 1;
/* Turn on transmit finished interrupt. Will fire immediately! */ /* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER); outb(UART_IER_THRI, iobase+UART_IER);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -684,13 +697,101 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -684,13 +697,101 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
/*
* Function irport_write (driver)
*
* Fill Tx FIFO with transmit data
*
* Called only from irport_write_wakeup()
*/
static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
{
int actual = 0;
/* Fill FIFO with current frame */
while ((actual < fifo_size) && (actual < len)) {
/* Transmit next byte */
outb(buf[actual], iobase+UART_TX);
actual++;
}
return actual;
}
/*
* Function irport_write_wakeup (tty)
*
* Called by the driver when there's room for more data. If we have
* more packets to send, we send them here.
*
* Called only from irport_interrupt()
* Make sure this function is *not* called while we are receiving,
* otherwise we will reset fifo and loose data :-(
*/
static inline void irport_write_wakeup(struct irport_cb *self)
{
int actual = 0;
int iobase;
unsigned int fcr;
ASSERT(self != NULL, return;);
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
iobase = self->io.sir_base;
/* Finished with frame? */
if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
actual = irport_write(iobase, self->io.fifo_size,
self->tx_buff.data, self->tx_buff.len);
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
} else {
/*
* Now serial buffer is almost free & we can start
* transmission of another packet. But first we must check
* if we need to change the speed of the hardware
*/
if (self->new_speed) {
irport_wait_hw_transmitter_finish(self);
irda_task_execute(self, __irport_change_speed,
irport_change_speed_complete,
NULL, (void *) self->new_speed);
self->new_speed = 0;
} else {
/* Tell network layer that we want more frames */
netif_wake_queue(self->netdev);
}
self->stats.tx_packets++;
/*
* Reset Rx FIFO to make sure that all reflected transmit data
* is discarded. This is needed for half duplex operation
*/
fcr = irport_get_fcr(self->io.speed);
fcr |= UART_FCR_CLEAR_RCVR;
outb(fcr, iobase+UART_FCR);
/* Finished transmitting */
self->transmitting = 0;
/* Turn on receive interrupts */
outb(UART_IER_RDI, iobase+UART_IER);
IRDA_DEBUG(1, "%s() : finished Tx\n", __FUNCTION__);
}
}
/* /*
* Function irport_receive (self) * Function irport_receive (self)
* *
* Receive one frame from the infrared port * Receive one frame from the infrared port
* *
* Called only from irport_interrupt()
*/ */
static void irport_receive(struct irport_cb *self) static inline void irport_receive(struct irport_cb *self)
{ {
int boguscount = 0; int boguscount = 0;
int iobase; int iobase;
...@@ -739,40 +840,51 @@ irqreturn_t irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -739,40 +840,51 @@ irqreturn_t irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
iobase = self->io.sir_base; iobase = self->io.sir_base;
iir = inb(iobase+UART_IIR) & UART_IIR_ID; /* Cut'n'paste interrupt routine from serial.c
while (iir) { * This version try to minimise latency and I/O operations.
handled = 1; * Simplified and modified to enforce half duplex operation.
* - Jean II */
/* Clear interrupt */ /* Check status even is iir reg is cleared, more robust and
* eliminate a read on the I/O bus - Jean II */
do {
/* Get interrupt status ; Clear interrupt */
lsr = inb(iobase+UART_LSR); lsr = inb(iobase+UART_LSR);
/* Are we receiving or transmitting ? */
if(!self->transmitting) {
/* Received something ? */
if (lsr & UART_LSR_DR)
irport_receive(self);
} else {
/* Room in Tx fifo ? */
if (lsr & (UART_LSR_THRE | UART_LSR_TEMT))
irport_write_wakeup(self);
}
IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", /* A bit hackish, but working as expected... Jean II */
__FUNCTION__, iir, lsr, iobase); if(lsr & (UART_LSR_THRE | UART_LSR_TEMT | UART_LSR_DR))
handled = 1;
switch (iir) { /* Make sure we don't stay here to long */
case UART_IIR_RLSI: if (boguscount++ > 10) {
IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); WARNING("%s() irq handler looping : lsr=%02x\n",
break; __FUNCTION__, lsr);
case UART_IIR_RDI:
/* Receive interrupt */
irport_receive(self);
break;
case UART_IIR_THRI:
if (lsr & UART_LSR_THRE)
/* Transmitter ready for data */
irport_write_wakeup(self);
break;
default:
IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir);
break;
}
/* Make sure we don't stay here too long */
if (boguscount++ > 100)
break; break;
}
/* Read interrupt register */
iir = inb(iobase+UART_IIR);
/* Enable this debug only when no other options and at low
* bit rates, otherwise it may cause Rx overruns (lsr=63).
* - Jean II */
IRDA_DEBUG(6, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
__FUNCTION__, iir, lsr, iobase);
/* As long as interrupt pending... */
} while ((iir & UART_IIR_NO_INT) == 0);
iir = inb(iobase + UART_IIR) & UART_IIR_ID;
}
spin_unlock(&self->lock); spin_unlock(&self->lock);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
...@@ -800,8 +912,8 @@ int irport_net_open(struct net_device *dev) ...@@ -800,8 +912,8 @@ int irport_net_open(struct net_device *dev)
char hwname[16]; char hwname[16];
unsigned long flags; unsigned long flags;
IRDA_DEBUG(1, "%s()\n", __FUNCTION__); IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
ASSERT(dev != NULL, return -1;); ASSERT(dev != NULL, return -1;);
self = (struct irport_cb *) dev->priv; self = (struct irport_cb *) dev->priv;
...@@ -815,7 +927,12 @@ int irport_net_open(struct net_device *dev) ...@@ -815,7 +927,12 @@ int irport_net_open(struct net_device *dev)
} }
spin_lock_irqsave(&self->lock, flags); spin_lock_irqsave(&self->lock, flags);
/* Init uart */
irport_start(self); irport_start(self);
/* Set 9600 bauds per default, including at the dongle */
irda_task_execute(self, __irport_change_speed,
irport_change_speed_complete,
NULL, (void *) 9600);
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
...@@ -828,12 +945,9 @@ int irport_net_open(struct net_device *dev) ...@@ -828,12 +945,9 @@ int irport_net_open(struct net_device *dev)
*/ */
self->irlap = irlap_open(dev, &self->qos, hwname); self->irlap = irlap_open(dev, &self->qos, hwname);
/* FIXME: change speed of dongle */
/* Ready to play! */ /* Ready to play! */
netif_start_queue(dev); netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0; return 0;
} }
...@@ -873,40 +987,16 @@ int irport_net_close(struct net_device *dev) ...@@ -873,40 +987,16 @@ int irport_net_close(struct net_device *dev)
free_irq(self->io.irq, dev); free_irq(self->io.irq, dev);
MOD_DEC_USE_COUNT;
return 0; return 0;
} }
/*
* Function irport_wait_until_sent (self)
*
* Delay exectution until finished transmitting
*
*/
#if 0
void irport_wait_until_sent(struct irport_cb *self)
{
int iobase;
iobase = self->io.sir_base;
/* Wait until Tx FIFO is empty */
while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
IRDA_DEBUG(2, "%s(), waiting!\n", __FUNCTION__);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(MSECS_TO_JIFFIES(60));
}
}
#endif
/* /*
* Function irport_is_receiving (self) * Function irport_is_receiving (self)
* *
* Returns true is we are currently receiving data * Returns true is we are currently receiving data
* *
*/ */
static int irport_is_receiving(struct irport_cb *self) static inline int irport_is_receiving(struct irport_cb *self)
{ {
return (self->rx_buff.state != OUTSIDE_FRAME); return (self->rx_buff.state != OUTSIDE_FRAME);
} }
...@@ -998,6 +1088,12 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -998,6 +1088,12 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
break; break;
} }
/* Locking :
* irda_device_dongle_init() can't be locked.
* irda_task_execute() doesn't need to be locked.
* Jean II
*/
/* Initialize dongle */ /* Initialize dongle */
dongle = irda_device_dongle_init(dev, irq->ifr_dongle); dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
if (!dongle) if (!dongle)
......
...@@ -504,10 +504,7 @@ static int irtty_open(struct tty_struct *tty) ...@@ -504,10 +504,7 @@ static int irtty_open(struct tty_struct *tty)
struct sirtty_cb *priv; struct sirtty_cb *priv;
int ret = 0; int ret = 0;
/* unfortunately, there's no tty_ldisc->owner field /* Module stuff handled via irda_ldisc.owner - Jean II */
* so there is some window for SMP race with rmmod
*/
MOD_INC_USE_COUNT;
/* First make sure we're not already connected. */ /* First make sure we're not already connected. */
if (tty->disc_data != NULL) { if (tty->disc_data != NULL) {
...@@ -569,7 +566,6 @@ static int irtty_open(struct tty_struct *tty) ...@@ -569,7 +566,6 @@ static int irtty_open(struct tty_struct *tty)
out_put: out_put:
sirdev_put_instance(dev); sirdev_put_instance(dev);
out: out:
MOD_DEC_USE_COUNT;
return ret; return ret;
} }
...@@ -614,8 +610,6 @@ static void irtty_close(struct tty_struct *tty) ...@@ -614,8 +610,6 @@ static void irtty_close(struct tty_struct *tty)
tty->driver->stop(tty); tty->driver->stop(tty);
kfree(priv); kfree(priv);
MOD_DEC_USE_COUNT;
} }
/* ------------------------------------------------------- */ /* ------------------------------------------------------- */
...@@ -633,6 +627,7 @@ static struct tty_ldisc irda_ldisc = { ...@@ -633,6 +627,7 @@ static struct tty_ldisc irda_ldisc = {
.receive_buf = irtty_receive_buf, .receive_buf = irtty_receive_buf,
.receive_room = irtty_receive_room, .receive_room = irtty_receive_room,
.write_wakeup = irtty_write_wakeup, .write_wakeup = irtty_write_wakeup,
.owner = THIS_MODULE,
}; };
/* ------------------------------------------------------- */ /* ------------------------------------------------------- */
......
...@@ -1096,6 +1096,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) ...@@ -1096,6 +1096,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
* to make sure packets gets through the * to make sure packets gets through the
* proper xmit handler - Jean II */ * proper xmit handler - Jean II */
} }
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
...@@ -1120,6 +1121,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) ...@@ -1120,6 +1121,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
/* Restore bank register */ /* Restore bank register */
outb(bank, iobase+BSR); outb(bank, iobase+BSR);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -1164,6 +1166,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) ...@@ -1164,6 +1166,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
* the speed change has been done. * the speed change has been done.
* Jean II */ * Jean II */
} }
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
...@@ -1250,6 +1253,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) ...@@ -1250,6 +1253,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
/* Restore bank register */ /* Restore bank register */
outb(bank, iobase+BSR); outb(bank, iobase+BSR);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
......
...@@ -151,6 +151,13 @@ static int irda_thread(void *startup) ...@@ -151,6 +151,13 @@ static int irda_thread(void *startup)
while (irda_rq_queue.thread != NULL) { while (irda_rq_queue.thread != NULL) {
/* We use TASK_INTERRUPTIBLE, rather than
* TASK_UNINTERRUPTIBLE. Andrew Morton made this
* change ; he told me that it is safe, because "signal
* blocking is now handled in daemonize()", he added
* that the problem is that "uninterruptible sleep
* contributes to load average", making user worry.
* Jean II */
set_task_state(current, TASK_INTERRUPTIBLE); set_task_state(current, TASK_INTERRUPTIBLE);
add_wait_queue(&irda_rq_queue.kick, &wait); add_wait_queue(&irda_rq_queue.kick, &wait);
if (list_empty(&irda_rq_queue.request_list)) if (list_empty(&irda_rq_queue.request_list))
......
...@@ -529,6 +529,9 @@ static int __init ircc_open(unsigned int fir_base, unsigned int sir_base) ...@@ -529,6 +529,9 @@ static int __init ircc_open(unsigned int fir_base, unsigned int sir_base)
irport->priv = self; irport->priv = self;
/* Keep track of module usage */
SET_MODULE_OWNER(self->netdev);
/* Initialize IO */ /* Initialize IO */
self->io = &irport->io; self->io = &irport->io;
self->io->fir_base = fir_base; self->io->fir_base = fir_base;
...@@ -747,6 +750,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -747,6 +750,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */ /* Check for empty frame */
if (!skb->len) { if (!skb->len) {
ircc_change_speed(self, speed); ircc_change_speed(self, speed);
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->irport->lock, flags); spin_unlock_irqrestore(&self->irport->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
...@@ -776,6 +780,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -776,6 +780,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Transmit frame */ /* Transmit frame */
ircc_dma_xmit(self, iobase, 0); ircc_dma_xmit(self, iobase, 0);
} }
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->irport->lock, flags); spin_unlock_irqrestore(&self->irport->lock, flags);
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -1090,8 +1095,6 @@ static int ircc_net_open(struct net_device *dev) ...@@ -1090,8 +1095,6 @@ static int ircc_net_open(struct net_device *dev)
WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io->dma); WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io->dma);
return -EAGAIN; return -EAGAIN;
} }
MOD_INC_USE_COUNT;
return 0; return 0;
} }
...@@ -1124,8 +1127,6 @@ static int ircc_net_close(struct net_device *dev) ...@@ -1124,8 +1127,6 @@ static int ircc_net_close(struct net_device *dev)
free_dma(self->io->dma); free_dma(self->io->dma);
MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -1187,6 +1188,9 @@ static int __exit ircc_close(struct ircc_cb *self) ...@@ -1187,6 +1188,9 @@ static int __exit ircc_close(struct ircc_cb *self)
iobase = self->irport->io.fir_base; iobase = self->irport->io.fir_base;
if (self->pmdev)
pm_unregister(self->pmdev);
/* This will destroy irport */ /* This will destroy irport */
irport_close(self->irport); irport_close(self->irport);
......
/*********************************************************************
* $Id: smsc-ircc2.c,v 1.19.2.5 2002/10/27 11:34:26 dip Exp $
*
* Description: Driver for the SMC Infrared Communications Controller
* Status: Experimental.
* Author: Daniele Peri (peri@csai.unipa.it)
* Created at:
* Modified at:
* Modified by:
*
* Copyright (c) 2002 Daniele Peri
* All Rights Reserved.
* Copyright (c) 2002 Jean Tourrilhes
*
*
* Based on smc-ircc.c:
*
* Copyright (c) 2001 Stefani Seibold
* Copyright (c) 1999-2001 Dag Brattli
* Copyright (c) 1998-1999 Thomas Davis,
*
* and irport.c:
*
* Copyright (c) 1997, 1998, 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.
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
#include <linux/serial_reg.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h>
#include "smsc-ircc2.h"
#include "smsc-sio.h"
/* Types */
struct smsc_transceiver {
char *name;
void (*set_for_speed)(int fir_base, u32 speed);
int (*probe)(int fir_base);
};
typedef struct smsc_transceiver smsc_transceiver_t;
#if 0
struct smc_chip {
char *name;
u16 flags;
u8 devid;
u8 rev;
};
typedef struct smc_chip smc_chip_t;
#endif
struct smsc_chip {
char *name;
#if 0
u8 type;
#endif
u16 flags;
u8 devid;
u8 rev;
};
typedef struct smsc_chip smsc_chip_t;
struct smsc_chip_address {
unsigned int cfg_base;
unsigned int type;
};
typedef struct smsc_chip_address smsc_chip_address_t;
/* Private data for each instance */
struct smsc_ircc_cb {
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct net_device_stats stats;
struct irlap_cb *irlap; /* The link layer we are binded to */
chipio_t io; /* IrDA controller information */
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
struct qos_info qos; /* QoS capabilities for this device */
spinlock_t lock; /* For serializing operations */
__u32 new_speed;
__u32 flags; /* Interface flags */
int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
int tx_len; /* Number of frames in tx_buff */
int transceiver;
struct pm_dev *pmdev;
};
/* Constants */
static const char *driver_name = "smsc-ircc2";
#define DIM(x) (sizeof(x)/(sizeof(*(x))))
#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600
#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1
#define SMSC_IRCC2_C_NET_TIMEOUT 0
#define SMSC_IRCC2_C_SIR_STOP 0
/* Prototypes */
static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq);
static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base);
static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq);
static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self);
static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self);
static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self);
static void smsc_ircc_init_chip(struct smsc_ircc_cb *self);
static int __exit smsc_ircc_close(struct smsc_ircc_cb *self);
static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase);
static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase);
static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self);
static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs);
static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase);
static void smsc_ircc_change_speed(void *priv, u32 speed);
static void smsc_ircc_set_sir_speed(void *priv, u32 speed);
static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void smsc_ircc_interrupt_sir(int irq, void *dev_id, struct pt_regs *regs);
static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
#if SMSC_IRCC2_C_SIR_STOP
static void smsc_ircc_sir_stop(struct smsc_ircc_cb *self);
#endif
static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self);
static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);
static int smsc_ircc_net_init(struct net_device *dev);
static int smsc_ircc_net_open(struct net_device *dev);
static int smsc_ircc_net_close(struct net_device *dev);
static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
#if SMSC_IRCC2_C_NET_TIMEOUT
static void smsc_ircc_timeout(struct net_device *dev);
#endif
static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev);
static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self);
static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self);
static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed);
static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
/* Probing */
static int __init smsc_ircc_look_for_chips(void);
static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type);
static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
static int __init smsc_superio_fdc(unsigned short cfg_base);
static int __init smsc_superio_lpc(unsigned short cfg_base);
/* Transceivers specific functions */
static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed);
static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base);
static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed);
static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base);
static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed);
static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base);
/* Power Management */
static void smsc_ircc_suspend(struct smsc_ircc_cb *self);
static void smsc_ircc_wakeup(struct smsc_ircc_cb *self);
static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
/* Transceivers for SMSC-ircc */
smsc_transceiver_t smsc_transceivers[]=
{
{ "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800},
{ "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select},
{ "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc},
{ NULL, NULL}
};
#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (DIM(smsc_transceivers)-1)
/* SMC SuperIO chipsets definitions */
#define KEY55_1 0 /* SuperIO Configuration mode with Key <0x55> */
#define KEY55_2 1 /* SuperIO Configuration mode with Key <0x55,0x55> */
#define NoIRDA 2 /* SuperIO Chip has no IRDA Port */
#define SIR 0 /* SuperIO Chip has only slow IRDA */
#define FIR 4 /* SuperIO Chip has fast IRDA */
#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */
static smsc_chip_t __initdata fdc_chips_flat[]=
{
/* Base address 0x3f0 or 0x370 */
{ "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */
{ "37C665GT", KEY55_2|NoIRDA, 0x65, 0x01 },
{ "37C665GT", KEY55_2|NoIRDA, 0x66, 0x01 },
{ "37C669", KEY55_2|SIR|SERx4, 0x03, 0x02 },
{ "37C669", KEY55_2|SIR|SERx4, 0x04, 0x02 }, /* ID? */
{ "37C78", KEY55_2|NoIRDA, 0x78, 0x00 },
{ "37N769", KEY55_1|FIR|SERx4, 0x28, 0x00 },
{ "37N869", KEY55_1|FIR|SERx4, 0x29, 0x00 },
{ NULL }
};
static smsc_chip_t __initdata fdc_chips_paged[]=
{
/* Base address 0x3f0 or 0x370 */
{ "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 },
{ "37B77X", KEY55_1|SIR|SERx4, 0x43, 0x00 },
{ "37B78X", KEY55_1|SIR|SERx4, 0x44, 0x00 },
{ "37B80X", KEY55_1|SIR|SERx4, 0x42, 0x00 },
{ "37C67X", KEY55_1|FIR|SERx4, 0x40, 0x00 },
{ "37C93X", KEY55_2|SIR|SERx4, 0x02, 0x01 },
{ "37C93XAPM", KEY55_1|SIR|SERx4, 0x30, 0x01 },
{ "37C93XFR", KEY55_2|FIR|SERx4, 0x03, 0x01 },
{ "37M707", KEY55_1|SIR|SERx4, 0x42, 0x00 },
{ "37M81X", KEY55_1|SIR|SERx4, 0x4d, 0x00 },
{ "37N958FR", KEY55_1|FIR|SERx4, 0x09, 0x04 },
{ "37N971", KEY55_1|FIR|SERx4, 0x0a, 0x00 },
{ "37N972", KEY55_1|FIR|SERx4, 0x0b, 0x00 },
{ NULL }
};
static smsc_chip_t __initdata lpc_chips_flat[]=
{
/* Base address 0x2E or 0x4E */
{ "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 },
{ "47N267", KEY55_1|FIR|SERx4, 0x5e, 0x00 },
{ NULL }
};
static smsc_chip_t __initdata lpc_chips_paged[]=
{
/* Base address 0x2E or 0x4E */
{ "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 },
{ "47B37X", KEY55_1|SIR|SERx4, 0x52, 0x00 },
{ "47M10X", KEY55_1|SIR|SERx4, 0x59, 0x00 },
{ "47M120", KEY55_1|NoIRDA|SERx4, 0x5c, 0x00 },
{ "47M13X", KEY55_1|SIR|SERx4, 0x59, 0x00 },
{ "47M14X", KEY55_1|SIR|SERx4, 0x5f, 0x00 },
{ "47N252", KEY55_1|FIR|SERx4, 0x0e, 0x00 },
{ "47S42X", KEY55_1|SIR|SERx4, 0x57, 0x00 },
{ NULL }
};
#define SMSCSIO_TYPE_FDC 1
#define SMSCSIO_TYPE_LPC 2
#define SMSCSIO_TYPE_FLAT 4
#define SMSCSIO_TYPE_PAGED 8
static smsc_chip_address_t __initdata possible_addresses[]=
{
{0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
{0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
{0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
{0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
{0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
{0,0}
};
/* Globals */
static struct smsc_ircc_cb *dev_self[] = { NULL, NULL};
static int ircc_irq=255;
static int ircc_dma=255;
static int ircc_fir=0;
static int ircc_sir=0;
static int ircc_cfg=0;
static int ircc_transceiver=0;
static unsigned short dev_count=0;
static inline void register_bank(int iobase, int bank)
{
outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)),
iobase+IRCC_MASTER);
}
/*******************************************************************************
*
*
* SMSC-ircc stuff
*
*
*******************************************************************************/
/*
* Function smsc_ircc_init ()
*
* Initialize chip. Just try to find out how many chips we are dealing with
* and where they are
*/
int __init smsc_ircc_init(void)
{
int ret=-ENODEV;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
dev_count=0;
if ((ircc_fir>0)&&(ircc_sir>0)) {
MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq) == 0)
return 0;
return -ENODEV;
}
/* try user provided configuration register base address */
if (ircc_cfg>0) {
MESSAGE(" Overriding configuration address 0x%04x\n", ircc_cfg);
if (!smsc_superio_fdc(ircc_cfg))
ret = 0;
if (!smsc_superio_lpc(ircc_cfg))
ret = 0;
}
if(smsc_ircc_look_for_chips()>0) ret = 0;
return ret;
}
/*
* Function smsc_ircc_open (firbase, sirbase, dma, irq)
*
* Try to open driver instance
*
*/
static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
{
struct smsc_ircc_cb *self;
int err;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
err= smsc_ircc_present(fir_base, sir_base);
if(err) return -ENODEV;
if (dev_count>DIM(dev_self)) {
WARNING("%s(), too many devices!\n", __FUNCTION__);
return -ENOMEM;
}
/*
* Allocate new instance of the driver
*/
self = kmalloc(sizeof(struct smsc_ircc_cb), GFP_KERNEL);
if (self == NULL) {
ERROR("%s, Can't allocate memory for control block!\n",
driver_name);
return -ENOMEM;
}
memset(self, 0, sizeof(struct smsc_ircc_cb));
/* Need to store self somewhere */
dev_self[dev_count++] = self;
spin_lock_init(&self->lock);
err = smsc_ircc_setup_buffers(self);
if(err) return err;
err= smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
if(err) return err;
smsc_ircc_setup_qos(self);
self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
smsc_ircc_init_chip(self);
if(ircc_transceiver > 0 && ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS) self->transceiver = ircc_transceiver;
else smsc_ircc_probe_transceiver(self);
err = smsc_ircc_setup_netdev(self);
if(err) return err;
self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, smsc_ircc_pmproc);
if (self->pmdev)
self->pmdev->data = self;
return 0;
}
/*
* Function smsc_ircc_present(fir_base, sir_base)
*
* Check the smsc-ircc chip presence
*
*/
static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
{
unsigned char low, high, chip, config, dma, irq, version;
if (check_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT) < 0) {
WARNING("%s: can't get fir_base of 0x%03x\n",
__FUNCTION__, fir_base);
return -ENODEV;
}
#if POSSIBLE_USED_BY_SERIAL_DRIVER
if (check_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT) < 0) {
WARNING("%s: can't get sir_base of 0x%03x\n",
__FUNCTION__, sir_base);
return -ENODEV;
}
#endif
register_bank(fir_base, 3);
high = inb(fir_base+IRCC_ID_HIGH);
low = inb(fir_base+IRCC_ID_LOW);
chip = inb(fir_base+IRCC_CHIP_ID);
version = inb(fir_base+IRCC_VERSION);
config = inb(fir_base+IRCC_INTERFACE);
dma = config & IRCC_INTERFACE_DMA_MASK;
irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
WARNING("%s(), addr 0x%04x - no device found!\n",
__FUNCTION__, fir_base);
return -ENODEV;
}
MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, "
"firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
chip & 0x0f, version, fir_base, sir_base, dma, irq);
return 0;
}
/*
* Function smsc_ircc_setup_buffers(self)
*
* Setup RX/TX buffers
*
*/
static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self)
{
self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
self->rx_buff.head = (u8 *) kmalloc(self->rx_buff.truesize,
GFP_KERNEL|GFP_DMA);
if (self->rx_buff.head == NULL) {
ERROR("%s, Can't allocate memory for receive buffer!\n",
driver_name);
kfree(self);
return -ENOMEM;
}
self->tx_buff.head = (u8 *) kmalloc(self->tx_buff.truesize,
GFP_KERNEL|GFP_DMA);
if (self->tx_buff.head == NULL) {
ERROR("%s, Can't allocate memory for transmit buffer!\n",
driver_name);
kfree(self->rx_buff.head);
kfree(self);
return -ENOMEM;
}
memset(self->rx_buff.head, 0, self->rx_buff.truesize);
memset(self->tx_buff.head, 0, self->tx_buff.truesize);
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;
return 0;
}
/*
* Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq)
*
* Setup I/O
*
*/
static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
{
unsigned char config, chip_dma, chip_irq;
void *ret;
register_bank(fir_base, 3);
config = inb(fir_base+IRCC_INTERFACE);
chip_dma = config & IRCC_INTERFACE_DMA_MASK;
chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
self->io.fir_base = fir_base;
self->io.sir_base = sir_base;
self->io.fir_ext = SMSC_IRCC2_FIR_CHIP_IO_EXTENT;
self->io.sir_ext = SMSC_IRCC2_SIR_CHIP_IO_EXTENT;
self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE;
self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED;
if (irq < 255) {
if (irq != chip_irq)
MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
driver_name, chip_irq, irq);
self->io.irq = irq;
}
else
self->io.irq = chip_irq;
if (dma < 255) {
if (dma != chip_dma)
MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
driver_name, chip_dma, dma);
self->io.dma = dma;
}
else
self->io.dma = chip_dma;
ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
if (!ret) {
WARNING("%s(), can't get iobase of 0x%03x\n",
__FUNCTION__, self->io.fir_base);
kfree(self->tx_buff.head);
kfree(self->rx_buff.head);
kfree(self);
return -ENODEV;
}
ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name);
if (!ret) {
WARNING("%s(), can't get iobase of 0x%03x\n",
__FUNCTION__, self->io.sir_base);
release_region(self->io.fir_base, self->io.fir_ext);
kfree(self->tx_buff.head);
kfree(self->rx_buff.head);
kfree(self);
return -ENODEV;
}
return 0;
}
/*
* Function smsc_ircc_setup_qos(self)
*
* Setup qos
*
*/
static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
{
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos);
self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME;
self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE;
irda_qos_bits_to_value(&self->qos);
}
/*
* Function smsc_ircc_init_chip(self)
*
* Init chip
*
*/
static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
{
int iobase, ir_mode, ctrl, fast;
ASSERT( self != NULL, return; );
iobase = self->io.fir_base;
ir_mode = IRCC_CFGA_IRDA_SIR_A;
ctrl = 0;
fast = 0;
register_bank(iobase, 0);
outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
outb(0x00, iobase+IRCC_MASTER);
register_bank(iobase, 1);
outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode),
iobase+IRCC_SCE_CFGA);
#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */
outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
iobase+IRCC_SCE_CFGB);
#else
outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
iobase+IRCC_SCE_CFGB);
#endif
(void) inb(iobase+IRCC_FIFO_THRESHOLD);
outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase+IRCC_FIFO_THRESHOLD);
register_bank(iobase, 4);
outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
register_bank(iobase, 0);
outb(fast, iobase+IRCC_LCR_A);
smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
/* Power on device */
outb(0x00, iobase+IRCC_MASTER);
}
/*
* Function smsc_ircc_setup_netdev(self)
*
* Alloc and setup network device
*
*/
static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self)
{
struct net_device *dev;
int err;
/* Alloc netdev */
if (!(dev = dev_alloc("irda%d", &err))) {
ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
kfree(self->tx_buff.head);
kfree(self->rx_buff.head);
kfree(self);
return -ENOMEM;
}
dev->priv = (void *) self;
self->netdev = dev;
dev->init = smsc_ircc_net_init;
dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
#if SMSC_IRCC2_C_NET_TIMEOUT
dev->tx_timeout = smsc_ircc_timeout;
dev->watchdog_timeo = HZ*2; /* Allow enough time for speed change */
#endif
dev->open = smsc_ircc_net_open;
dev->stop = smsc_ircc_net_close;
dev->do_ioctl = smsc_ircc_net_ioctl;
dev->get_stats = smsc_ircc_net_get_stats;
/* Make ifconfig display some details */
dev->base_addr = self->io.fir_base;
dev->irq = self->io.irq;
rtnl_lock();
err = register_netdevice(dev);
rtnl_unlock();
if (err) {
ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
kfree(self->tx_buff.head);
kfree(self->rx_buff.head);
kfree(self);
return -ENODEV;
}
MESSAGE("IrDA: Registered device %s\n", dev->name);
return 0;
}
/*
* Function smsc_ircc_net_ioctl (dev, rq, cmd)
*
* Process IOCTL commands for this device
*
*/
static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *) rq;
struct smsc_ircc_cb *self;
unsigned long flags;
int ret = 0;
ASSERT(dev != NULL, return -1;);
self = dev->priv;
ASSERT(self != NULL, return -1;);
IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else {
/* Make sure we are the only one touching
* self->io.speed and the hardware - Jean II */
spin_lock_irqsave(&self->lock, flags);
smsc_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;
break;
}
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
irq->ifr_receiving = smsc_ircc_is_receiving(self);
break;
#if 0
case SIOCSDTRRTS:
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
break;
#endif
default:
ret = -EOPNOTSUPP;
}
return ret;
}
static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
{
struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) dev->priv;
return &self->stats;
}
#if SMSC_IRCC2_C_NET_TIMEOUT
/*
* Function smsc_ircc_timeout (struct net_device *dev)
*
* The networking timeout management.
*
*/
static void smsc_ircc_timeout(struct net_device *dev)
{
struct smsc_ircc_cb *self;
unsigned long flags;
self = (struct smsc_ircc_cb *) dev->priv;
WARNING("%s: transmit timed out, changing speed to: %d\n", dev->name, self->io.speed);
spin_lock_irqsave(&self->lock, flags);
smsc_ircc_sir_start(self);
smsc_ircc_change_speed(self, self->io.speed);
dev->trans_start = jiffies;
netif_wake_queue(dev);
spin_unlock_irqrestore(&self->lock, flags);
}
#endif
/*
* Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev)
*
* Transmits the current frame until FIFO is full, then
* waits until the next transmit interrupt, and continues until the
* frame is transmitted.
*/
int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
{
struct smsc_ircc_cb *self;
unsigned long flags;
int iobase;
s32 speed;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
ASSERT(dev != NULL, return 0;);
self = (struct smsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
iobase = self->io.sir_base;
netif_stop_queue(dev);
/* Make sure test of self->io.speed & 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) {
/*
* We send frames one by one in SIR mode (no
* pipelining), so at this point, if we were sending
* a previous frame, we just received the interrupt
* telling us it is finished (UART_IIR_THRI).
* Therefore, waiting for the transmitter to really
* finish draining the fifo won't take too long.
* And the interrupt handler is not expected to run.
* - Jean II */
smsc_ircc_sir_wait_hw_transmitter_finish(self);
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
} else {
self->new_speed = speed;
}
}
/* Init tx buffer */
self->tx_buff.data = self->tx_buff.head;
/* Copy skb to tx_buff while wrapping, stuffing and making CRC */
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
self->stats.tx_bytes += self->tx_buff.len;
/* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
}
/*
* Function smsc_ircc_set_fir_speed (self, baud)
*
* Change the speed of the device
*
*/
static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed)
{
int fir_base, ir_mode, ctrl, fast;
ASSERT(self != NULL, return;);
fir_base = self->io.fir_base;
self->io.speed = speed;
switch(speed) {
default:
case 576000:
ir_mode = IRCC_CFGA_IRDA_HDLC;
ctrl = IRCC_CRC;
fast = 0;
IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__);
break;
case 1152000:
ir_mode = IRCC_CFGA_IRDA_HDLC;
ctrl = IRCC_1152 | IRCC_CRC;
fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA;
IRDA_DEBUG(0, "%s(), handling baud of 1152000\n",
__FUNCTION__);
break;
case 4000000:
ir_mode = IRCC_CFGA_IRDA_4PPM;
ctrl = IRCC_CRC;
fast = IRCC_LCR_A_FAST;
IRDA_DEBUG(0, "%s(), handling baud of 4000000\n",
__FUNCTION__);
break;
}
#if 0
Now in tranceiver!
/* This causes an interrupt */
register_bank(fir_base, 0);
outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast, fir_base+IRCC_LCR_A);
#endif
register_bank(fir_base, 1);
outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base+IRCC_SCE_CFGA);
register_bank(fir_base, 4);
outb((inb(fir_base+IRCC_CONTROL) & 0x30) | ctrl, fir_base+IRCC_CONTROL);
}
/*
* Function smsc_ircc_fir_start(self)
*
* Change the speed of the device
*
*/
static void smsc_ircc_fir_start(struct smsc_ircc_cb *self)
{
struct net_device *dev;
int fir_base;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
ASSERT(self != NULL, return;);
dev = self->netdev;
ASSERT(dev != NULL, return;);
fir_base = self->io.fir_base;
/* Reset everything */
/* Install FIR transmit handler */
dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
/* Clear FIFO */
outb(inb(fir_base+IRCC_LCR_A)|IRCC_LCR_A_FIFO_RESET, fir_base+IRCC_LCR_A);
/* Enable interrupt */
/*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);*/
register_bank(fir_base, 1);
/* Select the TX/RX interface */
#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */
outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
fir_base+IRCC_SCE_CFGB);
#else
outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
fir_base+IRCC_SCE_CFGB);
#endif
(void) inb(fir_base+IRCC_FIFO_THRESHOLD);
/* Enable SCE interrupts */
outb(0, fir_base+IRCC_MASTER);
register_bank(fir_base, 0);
outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);
outb(IRCC_MASTER_INT_EN, fir_base+IRCC_MASTER);
}
/*
* Function smsc_ircc_fir_stop(self, baud)
*
* Change the speed of the device
*
*/
static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self)
{
int fir_base;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
ASSERT(self != NULL, return;);
fir_base = self->io.fir_base;
register_bank(fir_base, 0);
/*outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);*/
outb(inb(fir_base+IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base+IRCC_LCR_B);
}
/*
* Function smsc_ircc_change_speed(self, baud)
*
* Change the speed of the device
*
* This function *must* be called with spinlock held, because it may
* be called from the irq handler. - Jean II
*/
static void smsc_ircc_change_speed(void *priv, u32 speed)
{
struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
struct net_device *dev;
int iobase;
int last_speed_was_sir;
IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed);
ASSERT(self != NULL, return;);
dev = self->netdev;
iobase = self->io.fir_base;
last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED;
#if 0
/* Temp Hack */
speed= 1152000;
self->io.speed = speed;
last_speed_was_sir = 0;
smsc_ircc_fir_start(self);
#endif
if(self->io.speed == 0)
smsc_ircc_sir_start(self);
#if 0
if(!last_speed_was_sir) speed = self->io.speed;
#endif
if(self->io.speed != speed) smsc_ircc_set_transceiver_for_speed(self, speed);
self->io.speed = speed;
if(speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
if(!last_speed_was_sir) {
smsc_ircc_fir_stop(self);
smsc_ircc_sir_start(self);
}
smsc_ircc_set_sir_speed(self, speed);
}
else {
if(last_speed_was_sir) {
#if SMSC_IRCC2_C_SIR_STOP
smsc_ircc_sir_stop(self);
#endif
smsc_ircc_fir_start(self);
}
smsc_ircc_set_fir_speed(self, speed);
#if 0
self->tx_buff.len = 10;
self->tx_buff.data = self->tx_buff.head;
smsc_ircc_dma_xmit(self, iobase, 4000);
#endif
/* Be ready for incoming frames */
smsc_ircc_dma_receive(self, iobase);
}
netif_wake_queue(dev);
}
/*
* Function smsc_ircc_set_sir_speed (self, speed)
*
* Set speed of IrDA port to specified baudrate
*
*/
void smsc_ircc_set_sir_speed(void *priv, __u32 speed)
{
struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
int iobase;
int fcr; /* FIFO control reg */
int lcr; /* Line control reg */
int divisor;
IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __FUNCTION__, speed);
ASSERT(self != NULL, return;);
iobase = self->io.sir_base;
/* Update accounting for new speed */
self->io.speed = speed;
/* Turn off interrupts */
outb(0, iobase+UART_IER);
divisor = SMSC_IRCC2_MAX_SIR_SPEED/speed;
fcr = UART_FCR_ENABLE_FIFO;
/*
* Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
* almost 1,7 ms at 19200 bps. At speeds above that we can just forget
* about this timeout since it will always be fast enough.
*/
if (self->io.speed < 38400)
fcr |= UART_FCR_TRIGGER_1;
else
fcr |= UART_FCR_TRIGGER_14;
/* IrDA ports use 8N1 */
lcr = UART_LCR_WLEN8;
outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */
outb(divisor >> 8, iobase+UART_DLM);
outb(lcr, iobase+UART_LCR); /* Set 8N1 */
outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
/* Turn on interrups */
outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed);
}
/*
* Function smsc_ircc_hard_xmit_fir (skb, dev)
*
* Transmit the frame!
*
*/
static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
{
struct smsc_ircc_cb *self;
unsigned long flags;
s32 speed;
int iobase;
int mtt;
ASSERT(dev != NULL, return 0;);
self = (struct smsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
iobase = self->io.fir_base;
netif_stop_queue(dev);
/* Make sure test of self->io.speed & speed change are atomic */
spin_lock_irqsave(&self->lock, flags);
/* 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) {
/* 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 */
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
} else
self->new_speed = speed;
}
memcpy(self->tx_buff.head, skb->data, skb->len);
self->tx_buff.len = skb->len;
self->tx_buff.data = self->tx_buff.head;
mtt = irda_get_mtt(skb);
if (mtt) {
int bofs;
/*
* Compute how many BOFs (STA or PA's) we need to waste the
* min turn time given the speed of the link.
*/
bofs = mtt * (self->io.speed / 1000) / 8000;
if (bofs > 4095)
bofs = 4095;
smsc_ircc_dma_xmit(self, iobase, bofs);
} else {
/* Transmit frame */
smsc_ircc_dma_xmit(self, iobase, 0);
}
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
}
/*
* Function smsc_ircc_dma_xmit (self, iobase)
*
* Transmit data using DMA
*
*/
static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs)
{
u8 ctrl;
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 1
/* Disable Rx */
register_bank(iobase, 0);
outb(0x00, iobase+IRCC_LCR_B);
#endif
register_bank(iobase, 1);
outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
iobase+IRCC_SCE_CFGB);
self->io.direction = IO_XMIT;
/* Set BOF additional count for generating the min turn time */
register_bank(iobase, 4);
outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);
ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;
outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);
/* Set max Tx frame size */
outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);
outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
/*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/
/* Enable burst mode chip Tx DMA */
register_bank(iobase, 1);
outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
/* Setup DMA controller (must be done after enabling chip DMA) */
setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len,
DMA_TX_MODE);
/* Enable interrupt */
register_bank(iobase, 0);
outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
/* Enable transmit */
outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
}
/*
* Function smsc_ircc_dma_xmit_complete (self)
*
* The transfer of a frame in finished. This function will only be called
* by the interrupt handler
*
*/
static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase)
{
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 0
/* Disable Tx */
register_bank(iobase, 0);
outb(0x00, iobase+IRCC_LCR_B);
#endif
register_bank(self->io.fir_base, 1);
outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
self->io.fir_base+IRCC_SCE_CFGB);
/* Check for underrun! */
register_bank(iobase, 0);
if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {
self->stats.tx_errors++;
self->stats.tx_fifo_errors++;
/* Reset error condition */
register_bank(iobase, 0);
outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);
outb(0x00, iobase+IRCC_MASTER);
} else {
self->stats.tx_packets++;
self->stats.tx_bytes += self->tx_buff.len;
}
/* Check if it's time to change the speed */
if (self->new_speed) {
smsc_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
}
netif_wake_queue(self->netdev);
}
/*
* Function smsc_ircc_dma_receive(self)
*
* Get ready for receiving a frame. The device will initiate a DMA
* if it starts to receive a frame.
*
*/
static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase)
{
#if 0
/* Turn off chip DMA */
register_bank(iobase, 1);
outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
iobase+IRCC_SCE_CFGB);
#endif
/* Disable Tx */
register_bank(iobase, 0);
outb(0x00, iobase+IRCC_LCR_B);
/* Turn off chip DMA */
register_bank(iobase, 1);
outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
iobase+IRCC_SCE_CFGB);
self->io.direction = IO_RECV;
self->rx_buff.data = self->rx_buff.head;
/* Set max Rx frame size */
register_bank(iobase, 4);
outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
/* Setup DMA controller */
setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize,
DMA_RX_MODE);
/* Enable burst mode chip Rx DMA */
register_bank(iobase, 1);
outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
/* Enable interrupt */
register_bank(iobase, 0);
outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
/* Enable receiver */
register_bank(iobase, 0);
outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
iobase+IRCC_LCR_B);
return 0;
}
/*
* Function smsc_ircc_dma_receive_complete(self, iobase)
*
* Finished with receiving frames
*
*/
static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase)
{
struct sk_buff *skb;
int len, msgcnt, lsr;
register_bank(iobase, 0);
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 0
/* Disable Rx */
register_bank(iobase, 0);
outb(0x00, iobase+IRCC_LCR_B);
#endif
register_bank(iobase, 0);
outb(inb(iobase+IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase+IRCC_LSAR);
lsr= inb(iobase+IRCC_LSR);
msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__,
get_dma_residue(self->io.dma));
len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
/* Look for errors
*/
if(lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
self->stats.rx_errors++;
if(lsr & IRCC_LSR_FRAME_ERROR) self->stats.rx_frame_errors++;
if(lsr & IRCC_LSR_CRC_ERROR) self->stats.rx_crc_errors++;
if(lsr & IRCC_LSR_SIZE_ERROR) self->stats.rx_length_errors++;
if(lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) self->stats.rx_length_errors++;
return;
}
/* Remove CRC */
if (self->io.speed < 4000000)
len -= 2;
else
len -= 4;
if ((len < 2) || (len > 2050)) {
WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
return;
}
IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len);
skb = dev_alloc_skb(len+1);
if (!skb) {
WARNING("%s(), memory squeeze, dropping frame.\n",
__FUNCTION__);
return;
}
/* Make sure IP header gets aligned */
skb_reserve(skb, 1);
memcpy(skb_put(skb, len), self->rx_buff.data, len);
self->stats.rx_packets++;
self->stats.rx_bytes += len;
skb->dev = self->netdev;
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_IRDA);
netif_rx(skb);
}
/*
* Function smsc_ircc_sir_receive (self)
*
* Receive one frame from the infrared port
*
*/
static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
{
int boguscount = 0;
int iobase;
ASSERT(self != NULL, return;);
iobase = self->io.sir_base;
/*
* Receive all characters in Rx FIFO, unwrap and unstuff them.
* async_unwrap_char will deliver all found frames
*/
do {
async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
inb(iobase+UART_RX));
/* Make sure we don't stay here to long */
if (boguscount++ > 32) {
IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__);
break;
}
} while (inb(iobase+UART_LSR) & UART_LSR_DR);
}
/*
* Function smsc_ircc_interrupt (irq, dev_id, regs)
*
* An interrupt from the chip has arrived. Time to do some work
*
*/
static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct smsc_ircc_cb *self;
int iobase, iir, lcra, lsr;
if (dev == NULL) {
printk(KERN_WARNING "%s: irq %d for unknown device.\n",
driver_name, irq);
return IRQ_NONE;
}
self = (struct smsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return IRQ_NONE;);
/* Serialise the interrupt handler in various CPUs, stop Tx path */
spin_lock(&self->lock);
/* Check if we should use the SIR interrupt handler */
if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
smsc_ircc_interrupt_sir(irq, dev_id, regs);
spin_unlock(&self->lock);
return IRQ_HANDLED;
}
iobase = self->io.fir_base;
register_bank(iobase, 0);
iir = inb(iobase+IRCC_IIR);
/* Disable interrupts */
outb(0, iobase+IRCC_IER);
lcra = inb(iobase+IRCC_LCR_A);
lsr = inb(iobase+IRCC_LSR);
IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir);
if (iir & IRCC_IIR_EOM) {
if (self->io.direction == IO_RECV)
smsc_ircc_dma_receive_complete(self, iobase);
else
smsc_ircc_dma_xmit_complete(self, iobase);
smsc_ircc_dma_receive(self, iobase);
}
if (iir & IRCC_IIR_ACTIVE_FRAME) {
/*printk(KERN_WARNING __FUNCTION__ "(): Active Frame\n");*/
}
/* Enable interrupts again */
register_bank(iobase, 0);
outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
spin_unlock(&self->lock);
return IRQ_HANDLED;
}
/*
* Function irport_interrupt_sir (irq, dev_id, regs)
*
* Interrupt handler for SIR modes
*/
void smsc_ircc_interrupt_sir(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct smsc_ircc_cb *self;
int boguscount = 0;
int iobase;
int iir, lsr;
if (!dev) {
WARNING("%s() irq %d for unknown device.\n",
__FUNCTION__, irq);
return;
}
self = (struct smsc_ircc_cb *) dev->priv;
/* Already locked comming here in smsc_ircc_interrupt() */
/*spin_lock(&self->lock);*/
iobase = self->io.sir_base;
iir = inb(iobase+UART_IIR) & UART_IIR_ID;
while (iir) {
/* Clear interrupt */
lsr = inb(iobase+UART_LSR);
IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
__FUNCTION__, iir, lsr, iobase);
switch (iir) {
case UART_IIR_RLSI:
IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__);
break;
case UART_IIR_RDI:
/* Receive interrupt */
smsc_ircc_sir_receive(self);
break;
case UART_IIR_THRI:
if (lsr & UART_LSR_THRE)
/* Transmitter ready for data */
smsc_ircc_sir_write_wakeup(self);
break;
default:
IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",
__FUNCTION__, iir);
break;
}
/* Make sure we don't stay here to long */
if (boguscount++ > 100)
break;
iir = inb(iobase + UART_IIR) & UART_IIR_ID;
}
/*spin_unlock(&self->lock);*/
}
#if 0 /* unused */
/*
* Function ircc_is_receiving (self)
*
* Return TRUE is we are currently receiving a frame
*
*/
static int ircc_is_receiving(struct smsc_ircc_cb *self)
{
int status = FALSE;
/* int iobase; */
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
ASSERT(self != NULL, return FALSE;);
IRDA_DEBUG(0, "%s: dma count = %d\n", __FUNCTION__,
get_dma_residue(self->io.dma));
status = (self->rx_buff.state != OUTSIDE_FRAME);
return status;
}
#endif /* unused */
static int smsc_ircc_net_init(struct net_device *dev)
{
/* Keep track of module usage */
SET_MODULE_OWNER(dev);
/* Set up to be a normal IrDA network device driver */
irda_device_setup(dev);
/* Insert overrides below this line! */
return 0;
}
/*
* Function smsc_ircc_net_open (dev)
*
* Start the device
*
*/
static int smsc_ircc_net_open(struct net_device *dev)
{
struct smsc_ircc_cb *self;
int iobase;
char hwname[16];
unsigned long flags;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
ASSERT(dev != NULL, return -1;);
self = (struct smsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
iobase = self->io.fir_base;
if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
(void *) dev)) {
IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
__FUNCTION__, self->io.irq);
return -EAGAIN;
}
spin_lock_irqsave(&self->lock, flags);
/*smsc_ircc_sir_start(self);*/
self->io.speed = 0;
smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
spin_unlock_irqrestore(&self->lock, flags);
/* Give self a hardware name */
/* It would be cool to offer the chip revision here - Jean II */
sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base);
/*
* Open new IrLAP layer instance, now that everything should be
* initialized properly
*/
self->irlap = irlap_open(dev, &self->qos, hwname);
/*
* Always allocate the DMA channel after the IRQ,
* and clean up on failure.
*/
if (request_dma(self->io.dma, dev->name)) {
smsc_ircc_net_close(dev);
WARNING("%s(), unable to allocate DMA=%d\n",
__FUNCTION__, self->io.dma);
return -EAGAIN;
}
netif_start_queue(dev);
return 0;
}
/*
* Function smsc_ircc_net_close (dev)
*
* Stop the device
*
*/
static int smsc_ircc_net_close(struct net_device *dev)
{
struct smsc_ircc_cb *self;
int iobase;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
ASSERT(dev != NULL, return -1;);
self = (struct smsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
iobase = self->io.fir_base;
/* Stop device */
netif_stop_queue(dev);
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
self->irlap = NULL;
free_irq(self->io.irq, dev);
disable_dma(self->io.dma);
free_dma(self->io.dma);
return 0;
}
static void smsc_ircc_suspend(struct smsc_ircc_cb *self)
{
MESSAGE("%s, Suspending\n", driver_name);
if (self->io.suspended)
return;
smsc_ircc_net_close(self->netdev);
self->io.suspended = 1;
}
static void smsc_ircc_wakeup(struct smsc_ircc_cb *self)
{
if (!self->io.suspended)
return;
/* 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 */
smsc_ircc_net_open(self->netdev);
MESSAGE("%s, Waking up\n", driver_name);
}
static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
{
struct smsc_ircc_cb *self = (struct smsc_ircc_cb*) dev->data;
if (self) {
switch (rqst) {
case PM_SUSPEND:
smsc_ircc_suspend(self);
break;
case PM_RESUME:
smsc_ircc_wakeup(self);
break;
}
}
return 0;
}
/*
* Function smsc_ircc_close (self)
*
* Close driver instance
*
*/
static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
{
int iobase;
unsigned long flags;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
ASSERT(self != NULL, return -1;);
iobase = self->io.fir_base;
if (self->pmdev)
pm_unregister(self->pmdev);
/* Remove netdevice */
if (self->netdev) {
rtnl_lock();
unregister_netdevice(self->netdev);
rtnl_unlock();
}
/* Make sure the irq handler is not exectuting */
spin_lock_irqsave(&self->lock, flags);
/* Stop interrupts */
register_bank(iobase, 0);
outb(0, iobase+IRCC_IER);
outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
outb(0x00, iobase+IRCC_MASTER);
#if 0
/* Reset to SIR mode */
register_bank(iobase, 1);
outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
#endif
spin_unlock_irqrestore(&self->lock, flags);
/* Release the PORTS that this driver is using */
IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
self->io.sir_base);
release_region(self->io.sir_base, self->io.sir_ext);
if (self->tx_buff.head)
kfree(self->tx_buff.head);
if (self->rx_buff.head)
kfree(self->rx_buff.head);
kfree(self);
return 0;
}
void __exit smsc_ircc_cleanup(void)
{
int i;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
for (i=0; i < 2; i++) {
if (dev_self[i])
smsc_ircc_close(dev_self[i]);
}
}
/*
* Start SIR operations
*
* This function *must* be called with spinlock held, because it may
* be called from the irq handler (via smsc_ircc_change_speed()). - Jean II
*/
void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
{
struct net_device *dev;
int fir_base, sir_base;
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
ASSERT(self != NULL, return;);
dev= self->netdev;
ASSERT(dev != NULL, return;);
dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;
fir_base = self->io.fir_base;
sir_base = self->io.sir_base;
/* Reset everything */
outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);
#if SMSC_IRCC2_C_SIR_STOP
/*smsc_ircc_sir_stop(self);*/
#endif
register_bank(fir_base, 1);
outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base+IRCC_SCE_CFGA);
/* Initialize UART */
outb(UART_LCR_WLEN8, sir_base+UART_LCR); /* Reset DLAB */
outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base+UART_MCR);
/* Turn on interrups */
outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base+UART_IER);
IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__);
outb(0x00, fir_base+IRCC_MASTER);
}
#if SMSC_IRCC2_C_SIR_STOP
void smsc_ircc_sir_stop(struct smsc_ircc_cb *self)
{
int iobase;
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
iobase = self->io.sir_base;
/* Reset UART */
outb(0, iobase+UART_MCR);
/* Turn off interrupts */
outb(0, iobase+UART_IER);
}
#endif
/*
* Function smsc_sir_write_wakeup (self)
*
* Called by the SIR interrupt handler when there's room for more data.
* If we have more packets to send, we send them here.
*
*/
static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
{
int actual = 0;
int iobase;
int fcr;
ASSERT(self != NULL, return;);
IRDA_DEBUG(4, "%s\n", __FUNCTION__);
iobase = self->io.sir_base;
/* Finished with frame? */
if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
self->tx_buff.data, self->tx_buff.len);
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
} else {
/*if (self->tx_buff.len ==0) {*/
/*
* Now serial buffer is almost free & we can start
* transmission of another packet. But first we must check
* if we need to change the speed of the hardware
*/
if (self->new_speed) {
IRDA_DEBUG(5, "%s(), Changing speed to %d.\n",
__FUNCTION__, self->new_speed);
smsc_ircc_sir_wait_hw_transmitter_finish(self);
smsc_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
} else {
/* Tell network layer that we want more frames */
netif_wake_queue(self->netdev);
}
self->stats.tx_packets++;
if(self->io.speed <= 115200) {
/*
* Reset Rx FIFO to make sure that all reflected transmit data
* is discarded. This is needed for half duplex operation
*/
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
if (self->io.speed < 38400)
fcr |= UART_FCR_TRIGGER_1;
else
fcr |= UART_FCR_TRIGGER_14;
outb(fcr, iobase+UART_FCR);
/* Turn on receive interrupts */
outb(UART_IER_RDI, iobase+UART_IER);
}
}
}
/*
* Function smsc_ircc_sir_write (iobase, fifo_size, buf, len)
*
* Fill Tx FIFO with transmit data
*
*/
static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
{
int actual = 0;
/* Tx FIFO should be empty! */
if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);
return 0;
}
/* Fill FIFO with current frame */
while ((fifo_size-- > 0) && (actual < len)) {
/* Transmit next byte */
outb(buf[actual], iobase+UART_TX);
actual++;
}
return actual;
}
/*
* Function smsc_ircc_is_receiving (self)
*
* Returns true is we are currently receiving data
*
*/
static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self)
{
return (self->rx_buff.state != OUTSIDE_FRAME);
}
/*
* Function smsc_ircc_probe_transceiver(self)
*
* Tries to find the used Transceiver
*
*/
static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
{
unsigned int i;
ASSERT(self != NULL, return;);
for(i=0; smsc_transceivers[i].name!=NULL; i++)
if((*smsc_transceivers[i].probe)(self->io.fir_base)) {
MESSAGE(" %s transceiver found\n", smsc_transceivers[i].name);
self->transceiver= i+1;
return;
}
MESSAGE("No transceiver found. Defaulting to %s\n", smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
self->transceiver= SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
}
/*
* Function smsc_ircc_set_transceiver_for_speed(self, speed)
*
* Set the transceiver according to the speed
*
*/
static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed)
{
unsigned int trx;
trx = self->transceiver;
if(trx>0) (*smsc_transceivers[trx-1].set_for_speed)(self->io.fir_base, speed);
}
/*
* Function smsc_ircc_wait_hw_transmitter_finish ()
*
* Wait for the real end of HW transmission
*
* The UART is a strict FIFO, and we get called only when we have finished
* pushing data to the FIFO, so the maximum amount of time we must wait
* is only for the FIFO to drain out.
*
* We use a simple calibrated loop. We may need to adjust the loop
* delay (udelay) to balance I/O traffic and latency. And we also need to
* adjust the maximum timeout.
* It would probably be better to wait for the proper interrupt,
* but it doesn't seem to be available.
*
* We can't use jiffies or kernel timers because :
* 1) We are called from the interrupt handler, which disable softirqs,
* so jiffies won't be increased
* 2) Jiffies granularity is usually very coarse (10ms), and we don't
* want to wait that long to detect stuck hardware.
* Jean II
*/
static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
{
int iobase;
int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;
iobase = self->io.sir_base;
/* Calibrated busy loop */
while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
udelay(1);
if(count == 0)
IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
}
/* PROBING
*
*
*/
static int __init smsc_ircc_look_for_chips(void)
{
smsc_chip_address_t *address;
char *type;
unsigned int cfg_base, found;
found = 0;
address = possible_addresses;
while(address->cfg_base){
cfg_base = address->cfg_base;
/*printk(KERN_WARNING __FUNCTION__ "(): probing: 0x%02x for: 0x%02x\n", cfg_base, address->type);*/
if( address->type & SMSCSIO_TYPE_FDC){
type = "FDC";
if((address->type) & SMSCSIO_TYPE_FLAT) {
if(!smsc_superio_flat(fdc_chips_flat,cfg_base, type)) found++;
}
if((address->type) & SMSCSIO_TYPE_PAGED) {
if(!smsc_superio_paged(fdc_chips_paged,cfg_base, type)) found++;
}
}
if( address->type & SMSCSIO_TYPE_LPC){
type = "LPC";
if((address->type) & SMSCSIO_TYPE_FLAT) {
if(!smsc_superio_flat(lpc_chips_flat,cfg_base,type)) found++;
}
if((address->type) & SMSCSIO_TYPE_PAGED) {
if(!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC")) found++;
}
}
address++;
}
return found;
}
/*
* Function smsc_superio_flat (chip, base, type)
*
* Try to get configuration of a smc SuperIO chip with flat register model
*
*/
static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfgbase, char *type)
{
unsigned short firbase, sirbase;
u8 mode, dma, irq;
int ret = -ENODEV;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type)==NULL)
return ret;
outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase);
mode = inb(cfgbase+1);
/*printk(KERN_WARNING __FUNCTION__ "(): mode: 0x%02x\n", mode);*/
if(!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
WARNING("%s(): IrDA not enabled\n", __FUNCTION__);
outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
sirbase = inb(cfgbase+1) << 2;
/* FIR iobase */
outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase);
firbase = inb(cfgbase+1) << 3;
/* DMA */
outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase);
dma = inb(cfgbase+1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
/* IRQ */
outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
irq = inb(cfgbase+1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);
if (firbase) {
if (smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
ret=0;
}
/* Exit configuration */
outb(SMSCSIO_CFGEXITKEY, cfgbase);
return ret;
}
/*
* Function smsc_superio_paged (chip, base, type)
*
* Try to get configuration of a smc SuperIO chip with paged register model
*
*/
static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type)
{
unsigned short fir_io, sir_io;
int ret = -ENODEV;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
if (smsc_ircc_probe(cfg_base,0x20,chips,type)==NULL)
return ret;
/* Select logical device (UART2) */
outb(0x07, cfg_base);
outb(0x05, cfg_base + 1);
/* SIR iobase */
outb(0x60, cfg_base);
sir_io = inb(cfg_base + 1) << 8;
outb(0x61, cfg_base);
sir_io |= inb(cfg_base + 1);
/* Read FIR base */
outb(0x62, cfg_base);
fir_io = inb(cfg_base + 1) << 8;
outb(0x63, cfg_base);
fir_io |= inb(cfg_base + 1);
outb(0x2b, cfg_base); /* ??? */
if (fir_io) {
if (smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
ret=0;
}
/* Exit configuration */
outb(SMSCSIO_CFGEXITKEY, cfg_base);
return ret;
}
static int __init smsc_access(unsigned short cfg_base,unsigned char reg)
{
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
outb(reg, cfg_base);
if (inb(cfg_base)!=reg)
return -1;
return 0;
}
static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type)
{
u8 devid,xdevid,rev;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
/* Leave configuration */
outb(SMSCSIO_CFGEXITKEY, cfg_base);
if (inb(cfg_base) == SMSCSIO_CFGEXITKEY) /* not a smc superio chip */
return NULL;
outb(reg, cfg_base);
xdevid=inb(cfg_base+1);
/* Enter configuration */
outb(SMSCSIO_CFGACCESSKEY, cfg_base);
#if 0
if (smsc_access(cfg_base,0x55)) /* send second key and check */
return NULL;
#endif
/* probe device ID */
if (smsc_access(cfg_base,reg))
return NULL;
devid=inb(cfg_base+1);
if (devid==0) /* typical value for unused port */
return NULL;
if (devid==0xff) /* typical value for unused port */
return NULL;
/* probe revision ID */
if (smsc_access(cfg_base,reg+1))
return NULL;
rev=inb(cfg_base+1);
if (rev>=128) /* i think this will make no sense */
return NULL;
if (devid==xdevid) /* protection against false positives */
return NULL;
/* Check for expected device ID; are there others? */
while(chip->devid!=devid) {
chip++;
if (chip->name==NULL)
return NULL;
}
MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
if (chip->rev>rev){
MESSAGE("Revision higher than expected\n");
return NULL;
}
if (chip->flags&NoIRDA)
MESSAGE("chipset does not support IRDA\n");
return chip;
}
static int __init smsc_superio_fdc(unsigned short cfg_base)
{
if (check_region(cfg_base, 2) < 0) {
WARNING("%s: can't get cfg_base of 0x%03x\n",
__FUNCTION__, cfg_base);
return -1;
}
if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
return 0;
return -1;
}
static int __init smsc_superio_lpc(unsigned short cfg_base)
{
#if 0
if (check_region(cfg_base, 2) < 0) {
IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",
cfg_base);
return -1;
}
#endif
if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
return 0;
return -1;
}
/************************************************
*
* Transceivers specific functions
*
************************************************/
/*
* Function smsc_ircc_set_transceiver_smsc_ircc_atc(fir_base, speed)
*
* Program transceiver through smsc-ircc ATC circuitry
*
*/
static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed)
{
unsigned long jiffies_now, jiffies_timeout;
u8 val;
jiffies_now= jiffies;
jiffies_timeout= jiffies+SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
/* ATC */
register_bank(fir_base, 4);
outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC);
while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout));
if(val)
WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,
inb(fir_base+IRCC_ATC));
}
/*
* Function smsc_ircc_probe_transceiver_smsc_ircc_atc(fir_base)
*
* Probe transceiver smsc-ircc ATC circuitry
*
*/
static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base)
{
return 0;
}
/*
* Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed)
*
* Set transceiver
*
*/
static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed)
{
u8 fast_mode;
switch(speed)
{
default:
case 576000 :
fast_mode = 0;
break;
case 1152000 :
case 4000000 :
fast_mode = IRCC_LCR_A_FAST;
break;
}
register_bank(fir_base, 0);
outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
}
/*
* Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base)
*
* Probe transceiver
*
*/
static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base)
{
return 0;
}
/*
* Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed)
*
* Set transceiver
*
*/
static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed)
{
u8 fast_mode;
switch(speed)
{
default:
case 576000 :
fast_mode = 0;
break;
case 1152000 :
case 4000000 :
fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA;
break;
}
/* This causes an interrupt */
register_bank(fir_base, 0);
outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
}
/*
* Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base)
*
* Probe transceiver
*
*/
static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base)
{
return 0;
}
module_init(smsc_ircc_init);
module_exit(smsc_ircc_cleanup);
MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
MODULE_LICENSE("GPL");
MODULE_PARM(ircc_dma, "1i");
MODULE_PARM_DESC(ircc_dma, "DMA channel");
MODULE_PARM(ircc_irq, "1i");
MODULE_PARM_DESC(ircc_irq, "IRQ line");
MODULE_PARM(ircc_fir, "1-4i");
MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
MODULE_PARM(ircc_sir, "1-4i");
MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
MODULE_PARM(ircc_cfg, "1-4i");
MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
MODULE_PARM(ircc_transceiver, "1i");
MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
/*********************************************************************
* $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
*
* Description: Definitions for the SMC IrCC chipset
* Status: Experimental.
* Author: Daniele Peri (peri@csai.unipa.it)
*
* Copyright (c) 2002 Daniele Peri
* All Rights Reserved.
*
* Based on smc-ircc.h:
*
* Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
* Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net>
* 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.
*
* 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
*
********************************************************************/
#ifndef SMSC_IRCC2_H
#define SMSC_IRCC2_H
/* DMA modes needed */
#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
/* Master Control Register */
#define IRCC_MASTER 0x07
#define IRCC_MASTER_POWERDOWN 0x80
#define IRCC_MASTER_RESET 0x40
#define IRCC_MASTER_INT_EN 0x20
#define IRCC_MASTER_ERROR_RESET 0x10
/* Register block 0 */
/* Interrupt Identification */
#define IRCC_IIR 0x01
#define IRCC_IIR_ACTIVE_FRAME 0x80
#define IRCC_IIR_EOM 0x40
#define IRCC_IIR_RAW_MODE 0x20
#define IRCC_IIR_FIFO 0x10
/* Interrupt Enable */
#define IRCC_IER 0x02
#define IRCC_IER_ACTIVE_FRAME 0x80
#define IRCC_IER_EOM 0x40
#define IRCC_IER_RAW_MODE 0x20
#define IRCC_IER_FIFO 0x10
/* Line Status Register */
#define IRCC_LSR 0x03
#define IRCC_LSR_UNDERRUN 0x80
#define IRCC_LSR_OVERRUN 0x40
#define IRCC_LSR_FRAME_ERROR 0x20
#define IRCC_LSR_SIZE_ERROR 0x10
#define IRCC_LSR_CRC_ERROR 0x80
#define IRCC_LSR_FRAME_ABORT 0x40
/* Line Status Address Register */
#define IRCC_LSAR 0x03
#define IRCC_LSAR_ADDRESS_MASK 0x07
/* Line Control Register A */
#define IRCC_LCR_A 0x04
#define IRCC_LCR_A_FIFO_RESET 0x80
#define IRCC_LCR_A_FAST 0x40
#define IRCC_LCR_A_GP_DATA 0x20
#define IRCC_LCR_A_RAW_TX 0x10
#define IRCC_LCR_A_RAW_RX 0x08
#define IRCC_LCR_A_ABORT 0x04
#define IRCC_LCR_A_DATA_DONE 0x02
/* Line Control Register B */
#define IRCC_LCR_B 0x05
#define IRCC_LCR_B_SCE_DISABLED 0x00
#define IRCC_LCR_B_SCE_TRANSMIT 0x40
#define IRCC_LCR_B_SCE_RECEIVE 0x80
#define IRCC_LCR_B_SCE_UNDEFINED 0xc0
#define IRCC_LCR_B_SIP_ENABLE 0x20
#define IRCC_LCR_B_BRICK_WALL 0x10
/* Bus Status Register */
#define IRCC_BSR 0x06
#define IRCC_BSR_NOT_EMPTY 0x80
#define IRCC_BSR_FIFO_FULL 0x40
#define IRCC_BSR_TIMEOUT 0x20
/* Register block 1 */
#define IRCC_FIFO_THRESHOLD 0x02
#define IRCC_SCE_CFGA 0x00
#define IRCC_CFGA_AUX_IR 0x80
#define IRCC_CFGA_HALF_DUPLEX 0x04
#define IRCC_CFGA_TX_POLARITY 0x02
#define IRCC_CFGA_RX_POLARITY 0x01
#define IRCC_CFGA_COM 0x00
#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87
#define IRCC_CFGA_IRDA_SIR_A 0x08
#define IRCC_CFGA_ASK_SIR 0x10
#define IRCC_CFGA_IRDA_SIR_B 0x18
#define IRCC_CFGA_IRDA_HDLC 0x20
#define IRCC_CFGA_IRDA_4PPM 0x28
#define IRCC_CFGA_CONSUMER 0x30
#define IRCC_CFGA_RAW_IR 0x38
#define IRCC_CFGA_OTHER 0x40
#define IRCC_IR_HDLC 0x04
#define IRCC_IR_4PPM 0x01
#define IRCC_IR_CONSUMER 0x02
#define IRCC_SCE_CFGB 0x01
#define IRCC_CFGB_LOOPBACK 0x20
#define IRCC_CFGB_LPBCK_TX_CRC 0x10
#define IRCC_CFGB_NOWAIT 0x08
#define IRCC_CFGB_STRING_MOVE 0x04
#define IRCC_CFGB_DMA_BURST 0x02
#define IRCC_CFGB_DMA_ENABLE 0x01
#define IRCC_CFGB_MUX_COM 0x00
#define IRCC_CFGB_MUX_IR 0x40
#define IRCC_CFGB_MUX_AUX 0x80
#define IRCC_CFGB_MUX_INACTIVE 0xc0
/* Register block 3 - Identification Registers! */
#define IRCC_ID_HIGH 0x00 /* 0x10 */
#define IRCC_ID_LOW 0x01 /* 0xB8 */
#define IRCC_CHIP_ID 0x02 /* 0xF1 */
#define IRCC_VERSION 0x03 /* 0x01 */
#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
/* Register block 4 - IrDA */
#define IRCC_CONTROL 0x00
#define IRCC_BOF_COUNT_LO 0x01 /* Low byte */
#define IRCC_BOF_COUNT_HI 0x00 /* High nibble (bit 0-3) */
#define IRCC_BRICKWALL_CNT_LO 0x02 /* Low byte */
#define IRCC_BRICKWALL_CNT_HI 0x03 /* High nibble (bit 4-7) */
#define IRCC_TX_SIZE_LO 0x04 /* Low byte */
#define IRCC_TX_SIZE_HI 0x03 /* High nibble (bit 0-3) */
#define IRCC_RX_SIZE_HI 0x05 /* High nibble (bit 0-3) */
#define IRCC_RX_SIZE_LO 0x06 /* Low byte */
#define IRCC_1152 0x80
#define IRCC_CRC 0x40
/* Register block 5 - IrDA */
#define IRCC_ATC 0x00
#define IRCC_ATC_nPROGREADY 0x80
#define IRCC_ATC_SPEED 0x40
#define IRCC_ATC_ENABLE 0x20
#define IRCC_ATC_MASK 0xE0
#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01
#define IRCC_SCE_TX_DELAY_TIMER 0x02
/*
* Other definitions
*/
#define SMSC_IRCC2_MAX_SIR_SPEED 115200
#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
#define SMSC_IRCC2_FIFO_SIZE 16
#define SMSC_IRCC2_FIFO_THRESHOLD 64
/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
#define SMSC_IRCC2_RX_BUFF_TRUESIZE 14384
#define SMSC_IRCC2_TX_BUFF_TRUESIZE 14384
#define SMSC_IRCC2_MIN_TURN_TIME 0x07
#define SMSC_IRCC2_WINDOW_SIZE 0x07
/* Maximum wait for hw transmitter to finish */
#define SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US 1000 /* 1 ms */
/* Maximum wait for ATC transceiver programming to finish */
#define SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES 1
#endif /* SMSC_IRCC2_H */
#ifndef SMSC_SIO_H
#define SMSC_SIO_H
/******************************************
Keys. They should work with every SMsC SIO
******************************************/
#define SMSCSIO_CFGACCESSKEY 0x55
#define SMSCSIO_CFGEXITKEY 0xaa
/*****************************
* Generic SIO Flat (!?) *
*****************************/
/* Register 0x0d */
#define SMSCSIOFLAT_DEVICEID_REG 0x0d
/* Register 0x0c */
#define SMSCSIOFLAT_UARTMODE0C_REG 0x0c
#define SMSCSIOFLAT_UART2MODE_MASK 0x38
#define SMSCSIOFLAT_UART2MODE_VAL_COM 0x00
#define SMSCSIOFLAT_UART2MODE_VAL_IRDA 0x08
#define SMSCSIOFLAT_UART2MODE_VAL_ASKIR 0x10
/* Register 0x25 */
#define SMSCSIOFLAT_UART2BASEADDR_REG 0x25
/* Register 0x2b */
#define SMSCSIOFLAT_FIRBASEADDR_REG 0x2b
/* Register 0x2c */
#define SMSCSIOFLAT_FIRDMASELECT_REG 0x2c
#define SMSCSIOFLAT_FIRDMASELECT_MASK 0x0f
/* Register 0x28 */
#define SMSCSIOFLAT_UARTIRQSELECT_REG 0x28
#define SMSCSIOFLAT_UART2IRQSELECT_MASK 0x0f
#define SMSCSIOFLAT_UART1IRQSELECT_MASK 0xf0
#define SMSCSIOFLAT_UARTIRQSELECT_VAL_NONE 0x00
/*********************
* LPC47N227 *
*********************/
#define LPC47N227_CFGACCESSKEY 0x55
#define LPC47N227_CFGEXITKEY 0xaa
/* Register 0x00 */
#define LPC47N227_FDCPOWERVALIDCONF_REG 0x00
#define LPC47N227_FDCPOWER_MASK 0x08
#define LPC47N227_VALID_MASK 0x80
/* Register 0x02 */
#define LPC47N227_UART12POWER_REG 0x02
#define LPC47N227_UART1POWERDOWN_MASK 0x08
#define LPC47N227_UART2POWERDOWN_MASK 0x80
/* Register 0x07 */
#define LPC47N227_APMBOOTDRIVE_REG 0x07
#define LPC47N227_PARPORT2AUTOPWRDOWN_MASK 0x10 /* auto power down on if set */
#define LPC47N227_UART2AUTOPWRDOWN_MASK 0x20 /* auto power down on if set */
#define LPC47N227_UART1AUTOPWRDOWN_MASK 0x40 /* auto power down on if set */
/* Register 0x0c */
#define LPC47N227_UARTMODE0C_REG 0x0c
#define LPC47N227_UART2MODE_MASK 0x38
#define LPC47N227_UART2MODE_VAL_COM 0x00
#define LPC47N227_UART2MODE_VAL_IRDA 0x08
#define LPC47N227_UART2MODE_VAL_ASKIR 0x10
/* Register 0x0d */
#define LPC47N227_DEVICEID_REG 0x0d
#define LPC47N227_DEVICEID_DEFVAL 0x5a
/* Register 0x0e */
#define LPC47N227_REVISIONID_REG 0x0e
/* Register 0x25 */
#define LPC47N227_UART2BASEADDR_REG 0x25
/* Register 0x28 */
#define LPC47N227_UARTIRQSELECT_REG 0x28
#define LPC47N227_UART2IRQSELECT_MASK 0x0f
#define LPC47N227_UART1IRQSELECT_MASK 0xf0
#define LPC47N227_UARTIRQSELECT_VAL_NONE 0x00
/* Register 0x2b */
#define LPC47N227_FIRBASEADDR_REG 0x2b
/* Register 0x2c */
#define LPC47N227_FIRDMASELECT_REG 0x2c
#define LPC47N227_FIRDMASELECT_MASK 0x0f
#define LPC47N227_FIRDMASELECT_VAL_DMA1 0x01 /* 47n227 has three dma channels */
#define LPC47N227_FIRDMASELECT_VAL_DMA2 0x02
#define LPC47N227_FIRDMASELECT_VAL_DMA3 0x03
#define LPC47N227_FIRDMASELECT_VAL_NONE 0x0f
#endif
...@@ -524,6 +524,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -524,6 +524,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */ /* Check for empty frame */
if (!skb->len) { if (!skb->len) {
w83977af_change_speed(self, speed); w83977af_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
} else } else
...@@ -579,6 +580,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -579,6 +580,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
switch_bank(iobase, SET0); switch_bank(iobase, SET0);
outb(ICR_ETXTHI, iobase+ICR); outb(ICR_ETXTHI, iobase+ICR);
} }
dev->trans_start = jiffies;
dev_kfree_skb(skb); dev_kfree_skb(skb);
/* Restore set register */ /* Restore set register */
......
...@@ -66,7 +66,7 @@ struct iriap_cb { ...@@ -66,7 +66,7 @@ struct iriap_cb {
__u32 daddr; __u32 daddr;
__u8 operation; __u8 operation;
struct sk_buff *skb; struct sk_buff *request_skb;
struct lsap_cb *lsap; struct lsap_cb *lsap;
__u8 slsap_sel; __u8 slsap_sel;
......
...@@ -195,8 +195,6 @@ struct irlan_cb { ...@@ -195,8 +195,6 @@ struct irlan_cb {
struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr); struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr);
void irlan_close(struct irlan_cb *self); void irlan_close(struct irlan_cb *self);
void irlan_close_tsaps(struct irlan_cb *self); void irlan_close_tsaps(struct irlan_cb *self);
void irlan_mod_inc_use_count(void);
void irlan_mod_dec_use_count(void);
int irlan_register_netdev(struct irlan_cb *self); int irlan_register_netdev(struct irlan_cb *self);
void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel); void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel);
......
...@@ -79,26 +79,6 @@ typedef enum { ...@@ -79,26 +79,6 @@ typedef enum {
LM_LAP_IDLE_TIMEOUT, LM_LAP_IDLE_TIMEOUT,
} IRLMP_EVENT; } IRLMP_EVENT;
/*
* Information which is used by the current thread, when executing in the
* state machine.
*/
struct irlmp_event {
IRLMP_EVENT *event;
struct sk_buff *skb;
__u8 hint;
__u32 daddr;
__u32 saddr;
__u8 slsap;
__u8 dlsap;
int reason;
struct discovery_t *discovery;
};
extern const char *irlmp_state[]; extern const char *irlmp_state[];
extern const char *irlsap_state[]; extern const char *irlsap_state[];
......
...@@ -67,6 +67,7 @@ struct irport_cb { ...@@ -67,6 +67,7 @@ struct irport_cb {
__u32 new_speed; __u32 new_speed;
int mode; int mode;
int index; /* Instance index */ int index; /* Instance index */
int transmitting; /* Are we transmitting ? */
spinlock_t lock; /* For serializing operations */ spinlock_t lock; /* For serializing operations */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
* *
* Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no> * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
* Copyright (c) 1999-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com>
* All Rights Reserved. * All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -190,6 +190,9 @@ static void irda_connect_confirm(void *instance, void *sap, ...@@ -190,6 +190,9 @@ static void irda_connect_confirm(void *instance, void *sap,
if (sk == NULL) if (sk == NULL)
return; return;
dev_kfree_skb(skb);
// Should be ??? skb_queue_tail(&sk->receive_queue, skb);
/* How much header space do we need to reserve */ /* How much header space do we need to reserve */
self->max_header_size = max_header_size; self->max_header_size = max_header_size;
...@@ -220,8 +223,6 @@ static void irda_connect_confirm(void *instance, void *sap, ...@@ -220,8 +223,6 @@ static void irda_connect_confirm(void *instance, void *sap,
self->max_data_size); self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
dev_kfree_skb(skb);
// Should be ??? skb_queue_tail(&sk->receive_queue, skb);
/* We are now connected! */ /* We are now connected! */
sk->state = TCP_ESTABLISHED; sk->state = TCP_ESTABLISHED;
...@@ -260,6 +261,7 @@ static void irda_connect_indication(void *instance, void *sap, ...@@ -260,6 +261,7 @@ static void irda_connect_indication(void *instance, void *sap,
case SOCK_STREAM: case SOCK_STREAM:
if (max_sdu_size != 0) { if (max_sdu_size != 0) {
ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__); ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__);
kfree_skb(skb);
return; return;
} }
self->max_data_size = irttp_get_max_seg_size(self->tsap); self->max_data_size = irttp_get_max_seg_size(self->tsap);
...@@ -267,6 +269,7 @@ static void irda_connect_indication(void *instance, void *sap, ...@@ -267,6 +269,7 @@ static void irda_connect_indication(void *instance, void *sap,
case SOCK_SEQPACKET: case SOCK_SEQPACKET:
if (max_sdu_size == 0) { if (max_sdu_size == 0) {
ERROR("%s: max_sdu_size cannot be 0\n", __FUNCTION__); ERROR("%s: max_sdu_size cannot be 0\n", __FUNCTION__);
kfree_skb(skb);
return; return;
} }
self->max_data_size = max_sdu_size; self->max_data_size = max_sdu_size;
...@@ -359,7 +362,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) ...@@ -359,7 +362,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
* doesn't touch the dtsap_sel and save the full value structure... * doesn't touch the dtsap_sel and save the full value structure...
*/ */
static void irda_getvalue_confirm(int result, __u16 obj_id, static void irda_getvalue_confirm(int result, __u16 obj_id,
struct ias_value *value, void *priv) struct ias_value *value, void *priv)
{ {
struct irda_sock *self; struct irda_sock *self;
...@@ -908,6 +911,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -908,6 +911,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
new->tsap = irttp_dup(self->tsap, new); new->tsap = irttp_dup(self->tsap, new);
if (!new->tsap) { if (!new->tsap) {
IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
kfree_skb(skb);
return -1; return -1;
} }
...@@ -926,6 +930,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -926,6 +930,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
/* Clean up the original one to keep it in listen state */ /* Clean up the original one to keep it in listen state */
irttp_listen(self->tsap); irttp_listen(self->tsap);
/* Wow ! What is that ? Jean II */
skb->sk = NULL; skb->sk = NULL;
skb->destructor = NULL; skb->destructor = NULL;
kfree_skb(skb); kfree_skb(skb);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no> * Modified by: Dag Brattli <dagb@cs.uit.no>
* *
* Copyright (c) 1999 Dag Brattli, All Rights Reserved. * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
* Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -251,7 +252,6 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, ...@@ -251,7 +252,6 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
info->max_header_size, skb); info->max_header_size, skb);
else { else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
dev_kfree_skb(skb);
} }
} }
...@@ -295,7 +295,6 @@ void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, ...@@ -295,7 +295,6 @@ void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
info->max_header_size, skb); info->max_header_size, skb);
else { else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
dev_kfree_skb(skb);
} }
} }
...@@ -338,7 +337,6 @@ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb) ...@@ -338,7 +337,6 @@ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
self->notify.data_indication(self->notify.instance, self, skb); self->notify.data_indication(self->notify.instance, self, skb);
else { else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
dev_kfree_skb(skb);
} }
} }
...@@ -370,9 +368,8 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb) ...@@ -370,9 +368,8 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
if (skb->len) if (skb->len)
ircomm_data_indication(self, skb); ircomm_data_indication(self, skb);
else { else {
IRDA_DEBUG(4, IRDA_DEBUG(4, "%s(), data was control info only!\n",
"%s(), data was control info only!\n", __FUNCTION__ ); __FUNCTION__ );
dev_kfree_skb(skb);
} }
} }
...@@ -408,24 +405,28 @@ EXPORT_SYMBOL(ircomm_control_request); ...@@ -408,24 +405,28 @@ EXPORT_SYMBOL(ircomm_control_request);
static void ircomm_control_indication(struct ircomm_cb *self, static void ircomm_control_indication(struct ircomm_cb *self,
struct sk_buff *skb, int clen) struct sk_buff *skb, int clen)
{ {
struct sk_buff *ctrl_skb;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
ctrl_skb = skb_clone(skb, GFP_ATOMIC); /* Use udata for delivering data on the control channel */
if (!ctrl_skb) if (self->notify.udata_indication) {
return; struct sk_buff *ctrl_skb;
/* We don't own the skb, so clone it */
ctrl_skb = skb_clone(skb, GFP_ATOMIC);
if (!ctrl_skb)
return;
/* Remove data channel from control channel */ /* Remove data channel from control channel */
skb_trim(ctrl_skb, clen+1); skb_trim(ctrl_skb, clen+1);
/* Use udata for delivering data on the control channel */
if (self->notify.udata_indication)
self->notify.udata_indication(self->notify.instance, self, self->notify.udata_indication(self->notify.instance, self,
ctrl_skb); ctrl_skb);
else {
/* Drop reference count -
* see ircomm_tty_control_indication(). */
dev_kfree_skb(ctrl_skb);
} else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
dev_kfree_skb(skb);
} }
} }
...@@ -470,7 +471,6 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, ...@@ -470,7 +471,6 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
info->reason, skb); info->reason, skb);
} else { } else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
dev_kfree_skb(skb);
} }
} }
......
...@@ -109,9 +109,7 @@ static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, ...@@ -109,9 +109,7 @@ static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
default: default:
IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_event[event]); ircomm_event[event]);
if (skb) ret = -EINVAL;
dev_kfree_skb(skb);
return -EINVAL;
} }
return ret; return ret;
} }
...@@ -141,8 +139,6 @@ static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, ...@@ -141,8 +139,6 @@ static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_event[event]); ircomm_event[event]);
if (skb)
dev_kfree_skb(skb);
ret = -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
...@@ -176,8 +172,6 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, ...@@ -176,8 +172,6 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ , IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
ircomm_event[event]); ircomm_event[event]);
if (skb)
dev_kfree_skb(skb);
ret = -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
...@@ -220,8 +214,6 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, ...@@ -220,8 +214,6 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ , IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
ircomm_event[event]); ircomm_event[event]);
if (skb)
dev_kfree_skb(skb);
ret = -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* Sources: Previous IrLPT work by Thomas Davis * Sources: Previous IrLPT work by Thomas Davis
* *
* Copyright (c) 1999 Dag Brattli, All Rights Reserved. * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
* Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -93,6 +94,10 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self, ...@@ -93,6 +94,10 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self,
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
skb_get(userdata);
ret = irlmp_connect_request(self->lsap, info->dlsap_sel, ret = irlmp_connect_request(self->lsap, info->dlsap_sel,
info->saddr, info->daddr, NULL, userdata); info->saddr, info->daddr, NULL, userdata);
return ret; return ret;
...@@ -106,29 +111,32 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self, ...@@ -106,29 +111,32 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self,
*/ */
int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
int ret; int ret;
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
/* Any userdata supplied? */ /* Any userdata supplied? */
if (userdata == NULL) { if (userdata == NULL) {
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return -ENOMEM; return -ENOMEM;
/* Reserve space for MUX and LAP header */ /* Reserve space for MUX and LAP header */
skb_reserve(skb, LMP_MAX_HEADER); skb_reserve(tx_skb, LMP_MAX_HEADER);
} else { } else {
skb = userdata;
/* /*
* Check that the client has reserved enough space for * Check that the client has reserved enough space for
* headers * headers
*/ */
ASSERT(skb_headroom(skb) >= LMP_MAX_HEADER, return -1;); ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER, return -1;);
/* Don't forget to refcount it - should be NULL anyway */
skb_get(userdata);
tx_skb = userdata;
} }
ret = irlmp_connect_response(self->lsap, skb); ret = irlmp_connect_response(self->lsap, tx_skb);
return 0; return 0;
} }
...@@ -137,20 +145,24 @@ int ircomm_lmp_disconnect_request(struct ircomm_cb *self, ...@@ -137,20 +145,24 @@ int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
struct sk_buff *userdata, struct sk_buff *userdata,
struct ircomm_info *info) struct ircomm_info *info)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
int ret; int ret;
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
if (!userdata) { if (!userdata) {
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return -ENOMEM; return -ENOMEM;
/* Reserve space for MUX and LAP header */ /* Reserve space for MUX and LAP header */
skb_reserve(skb, LMP_MAX_HEADER); skb_reserve(tx_skb, LMP_MAX_HEADER);
userdata = skb; userdata = tx_skb;
} else {
/* Don't forget to refcount it - should be NULL anyway */
skb_get(userdata);
} }
ret = irlmp_disconnect_request(self->lsap, userdata); ret = irlmp_disconnect_request(self->lsap, userdata);
return ret; return ret;
...@@ -217,8 +229,11 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb, ...@@ -217,8 +229,11 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ ); IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ );
/* Don't forget to refcount it - see ircomm_tty_do_softint() */
skb_get(skb);
skb->destructor = ircomm_lmp_flow_control; skb->destructor = ircomm_lmp_flow_control;
if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) { if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ ); IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ );
self->flow_status = FLOW_STOP; self->flow_status = FLOW_STOP;
...@@ -229,7 +244,7 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb, ...@@ -229,7 +244,7 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
ret = irlmp_data_request(self->lsap, skb); ret = irlmp_data_request(self->lsap, skb);
if (ret) { if (ret) {
ERROR("%s(), failed\n", __FUNCTION__); ERROR("%s(), failed\n", __FUNCTION__);
dev_kfree_skb(skb); /* irlmp_data_request already free the packet */
} }
return ret; return ret;
...@@ -254,6 +269,9 @@ int ircomm_lmp_data_indication(void *instance, void *sap, ...@@ -254,6 +269,9 @@ int ircomm_lmp_data_indication(void *instance, void *sap,
ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL); ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
/* Drop reference count - see ircomm_tty_data_indication(). */
dev_kfree_skb(skb);
return 0; return 0;
} }
...@@ -285,6 +303,9 @@ void ircomm_lmp_connect_confirm(void *instance, void *sap, ...@@ -285,6 +303,9 @@ void ircomm_lmp_connect_confirm(void *instance, void *sap,
info.qos = qos; info.qos = qos;
ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info); ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info);
/* Drop reference count - see ircomm_tty_connect_confirm(). */
dev_kfree_skb(skb);
} }
/* /*
...@@ -315,6 +336,9 @@ void ircomm_lmp_connect_indication(void *instance, void *sap, ...@@ -315,6 +336,9 @@ void ircomm_lmp_connect_indication(void *instance, void *sap,
info.qos = qos; info.qos = qos;
ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info); ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info);
/* Drop reference count - see ircomm_tty_connect_indication(). */
dev_kfree_skb(skb);
} }
/* /*
...@@ -338,4 +362,8 @@ void ircomm_lmp_disconnect_indication(void *instance, void *sap, ...@@ -338,4 +362,8 @@ void ircomm_lmp_disconnect_indication(void *instance, void *sap,
info.reason = reason; info.reason = reason;
ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info); ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
/* Drop reference count - see ircomm_tty_disconnect_indication(). */
if(skb)
dev_kfree_skb(skb);
} }
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no> * Modified by: Dag Brattli <dagb@cs.uit.no>
* *
* Copyright (c) 1999 Dag Brattli, All Rights Reserved. * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
* Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -94,9 +95,14 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self, ...@@ -94,9 +95,14 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self,
IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
skb_get(userdata);
ret = irttp_connect_request(self->tsap, info->dlsap_sel, ret = irttp_connect_request(self->tsap, info->dlsap_sel,
info->saddr, info->daddr, NULL, info->saddr, info->daddr, NULL,
TTP_SAR_DISABLE, userdata); TTP_SAR_DISABLE, userdata);
return ret; return ret;
} }
...@@ -106,13 +112,18 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self, ...@@ -106,13 +112,18 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self,
* *
* *
*/ */
int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb) int ircomm_ttp_connect_response(struct ircomm_cb *self,
struct sk_buff *userdata)
{ {
int ret; int ret;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, skb); /* Don't forget to refcount it - should be NULL anyway */
if(userdata)
skb_get(userdata);
ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
return ret; return ret;
} }
...@@ -126,7 +137,8 @@ int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb) ...@@ -126,7 +137,8 @@ int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb)
* some of them are sent after connection establishment, so this can * some of them are sent after connection establishment, so this can
* increase the latency a bit. * increase the latency a bit.
*/ */
int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, int ircomm_ttp_data_request(struct ircomm_cb *self,
struct sk_buff *skb,
int clen) int clen)
{ {
int ret; int ret;
...@@ -140,6 +152,10 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, ...@@ -140,6 +152,10 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
* only frames, to make things easier and avoid queueing * only frames, to make things easier and avoid queueing
*/ */
ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;); ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
/* Don't forget to refcount it - see ircomm_tty_do_softint() */
skb_get(skb);
skb_push(skb, IRCOMM_HEADER_SIZE); skb_push(skb, IRCOMM_HEADER_SIZE);
skb->data[0] = clen; skb->data[0] = clen;
...@@ -147,7 +163,7 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb, ...@@ -147,7 +163,7 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
ret = irttp_data_request(self->tsap, skb); ret = irttp_data_request(self->tsap, skb);
if (ret) { if (ret) {
ERROR("%s(), failed\n", __FUNCTION__); ERROR("%s(), failed\n", __FUNCTION__);
dev_kfree_skb(skb); /* irttp_data_request already free the packet */
} }
return ret; return ret;
...@@ -172,6 +188,9 @@ int ircomm_ttp_data_indication(void *instance, void *sap, ...@@ -172,6 +188,9 @@ int ircomm_ttp_data_indication(void *instance, void *sap,
ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL); ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
/* Drop reference count - see ircomm_tty_data_indication(). */
dev_kfree_skb(skb);
return 0; return 0;
} }
...@@ -189,12 +208,11 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap, ...@@ -189,12 +208,11 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap,
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_MAGIC, return;); ASSERT(self->magic == IRCOMM_MAGIC, return;);
ASSERT(skb != NULL, return;); ASSERT(skb != NULL, return;);
ASSERT(qos != NULL, return;); ASSERT(qos != NULL, goto out;);
if (max_sdu_size != TTP_SAR_DISABLE) { if (max_sdu_size != TTP_SAR_DISABLE) {
ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__); ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
dev_kfree_skb(skb); goto out;
return;
} }
info.max_data_size = irttp_get_max_seg_size(self->tsap) info.max_data_size = irttp_get_max_seg_size(self->tsap)
...@@ -203,6 +221,10 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap, ...@@ -203,6 +221,10 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap,
info.qos = qos; info.qos = qos;
ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info); ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
out:
/* Drop reference count - see ircomm_tty_connect_confirm(). */
dev_kfree_skb(skb);
} }
/* /*
...@@ -226,12 +248,11 @@ void ircomm_ttp_connect_indication(void *instance, void *sap, ...@@ -226,12 +248,11 @@ void ircomm_ttp_connect_indication(void *instance, void *sap,
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_MAGIC, return;); ASSERT(self->magic == IRCOMM_MAGIC, return;);
ASSERT(skb != NULL, return;); ASSERT(skb != NULL, return;);
ASSERT(qos != NULL, return;); ASSERT(qos != NULL, goto out;);
if (max_sdu_size != TTP_SAR_DISABLE) { if (max_sdu_size != TTP_SAR_DISABLE) {
ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__); ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
dev_kfree_skb(skb); goto out;
return;
} }
info.max_data_size = irttp_get_max_seg_size(self->tsap) info.max_data_size = irttp_get_max_seg_size(self->tsap)
...@@ -240,6 +261,10 @@ void ircomm_ttp_connect_indication(void *instance, void *sap, ...@@ -240,6 +261,10 @@ void ircomm_ttp_connect_indication(void *instance, void *sap,
info.qos = qos; info.qos = qos;
ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info); ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
out:
/* Drop reference count - see ircomm_tty_connect_indication(). */
dev_kfree_skb(skb);
} }
/* /*
...@@ -254,6 +279,10 @@ int ircomm_ttp_disconnect_request(struct ircomm_cb *self, ...@@ -254,6 +279,10 @@ int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
{ {
int ret; int ret;
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
skb_get(userdata);
ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL); ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
return ret; return ret;
...@@ -280,6 +309,10 @@ void ircomm_ttp_disconnect_indication(void *instance, void *sap, ...@@ -280,6 +309,10 @@ void ircomm_ttp_disconnect_indication(void *instance, void *sap,
info.reason = reason; info.reason = reason;
ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info); ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
/* Drop reference count - see ircomm_tty_disconnect_indication(). */
if(skb)
dev_kfree_skb(skb);
} }
/* /*
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* Sources: serial.c and previous IrCOMM work by Takahide Higuchi * Sources: serial.c and previous IrCOMM work by Takahide Higuchi
* *
* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
* Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -663,8 +664,12 @@ static void ircomm_tty_do_softint(void *private_) ...@@ -663,8 +664,12 @@ static void ircomm_tty_do_softint(void *private_)
spin_unlock_irqrestore(&self->spinlock, flags); spin_unlock_irqrestore(&self->spinlock, flags);
/* Flush control buffer if any */ /* Flush control buffer if any */
if (ctrl_skb && self->flow == FLOW_START) if(ctrl_skb) {
ircomm_control_request(self->ircomm, ctrl_skb); if(self->flow == FLOW_START)
ircomm_control_request(self->ircomm, ctrl_skb);
/* Drop reference count - see ircomm_ttp_data_request(). */
dev_kfree_skb(ctrl_skb);
}
if (tty->hw_stopped) if (tty->hw_stopped)
return; return;
...@@ -678,8 +683,11 @@ static void ircomm_tty_do_softint(void *private_) ...@@ -678,8 +683,11 @@ static void ircomm_tty_do_softint(void *private_)
spin_unlock_irqrestore(&self->spinlock, flags); spin_unlock_irqrestore(&self->spinlock, flags);
/* Flush transmit buffer if any */ /* Flush transmit buffer if any */
if (skb) if (skb) {
ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL); ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
/* Drop reference count - see ircomm_ttp_data_request(). */
dev_kfree_skb(skb);
}
/* Check if user (still) wants to be waken up */ /* Check if user (still) wants to be waken up */
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
...@@ -1179,7 +1187,6 @@ static int ircomm_tty_data_indication(void *instance, void *sap, ...@@ -1179,7 +1187,6 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
if (!self->tty) { if (!self->tty) {
IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ ); IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ );
dev_kfree_skb(skb);
return 0; return 0;
} }
...@@ -1204,7 +1211,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap, ...@@ -1204,7 +1211,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
* handler * handler
*/ */
self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len); self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len);
dev_kfree_skb(skb);
/* No need to kfree_skb - see ircomm_ttp_data_indication() */
return 0; return 0;
} }
...@@ -1231,7 +1239,8 @@ static int ircomm_tty_control_indication(void *instance, void *sap, ...@@ -1231,7 +1239,8 @@ static int ircomm_tty_control_indication(void *instance, void *sap,
irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen), irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen),
&ircomm_param_info); &ircomm_param_info);
dev_kfree_skb(skb);
/* No need to kfree_skb - see ircomm_control_indication() */
return 0; return 0;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no> * Modified by: Dag Brattli <dagb@cs.uit.no>
* *
* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
* Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -236,8 +237,9 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self) ...@@ -236,8 +237,9 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
irias_insert_object(self->obj); irias_insert_object(self->obj);
} }
self->skey = irlmp_register_service(hints); self->skey = irlmp_register_service(hints);
self->ckey = irlmp_register_client( self->ckey = irlmp_register_client(hints,
hints, ircomm_tty_discovery_indication, NULL, (void *) self); ircomm_tty_discovery_indication,
NULL, (void *) self);
} }
/* /*
...@@ -459,7 +461,7 @@ void ircomm_tty_connect_confirm(void *instance, void *sap, ...@@ -459,7 +461,7 @@ void ircomm_tty_connect_confirm(void *instance, void *sap,
ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL); ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
dev_kfree_skb(skb); /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */
} }
/* /*
...@@ -496,7 +498,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap, ...@@ -496,7 +498,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL); ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
dev_kfree_skb(skb); /* No need to kfree_skb - see ircomm_ttp_connect_indication() */
} }
/* /*
...@@ -647,7 +649,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, ...@@ -647,7 +649,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
default: default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]); ircomm_tty_event[event]);
return -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
...@@ -718,7 +720,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self, ...@@ -718,7 +720,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
default: default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]); ircomm_tty_event[event]);
return -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
...@@ -774,7 +776,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, ...@@ -774,7 +776,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
default: default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]); ircomm_tty_event[event]);
return -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
...@@ -822,7 +824,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, ...@@ -822,7 +824,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
default: default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]); ircomm_tty_event[event]);
return -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
...@@ -874,7 +876,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, ...@@ -874,7 +876,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
default: default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]); ircomm_tty_event[event]);
return -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
...@@ -917,7 +919,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, ...@@ -917,7 +919,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
default: default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]); ircomm_tty_event[event]);
return -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -210,8 +210,8 @@ static void __iriap_close(struct iriap_cb *self) ...@@ -210,8 +210,8 @@ static void __iriap_close(struct iriap_cb *self)
del_timer(&self->watchdog_timer); del_timer(&self->watchdog_timer);
if (self->skb) if (self->request_skb)
dev_kfree_skb(self->skb); dev_kfree_skb(self->request_skb);
self->magic = 0; self->magic = 0;
...@@ -278,7 +278,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) ...@@ -278,7 +278,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
*/ */
static void iriap_disconnect_indication(void *instance, void *sap, static void iriap_disconnect_indication(void *instance, void *sap,
LM_REASON reason, LM_REASON reason,
struct sk_buff *userdata) struct sk_buff *skb)
{ {
struct iriap_cb *self; struct iriap_cb *self;
...@@ -293,6 +293,10 @@ static void iriap_disconnect_indication(void *instance, void *sap, ...@@ -293,6 +293,10 @@ static void iriap_disconnect_indication(void *instance, void *sap,
del_timer(&self->watchdog_timer); del_timer(&self->watchdog_timer);
/* Not needed */
if (skb)
dev_kfree_skb(skb);
if (self->mode == IAS_CLIENT) { if (self->mode == IAS_CLIENT) {
IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__); IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__);
...@@ -312,9 +316,6 @@ static void iriap_disconnect_indication(void *instance, void *sap, ...@@ -312,9 +316,6 @@ static void iriap_disconnect_indication(void *instance, void *sap,
NULL); NULL);
iriap_close(self); iriap_close(self);
} }
if (userdata)
dev_kfree_skb(userdata);
} }
/* /*
...@@ -322,15 +323,15 @@ static void iriap_disconnect_indication(void *instance, void *sap, ...@@ -322,15 +323,15 @@ static void iriap_disconnect_indication(void *instance, void *sap,
*/ */
void iriap_disconnect_request(struct iriap_cb *self) void iriap_disconnect_request(struct iriap_cb *self)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;); ASSERT(self->magic == IAS_MAGIC, return;);
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (skb == NULL) { if (tx_skb == NULL) {
IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n", IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n",
__FUNCTION__, 64); __FUNCTION__, 64);
return; return;
...@@ -339,9 +340,9 @@ void iriap_disconnect_request(struct iriap_cb *self) ...@@ -339,9 +340,9 @@ void iriap_disconnect_request(struct iriap_cb *self)
/* /*
* Reserve space for MUX control and LAP header * Reserve space for MUX control and LAP header
*/ */
skb_reserve(skb, LMP_MAX_HEADER); skb_reserve(tx_skb, LMP_MAX_HEADER);
irlmp_disconnect_request(self->lsap, skb); irlmp_disconnect_request(self->lsap, tx_skb);
} }
void iriap_getinfobasedetails_request(void) void iriap_getinfobasedetails_request(void)
...@@ -379,7 +380,7 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self, ...@@ -379,7 +380,7 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self,
__u32 saddr, __u32 daddr, __u32 saddr, __u32 daddr,
char *name, char *attr) char *name, char *attr)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
int name_len, attr_len, skb_len; int name_len, attr_len, skb_len;
__u8 *frame; __u8 *frame;
...@@ -405,14 +406,14 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self, ...@@ -405,14 +406,14 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self,
attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */ attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */
skb_len = self->max_header_size+2+name_len+1+attr_len+4; skb_len = self->max_header_size+2+name_len+1+attr_len+4;
skb = dev_alloc_skb(skb_len); tx_skb = dev_alloc_skb(skb_len);
if (!skb) if (!tx_skb)
return -ENOMEM; return -ENOMEM;
/* Reserve space for MUX and LAP header */ /* Reserve space for MUX and LAP header */
skb_reserve(skb, self->max_header_size); skb_reserve(tx_skb, self->max_header_size);
skb_put(skb, 3+name_len+attr_len); skb_put(tx_skb, 3+name_len+attr_len);
frame = skb->data; frame = tx_skb->data;
/* Build frame */ /* Build frame */
frame[0] = IAP_LST | GET_VALUE_BY_CLASS; frame[0] = IAP_LST | GET_VALUE_BY_CLASS;
...@@ -421,7 +422,10 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self, ...@@ -421,7 +422,10 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self,
frame[2+name_len] = attr_len; /* Insert length of attr */ frame[2+name_len] = attr_len; /* Insert length of attr */
memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */ memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */
iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, skb); iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb);
/* Drop reference count - see state_s_disconnect(). */
dev_kfree_skb(tx_skb);
return 0; return 0;
} }
...@@ -495,7 +499,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) ...@@ -495,7 +499,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
/* Aborting, close connection! */ /* Aborting, close connection! */
iriap_disconnect_request(self); iriap_disconnect_request(self);
dev_kfree_skb(skb);
return; return;
/* break; */ /* break; */
} }
...@@ -533,7 +536,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) ...@@ -533,7 +536,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__);
irias_delete_value(value); irias_delete_value(value);
} }
dev_kfree_skb(skb);
} }
/* /*
...@@ -545,7 +547,7 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) ...@@ -545,7 +547,7 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
__u8 ret_code, struct ias_value *value) __u8 ret_code, struct ias_value *value)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
int n; int n;
__u32 tmp_be32, tmp_be16; __u32 tmp_be32, tmp_be16;
__u8 *fp; __u8 *fp;
...@@ -565,15 +567,15 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, ...@@ -565,15 +567,15 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
* value. We add 32 bytes because of the 6 bytes for the frame and * value. We add 32 bytes because of the 6 bytes for the frame and
* max 5 bytes for the value coding. * max 5 bytes for the value coding.
*/ */
skb = dev_alloc_skb(value->len + self->max_header_size + 32); tx_skb = dev_alloc_skb(value->len + self->max_header_size + 32);
if (!skb) if (!tx_skb)
return; return;
/* Reserve space for MUX and LAP header */ /* Reserve space for MUX and LAP header */
skb_reserve(skb, self->max_header_size); skb_reserve(tx_skb, self->max_header_size);
skb_put(skb, 6); skb_put(tx_skb, 6);
fp = skb->data; fp = tx_skb->data;
/* Build frame */ /* Build frame */
fp[n++] = GET_VALUE_BY_CLASS | IAP_LST; fp[n++] = GET_VALUE_BY_CLASS | IAP_LST;
...@@ -589,21 +591,21 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, ...@@ -589,21 +591,21 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
switch (value->type) { switch (value->type) {
case IAS_STRING: case IAS_STRING:
skb_put(skb, 3 + value->len); skb_put(tx_skb, 3 + value->len);
fp[n++] = value->type; fp[n++] = value->type;
fp[n++] = 0; /* ASCII */ fp[n++] = 0; /* ASCII */
fp[n++] = (__u8) value->len; fp[n++] = (__u8) value->len;
memcpy(fp+n, value->t.string, value->len); n+=value->len; memcpy(fp+n, value->t.string, value->len); n+=value->len;
break; break;
case IAS_INTEGER: case IAS_INTEGER:
skb_put(skb, 5); skb_put(tx_skb, 5);
fp[n++] = value->type; fp[n++] = value->type;
tmp_be32 = cpu_to_be32(value->t.integer); tmp_be32 = cpu_to_be32(value->t.integer);
memcpy(fp+n, &tmp_be32, 4); n += 4; memcpy(fp+n, &tmp_be32, 4); n += 4;
break; break;
case IAS_OCT_SEQ: case IAS_OCT_SEQ:
skb_put(skb, 3 + value->len); skb_put(tx_skb, 3 + value->len);
fp[n++] = value->type; fp[n++] = value->type;
tmp_be16 = cpu_to_be16(value->len); tmp_be16 = cpu_to_be16(value->len);
...@@ -612,14 +614,17 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, ...@@ -612,14 +614,17 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
break; break;
case IAS_MISSING: case IAS_MISSING:
IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__); IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__);
skb_put(skb, 1); skb_put(tx_skb, 1);
fp[n++] = value->type; fp[n++] = value->type;
break; break;
default: default:
IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__);
break; break;
} }
iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb); iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb);
/* Drop reference count - see state_r_execute(). */
dev_kfree_skb(tx_skb);
} }
/* /*
...@@ -657,9 +662,6 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self, ...@@ -657,9 +662,6 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
memcpy(attr, fp+n, attr_len); n+=attr_len; memcpy(attr, fp+n, attr_len); n+=attr_len;
attr[attr_len] = '\0'; attr[attr_len] = '\0';
/* We do not need the buffer anymore */
dev_kfree_skb(skb);
IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr); IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
obj = irias_find_object(name); obj = irias_find_object(name);
...@@ -694,7 +696,7 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self, ...@@ -694,7 +696,7 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
*/ */
void iriap_send_ack(struct iriap_cb *self) void iriap_send_ack(struct iriap_cb *self)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
__u8 *frame; __u8 *frame;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__); IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
...@@ -702,19 +704,19 @@ void iriap_send_ack(struct iriap_cb *self) ...@@ -702,19 +704,19 @@ void iriap_send_ack(struct iriap_cb *self)
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;); ASSERT(self->magic == IAS_MAGIC, return;);
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return; return;
/* Reserve space for MUX and LAP header */ /* Reserve space for MUX and LAP header */
skb_reserve(skb, self->max_header_size); skb_reserve(tx_skb, self->max_header_size);
skb_put(skb, 1); skb_put(tx_skb, 1);
frame = skb->data; frame = tx_skb->data;
/* Build frame */ /* Build frame */
frame[0] = IAP_LST | IAP_ACK | self->operation; frame[0] = IAP_LST | IAP_ACK | self->operation;
irlmp_data_request(self->lsap, skb); irlmp_data_request(self->lsap, tx_skb);
} }
void iriap_connect_request(struct iriap_cb *self) void iriap_connect_request(struct iriap_cb *self)
...@@ -742,7 +744,7 @@ void iriap_connect_request(struct iriap_cb *self) ...@@ -742,7 +744,7 @@ void iriap_connect_request(struct iriap_cb *self)
static void iriap_connect_confirm(void *instance, void *sap, static void iriap_connect_confirm(void *instance, void *sap,
struct qos_info *qos, __u32 max_seg_size, struct qos_info *qos, __u32 max_seg_size,
__u8 max_header_size, __u8 max_header_size,
struct sk_buff *userdata) struct sk_buff *skb)
{ {
struct iriap_cb *self; struct iriap_cb *self;
...@@ -750,14 +752,17 @@ static void iriap_connect_confirm(void *instance, void *sap, ...@@ -750,14 +752,17 @@ static void iriap_connect_confirm(void *instance, void *sap,
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;); ASSERT(self->magic == IAS_MAGIC, return;);
ASSERT(userdata != NULL, return;); ASSERT(skb != NULL, return;);
self->max_data_size = max_seg_size; self->max_data_size = max_seg_size;
self->max_header_size = max_header_size; self->max_header_size = max_header_size;
del_timer(&self->watchdog_timer); del_timer(&self->watchdog_timer);
iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata); iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb);
/* Drop reference count - see state_s_make_call(). */
dev_kfree_skb(skb);
} }
/* /*
...@@ -769,7 +774,7 @@ static void iriap_connect_confirm(void *instance, void *sap, ...@@ -769,7 +774,7 @@ static void iriap_connect_confirm(void *instance, void *sap,
static void iriap_connect_indication(void *instance, void *sap, static void iriap_connect_indication(void *instance, void *sap,
struct qos_info *qos, __u32 max_seg_size, struct qos_info *qos, __u32 max_seg_size,
__u8 max_header_size, __u8 max_header_size,
struct sk_buff *userdata) struct sk_buff *skb)
{ {
struct iriap_cb *self, *new; struct iriap_cb *self, *new;
...@@ -777,22 +782,22 @@ static void iriap_connect_indication(void *instance, void *sap, ...@@ -777,22 +782,22 @@ static void iriap_connect_indication(void *instance, void *sap,
self = (struct iriap_cb *) instance; self = (struct iriap_cb *) instance;
ASSERT(self != NULL, return;); ASSERT(skb != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;); ASSERT(self != NULL, goto out;);
ASSERT(self->magic == IAS_MAGIC, goto out;);
/* Start new server */ /* Start new server */
new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
if (!new) { if (!new) {
IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__);
dev_kfree_skb(userdata); goto out;
return;
} }
/* Now attach up the new "socket" */ /* Now attach up the new "socket" */
new->lsap = irlmp_dup(self->lsap, new); new->lsap = irlmp_dup(self->lsap, new);
if (!new->lsap) { if (!new->lsap) {
IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
return; goto out;
} }
new->max_data_size = max_seg_size; new->max_data_size = max_seg_size;
...@@ -801,7 +806,11 @@ static void iriap_connect_indication(void *instance, void *sap, ...@@ -801,7 +806,11 @@ static void iriap_connect_indication(void *instance, void *sap,
/* Clean up the original one to keep it in listen state */ /* Clean up the original one to keep it in listen state */
irlmp_listen(self->lsap); irlmp_listen(self->lsap);
iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, userdata); iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb);
out:
/* Drop reference count - see state_r_disconnect(). */
dev_kfree_skb(skb);
} }
/* /*
...@@ -821,10 +830,9 @@ static int iriap_data_indication(void *instance, void *sap, ...@@ -821,10 +830,9 @@ static int iriap_data_indication(void *instance, void *sap,
self = (struct iriap_cb *) instance; self = (struct iriap_cb *) instance;
ASSERT(self != NULL, return 0;);
ASSERT(self->magic == IAS_MAGIC, return 0;);
ASSERT(skb != NULL, return 0;); ASSERT(skb != NULL, return 0;);
ASSERT(self != NULL, goto out;);
ASSERT(self->magic == IAS_MAGIC, goto out;);
frame = skb->data; frame = skb->data;
...@@ -832,22 +840,19 @@ static int iriap_data_indication(void *instance, void *sap, ...@@ -832,22 +840,19 @@ static int iriap_data_indication(void *instance, void *sap,
/* Call server */ /* Call server */
IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__); IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__);
iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
goto out;
return 0;
} }
opcode = frame[0]; opcode = frame[0];
if (~opcode & IAP_LST) { if (~opcode & IAP_LST) {
WARNING("%s:, IrIAS multiframe commands or " WARNING("%s:, IrIAS multiframe commands or "
"results is not implemented yet!\n", __FUNCTION__); "results is not implemented yet!\n", __FUNCTION__);
dev_kfree_skb(skb); goto out;
return 0;
} }
/* Check for ack frames since they don't contain any data */ /* Check for ack frames since they don't contain any data */
if (opcode & IAP_ACK) { if (opcode & IAP_ACK) {
IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__); IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__);
dev_kfree_skb(skb); goto out;
return 0;
} }
opcode &= ~IAP_LST; /* Mask away LST bit */ opcode &= ~IAP_LST; /* Mask away LST bit */
...@@ -855,7 +860,6 @@ static int iriap_data_indication(void *instance, void *sap, ...@@ -855,7 +860,6 @@ static int iriap_data_indication(void *instance, void *sap,
switch (opcode) { switch (opcode) {
case GET_INFO_BASE: case GET_INFO_BASE:
IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n"); IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n");
dev_kfree_skb(skb);
break; break;
case GET_VALUE_BY_CLASS: case GET_VALUE_BY_CLASS:
iriap_do_call_event(self, IAP_RECV_F_LST, NULL); iriap_do_call_event(self, IAP_RECV_F_LST, NULL);
...@@ -876,7 +880,6 @@ static int iriap_data_indication(void *instance, void *sap, ...@@ -876,7 +880,6 @@ static int iriap_data_indication(void *instance, void *sap,
if (self->confirm) if (self->confirm)
self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
self->priv); self->priv);
dev_kfree_skb(skb);
break; break;
case IAS_ATTRIB_UNKNOWN: case IAS_ATTRIB_UNKNOWN:
IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__); IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__);
...@@ -890,16 +893,18 @@ static int iriap_data_indication(void *instance, void *sap, ...@@ -890,16 +893,18 @@ static int iriap_data_indication(void *instance, void *sap,
if (self->confirm) if (self->confirm)
self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL, self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL,
self->priv); self->priv);
dev_kfree_skb(skb);
break; break;
} }
break; break;
default: default:
IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__, IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__,
opcode); opcode);
dev_kfree_skb(skb);
break; break;
} }
out:
/* Cleanup - sub-calls will have done skb_get() as needed. */
dev_kfree_skb(skb);
return 0; return 0;
} }
...@@ -939,6 +944,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) ...@@ -939,6 +944,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
iriap_getvaluebyclass_indication(self, skb); iriap_getvaluebyclass_indication(self, skb);
break; break;
} }
/* skb will be cleaned up in iriap_data_indication */
} }
/* /*
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* *
* Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>, * Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -174,8 +175,11 @@ static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event, ...@@ -174,8 +175,11 @@ static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
switch (event) { switch (event) {
case IAP_CALL_REQUEST_GVBC: case IAP_CALL_REQUEST_GVBC:
iriap_next_client_state(self, S_CONNECTING); iriap_next_client_state(self, S_CONNECTING);
ASSERT(self->skb == NULL, return;); ASSERT(self->request_skb == NULL, return;);
self->skb = skb; /* Don't forget to refcount it -
* see iriap_getvaluebyclass_request(). */
skb_get(skb);
self->request_skb = skb;
iriap_connect_request(self); iriap_connect_request(self);
break; break;
case IAP_LM_DISCONNECT_INDICATION: case IAP_LM_DISCONNECT_INDICATION:
...@@ -251,20 +255,21 @@ static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event, ...@@ -251,20 +255,21 @@ static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event,
static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct sk_buff *tx_skb;
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
switch (event) { switch (event) {
case IAP_CALL_REQUEST: case IAP_CALL_REQUEST:
skb = self->skb; /* Already refcounted - see state_s_disconnect() */
self->skb = NULL; tx_skb = self->request_skb;
self->request_skb = NULL;
irlmp_data_request(self->lsap, skb); irlmp_data_request(self->lsap, tx_skb);
iriap_next_call_state(self, S_OUTSTANDING); iriap_next_call_state(self, S_OUTSTANDING);
break; break;
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
} }
...@@ -379,10 +384,6 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, ...@@ -379,10 +384,6 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
* care about LM_Idle_request()! * care about LM_Idle_request()!
*/ */
iriap_next_r_connect_state(self, R_RECEIVING); iriap_next_r_connect_state(self, R_RECEIVING);
if (skb)
dev_kfree_skb(skb);
break; break;
default: default:
IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event); IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event);
...@@ -450,7 +451,6 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, ...@@ -450,7 +451,6 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
break; break;
} }
} }
/* /*
...@@ -465,11 +465,8 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, ...@@ -465,11 +465,8 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
ASSERT(skb != NULL, return;); ASSERT(skb != NULL, return;);
ASSERT(self != NULL, return;);
if (!self || self->magic != IAS_MAGIC) { ASSERT(self->magic == IAS_MAGIC, return;);
IRDA_DEBUG(0, "%s(), bad pointer self\n", __FUNCTION__);
return;
}
switch (event) { switch (event) {
case IAP_CALL_RESPONSE: case IAP_CALL_RESPONSE:
...@@ -479,6 +476,10 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, ...@@ -479,6 +476,10 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
*/ */
iriap_next_r_connect_state(self, R_RECEIVING); iriap_next_r_connect_state(self, R_RECEIVING);
/* Don't forget to refcount it - see
* iriap_getvaluebyclass_response(). */
skb_get(skb);
irlmp_data_request(self->lsap, skb); irlmp_data_request(self->lsap, skb);
break; break;
default: default:
......
...@@ -1180,20 +1180,6 @@ void print_ret_code(__u8 code) ...@@ -1180,20 +1180,6 @@ void print_ret_code(__u8 code)
} }
} }
void irlan_mod_inc_use_count(void)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
void irlan_mod_dec_use_count(void)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("The Linux IrDA LAN protocol"); MODULE_DESCRIPTION("The Linux IrDA LAN protocol");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/module.h>
#include <net/arp.h> #include <net/arp.h>
#include <net/irda/irda.h> #include <net/irda/irda.h>
...@@ -61,6 +62,7 @@ int irlan_eth_init(struct net_device *dev) ...@@ -61,6 +62,7 @@ int irlan_eth_init(struct net_device *dev)
dev->hard_start_xmit = irlan_eth_xmit; dev->hard_start_xmit = irlan_eth_xmit;
dev->get_stats = irlan_eth_get_stats; dev->get_stats = irlan_eth_get_stats;
dev->set_multicast_list = irlan_eth_set_multicast_list; dev->set_multicast_list = irlan_eth_set_multicast_list;
SET_MODULE_OWNER(dev);
ether_setup(dev); ether_setup(dev);
...@@ -112,8 +114,6 @@ int irlan_eth_open(struct net_device *dev) ...@@ -112,8 +114,6 @@ int irlan_eth_open(struct net_device *dev)
self->disconnect_reason = 0; self->disconnect_reason = 0;
irlan_client_wakeup(self, self->saddr, self->daddr); irlan_client_wakeup(self, self->saddr, self->daddr);
irlan_mod_inc_use_count();
/* Make sure we have a hardware address before we return, so DHCP clients gets happy */ /* Make sure we have a hardware address before we return, so DHCP clients gets happy */
interruptible_sleep_on(&self->open_wait); interruptible_sleep_on(&self->open_wait);
...@@ -138,8 +138,6 @@ int irlan_eth_close(struct net_device *dev) ...@@ -138,8 +138,6 @@ int irlan_eth_close(struct net_device *dev)
/* Stop device */ /* Stop device */
netif_stop_queue(dev); netif_stop_queue(dev);
irlan_mod_dec_use_count();
irlan_close_data_channel(self); irlan_close_data_channel(self);
irlan_close_tsaps(self); irlan_close_tsaps(self);
...@@ -206,7 +204,7 @@ int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -206,7 +204,7 @@ int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev)
* confuse do_dev_queue_xmit() in dev.c! I have * confuse do_dev_queue_xmit() in dev.c! I have
* tried :-) DB * tried :-) DB
*/ */
dev_kfree_skb(skb); /* irttp_data_request already free the packet */
self->stats.tx_dropped++; self->stats.tx_dropped++;
} else { } else {
self->stats.tx_packets++; self->stats.tx_packets++;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no> * Modified by: Dag Brattli <dagb@cs.uit.no>
* *
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -244,7 +244,6 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) ...@@ -244,7 +244,6 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
irlap_init_qos_capabilities(self, NULL); /* No user QoS! */ irlap_init_qos_capabilities(self, NULL); /* No user QoS! */
skb_get(skb); /*LEVEL4*/
irlmp_link_connect_indication(self->notify.instance, self->saddr, irlmp_link_connect_indication(self->notify.instance, self->saddr,
self->daddr, &self->qos_tx, skb); self->daddr, &self->qos_tx, skb);
} }
...@@ -255,12 +254,11 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) ...@@ -255,12 +254,11 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
* Service user has accepted incoming connection * Service user has accepted incoming connection
* *
*/ */
void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata)
{ {
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
irlap_do_event(self, CONNECT_RESPONSE, skb, NULL); irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);
kfree_skb(skb);
} }
/* /*
...@@ -305,7 +303,6 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb) ...@@ -305,7 +303,6 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
skb_get(skb); /*LEVEL4*/
irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb); irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);
} }
...@@ -322,7 +319,6 @@ void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb, ...@@ -322,7 +319,6 @@ void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,
/* Hide LAP header from IrLMP layer */ /* Hide LAP header from IrLMP layer */
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
skb_get(skb); /*LEVEL4*/
irlmp_link_data_indication(self->notify.instance, skb, unreliable); irlmp_link_data_indication(self->notify.instance, skb, unreliable);
} }
...@@ -354,6 +350,9 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, ...@@ -354,6 +350,9 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
else else
skb->data[1] = I_FRAME; skb->data[1] = I_FRAME;
/* Don't forget to refcount it - see irlmp_connect_request(). */
skb_get(skb);
/* Add at the end of the queue (keep ordering) - Jean II */ /* Add at the end of the queue (keep ordering) - Jean II */
skb_queue_tail(&self->txq, skb); skb_queue_tail(&self->txq, skb);
...@@ -392,6 +391,8 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb) ...@@ -392,6 +391,8 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
skb->data[0] = CBROADCAST; skb->data[0] = CBROADCAST;
skb->data[1] = UI_FRAME; skb->data[1] = UI_FRAME;
/* Don't need to refcount, see irlmp_connless_data_request() */
skb_queue_tail(&self->txq_ultra, skb); skb_queue_tail(&self->txq_ultra, skb);
irlap_do_event(self, SEND_UI_FRAME, NULL, NULL); irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
...@@ -416,7 +417,6 @@ void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb) ...@@ -416,7 +417,6 @@ void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
/* Hide LAP header from IrLMP layer */ /* Hide LAP header from IrLMP layer */
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
skb_get(skb); /*LEVEL4*/
irlmp_link_unitdata_indication(self->notify.instance, skb); irlmp_link_unitdata_indication(self->notify.instance, skb);
} }
#endif /* CONFIG_IRDA_ULTRA */ #endif /* CONFIG_IRDA_ULTRA */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>, * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>,
* Copyright (c) 1998 Thomas Davis <ratbert@radiks.net> * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net>
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -287,6 +287,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -287,6 +287,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
/* Send one frame */ /* Send one frame */
ret = (*state[self->state])(self, SEND_I_CMD, ret = (*state[self->state])(self, SEND_I_CMD,
skb, NULL); skb, NULL);
/* Drop reference count.
* It will be increase as needed in
* irlap_send_data_xxx() */
kfree_skb(skb); kfree_skb(skb);
/* Poll the higher layers for one more frame */ /* Poll the higher layers for one more frame */
...@@ -517,6 +520,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -517,6 +520,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
CMD_FRAME); CMD_FRAME);
else else
break; break;
/* irlap_send_ui_frame() won't increase skb reference
* count, so no dev_kfree_skb() - Jean II */
} }
if (i == 2) { if (i == 2) {
/* Force us to listen 500 ms again */ /* Force us to listen 500 ms again */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -106,7 +106,7 @@ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb) ...@@ -106,7 +106,7 @@ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
*/ */
void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
struct snrm_frame *frame; struct snrm_frame *frame;
int ret; int ret;
...@@ -114,11 +114,11 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) ...@@ -114,11 +114,11 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
/* Allocate frame */ /* Allocate frame */
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return; return;
frame = (struct snrm_frame *) skb_put(skb, 2); frame = (struct snrm_frame *) skb_put(tx_skb, 2);
/* Insert connection address field */ /* Insert connection address field */
if (qos) if (qos)
...@@ -133,19 +133,19 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) ...@@ -133,19 +133,19 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
* If we are establishing a connection then insert QoS paramerters * If we are establishing a connection then insert QoS paramerters
*/ */
if (qos) { if (qos) {
skb_put(skb, 9); /* 21 left */ skb_put(tx_skb, 9); /* 21 left */
frame->saddr = cpu_to_le32(self->saddr); frame->saddr = cpu_to_le32(self->saddr);
frame->daddr = cpu_to_le32(self->daddr); frame->daddr = cpu_to_le32(self->daddr);
frame->ncaddr = self->caddr; frame->ncaddr = self->caddr;
ret = irlap_insert_qos_negotiation_params(self, skb); ret = irlap_insert_qos_negotiation_params(self, tx_skb);
if (ret < 0) { if (ret < 0) {
dev_kfree_skb(skb); dev_kfree_skb(tx_skb);
return; return;
} }
} }
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -162,8 +162,8 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, ...@@ -162,8 +162,8 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
frame = (struct snrm_frame *) skb->data; frame = (struct snrm_frame *) skb->data;
if (skb->len >= sizeof(struct snrm_frame)) { if (skb->len >= sizeof(struct snrm_frame)) {
/* Copy the new connection address */ /* Copy the new connection address ignoring the C/R bit */
info->caddr = frame->ncaddr; info->caddr = frame->ncaddr & 0xFE;
/* Check if the new connection address is valid */ /* Check if the new connection address is valid */
if ((info->caddr == 0x00) || (info->caddr == 0xfe)) { if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
...@@ -197,7 +197,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, ...@@ -197,7 +197,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
*/ */
void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
struct ua_frame *frame; struct ua_frame *frame;
int ret; int ret;
...@@ -206,14 +206,12 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) ...@@ -206,14 +206,12 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
skb = NULL;
/* Allocate frame */ /* Allocate frame */
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return; return;
frame = (struct ua_frame *) skb_put(skb, 10); frame = (struct ua_frame *) skb_put(tx_skb, 10);
/* Build UA response */ /* Build UA response */
frame->caddr = self->caddr; frame->caddr = self->caddr;
...@@ -224,14 +222,14 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) ...@@ -224,14 +222,14 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
/* Should we send QoS negotiation parameters? */ /* Should we send QoS negotiation parameters? */
if (qos) { if (qos) {
ret = irlap_insert_qos_negotiation_params(self, skb); ret = irlap_insert_qos_negotiation_params(self, tx_skb);
if (ret < 0) { if (ret < 0) {
dev_kfree_skb(skb); dev_kfree_skb(tx_skb);
return; return;
} }
} }
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
...@@ -243,17 +241,17 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) ...@@ -243,17 +241,17 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
*/ */
void irlap_send_dm_frame( struct irlap_cb *self) void irlap_send_dm_frame( struct irlap_cb *self)
{ {
struct sk_buff *skb = NULL; struct sk_buff *tx_skb = NULL;
__u8 *frame; __u8 *frame;
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
skb = dev_alloc_skb(32); tx_skb = dev_alloc_skb(32);
if (!skb) if (!tx_skb)
return; return;
frame = skb_put( skb, 2); frame = skb_put(tx_skb, 2);
if (self->state == LAP_NDM) if (self->state == LAP_NDM)
frame[0] = CBROADCAST; frame[0] = CBROADCAST;
...@@ -262,7 +260,7 @@ void irlap_send_dm_frame( struct irlap_cb *self) ...@@ -262,7 +260,7 @@ void irlap_send_dm_frame( struct irlap_cb *self)
frame[1] = DM_RSP | PF_BIT; frame[1] = DM_RSP | PF_BIT;
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -273,7 +271,7 @@ void irlap_send_dm_frame( struct irlap_cb *self) ...@@ -273,7 +271,7 @@ void irlap_send_dm_frame( struct irlap_cb *self)
*/ */
void irlap_send_disc_frame(struct irlap_cb *self) void irlap_send_disc_frame(struct irlap_cb *self)
{ {
struct sk_buff *skb = NULL; struct sk_buff *tx_skb = NULL;
__u8 *frame; __u8 *frame;
IRDA_DEBUG(3, "%s()\n", __FUNCTION__); IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
...@@ -281,16 +279,16 @@ void irlap_send_disc_frame(struct irlap_cb *self) ...@@ -281,16 +279,16 @@ void irlap_send_disc_frame(struct irlap_cb *self)
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
skb = dev_alloc_skb(16); tx_skb = dev_alloc_skb(16);
if (!skb) if (!tx_skb)
return; return;
frame = skb_put(skb, 2); frame = skb_put(tx_skb, 2);
frame[0] = self->caddr | CMD_FRAME; frame[0] = self->caddr | CMD_FRAME;
frame[1] = DISC_CMD | PF_BIT; frame[1] = DISC_CMD | PF_BIT;
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -302,7 +300,7 @@ void irlap_send_disc_frame(struct irlap_cb *self) ...@@ -302,7 +300,7 @@ void irlap_send_disc_frame(struct irlap_cb *self)
void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
__u8 command, discovery_t *discovery) __u8 command, discovery_t *discovery)
{ {
struct sk_buff *skb = NULL; struct sk_buff *tx_skb = NULL;
struct xid_frame *frame; struct xid_frame *frame;
__u32 bcast = BROADCAST; __u32 bcast = BROADCAST;
__u8 *info; __u8 *info;
...@@ -314,12 +312,12 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, ...@@ -314,12 +312,12 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
ASSERT(discovery != NULL, return;); ASSERT(discovery != NULL, return;);
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return; return;
skb_put(skb, 14); skb_put(tx_skb, 14);
frame = (struct xid_frame *) skb->data; frame = (struct xid_frame *) tx_skb->data;
if (command) { if (command) {
frame->caddr = CBROADCAST | CMD_FRAME; frame->caddr = CBROADCAST | CMD_FRAME;
...@@ -367,21 +365,21 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, ...@@ -367,21 +365,21 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
int len; int len;
if (discovery->data.hints[0] & HINT_EXTENSION) { if (discovery->data.hints[0] & HINT_EXTENSION) {
info = skb_put(skb, 2); info = skb_put(tx_skb, 2);
info[0] = discovery->data.hints[0]; info[0] = discovery->data.hints[0];
info[1] = discovery->data.hints[1]; info[1] = discovery->data.hints[1];
} else { } else {
info = skb_put(skb, 1); info = skb_put(tx_skb, 1);
info[0] = discovery->data.hints[0]; info[0] = discovery->data.hints[0];
} }
info = skb_put(skb, 1); info = skb_put(tx_skb, 1);
info[0] = discovery->data.charset; info[0] = discovery->data.charset;
len = IRDA_MIN(discovery->name_len, skb_tailroom(skb)); len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb));
info = skb_put(skb, len); info = skb_put(tx_skb, len);
memcpy(info, discovery->data.info, len); memcpy(info, discovery->data.info, len);
} }
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -498,7 +496,6 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, ...@@ -498,7 +496,6 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
break; break;
default: default:
/* Error!! */ /* Error!! */
dev_kfree_skb(skb);
return; return;
} }
info->s = xid->slotnr; info->s = xid->slotnr;
...@@ -561,21 +558,21 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, ...@@ -561,21 +558,21 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
*/ */
void irlap_send_rr_frame(struct irlap_cb *self, int command) void irlap_send_rr_frame(struct irlap_cb *self, int command)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
__u8 *frame; __u8 *frame;
skb = dev_alloc_skb(16); tx_skb = dev_alloc_skb(16);
if (!skb) if (!tx_skb)
return; return;
frame = skb_put(skb, 2); frame = skb_put(tx_skb, 2);
frame[0] = self->caddr; frame[0] = self->caddr;
frame[0] |= (command) ? CMD_FRAME : 0; frame[0] |= (command) ? CMD_FRAME : 0;
frame[1] = RR | PF_BIT | (self->vr << 5); frame[1] = RR | PF_BIT | (self->vr << 5);
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -586,19 +583,19 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command) ...@@ -586,19 +583,19 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command)
*/ */
void irlap_send_rd_frame(struct irlap_cb *self) void irlap_send_rd_frame(struct irlap_cb *self)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
__u8 *frame; __u8 *frame;
skb = dev_alloc_skb(16); tx_skb = dev_alloc_skb(16);
if (!skb) if (!tx_skb)
return; return;
frame = skb_put(skb, 2); frame = skb_put(tx_skb, 2);
frame[0] = self->caddr; frame[0] = self->caddr;
frame[1] = RD_RSP | PF_BIT; frame[1] = RD_RSP | PF_BIT;
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -623,17 +620,17 @@ static inline void irlap_recv_rr_frame(struct irlap_cb *self, ...@@ -623,17 +620,17 @@ static inline void irlap_recv_rr_frame(struct irlap_cb *self,
void irlap_send_frmr_frame( struct irlap_cb *self, int command) void irlap_send_frmr_frame( struct irlap_cb *self, int command)
{ {
struct sk_buff *skb = NULL; struct sk_buff *tx_skb = NULL;
__u8 *frame; __u8 *frame;
ASSERT( self != NULL, return;); ASSERT( self != NULL, return;);
ASSERT( self->magic == LAP_MAGIC, return;); ASSERT( self->magic == LAP_MAGIC, return;);
skb = dev_alloc_skb( 32); tx_skb = dev_alloc_skb( 32);
if (!skb) if (!tx_skb)
return; return;
frame = skb_put( skb, 2); frame = skb_put(tx_skb, 2);
frame[0] = self->caddr; frame[0] = self->caddr;
frame[0] |= (command) ? CMD_FRAME : 0; frame[0] |= (command) ? CMD_FRAME : 0;
...@@ -646,7 +643,7 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command) ...@@ -646,7 +643,7 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command)
IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies); IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies);
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -739,17 +736,19 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb) ...@@ -739,17 +736,19 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
*/ */
skb->data[1] = I_FRAME | (self->vs << 1); skb->data[1] = I_FRAME | (self->vs << 1);
/*
* Insert frame in store, in case of retransmissions
* Increase skb reference count, see irlap_do_event()
*/
skb_get(skb);
skb_queue_tail(&self->wx_list, skb);
/* Copy buffer */ /* Copy buffer */
tx_skb = skb_clone(skb, GFP_ATOMIC); tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) { if (tx_skb == NULL) {
return; return;
} }
/*
* Insert frame in store, in case of retransmissions
*/
skb_queue_tail(&self->wx_list, skb_get(skb));
self->vs = (self->vs + 1) % 8; self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE; self->ack_required = FALSE;
self->window -= 1; self->window -= 1;
...@@ -782,17 +781,19 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) ...@@ -782,17 +781,19 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
*/ */
skb->data[1] = I_FRAME | (self->vs << 1); skb->data[1] = I_FRAME | (self->vs << 1);
/*
* Insert frame in store, in case of retransmissions
* Increase skb reference count, see irlap_do_event()
*/
skb_get(skb);
skb_queue_tail(&self->wx_list, skb);
/* Copy buffer */ /* Copy buffer */
tx_skb = skb_clone(skb, GFP_ATOMIC); tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) { if (tx_skb == NULL) {
return; return;
} }
/*
* Insert frame in store, in case of retransmissions
*/
skb_queue_tail(&self->wx_list, skb_get(skb));
/* /*
* Set poll bit if necessary. We do this to the copied * Set poll bit if necessary. We do this to the copied
* skb, since retransmitted need to set or clear the poll * skb, since retransmitted need to set or clear the poll
...@@ -850,14 +851,18 @@ void irlap_send_data_secondary_final(struct irlap_cb *self, ...@@ -850,14 +851,18 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
*/ */
skb->data[1] = I_FRAME | (self->vs << 1); skb->data[1] = I_FRAME | (self->vs << 1);
/*
* Insert frame in store, in case of retransmissions
* Increase skb reference count, see irlap_do_event()
*/
skb_get(skb);
skb_queue_tail(&self->wx_list, skb);
tx_skb = skb_clone(skb, GFP_ATOMIC); tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) { if (tx_skb == NULL) {
return; return;
} }
/* Insert frame in store */
skb_queue_tail(&self->wx_list, skb_get(skb));
tx_skb->data[1] |= PF_BIT; tx_skb->data[1] |= PF_BIT;
self->vs = (self->vs + 1) % 8; self->vs = (self->vs + 1) % 8;
...@@ -903,14 +908,18 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) ...@@ -903,14 +908,18 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
*/ */
skb->data[1] = I_FRAME | (self->vs << 1); skb->data[1] = I_FRAME | (self->vs << 1);
/*
* Insert frame in store, in case of retransmissions
* Increase skb reference count, see irlap_do_event()
*/
skb_get(skb);
skb_queue_tail(&self->wx_list, skb);
tx_skb = skb_clone(skb, GFP_ATOMIC); tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) { if (tx_skb == NULL) {
return; return;
} }
/* Insert frame in store */
skb_queue_tail(&self->wx_list, skb_get(skb));
self->vs = (self->vs + 1) % 8; self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE; self->ack_required = FALSE;
self->window -= 1; self->window -= 1;
...@@ -939,8 +948,6 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) ...@@ -939,8 +948,6 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
/* Initialize variables */ /* Initialize variables */
skb = tx_skb = NULL;
count = skb_queue_len(&self->wx_list); count = skb_queue_len(&self->wx_list);
/* Resend unacknowledged frame(s) */ /* Resend unacknowledged frame(s) */
...@@ -1020,9 +1027,6 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command) ...@@ -1020,9 +1027,6 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
ASSERT(self != NULL, return;); ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->magic == LAP_MAGIC, return;);
/* Initialize variables */
skb = tx_skb = NULL;
/* Resend unacknowledged frame(s) */ /* Resend unacknowledged frame(s) */
skb = skb_peek(&self->wx_list); skb = skb_peek(&self->wx_list);
if (skb != NULL) { if (skb != NULL) {
...@@ -1186,35 +1190,35 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, ...@@ -1186,35 +1190,35 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
struct sk_buff *cmd) struct sk_buff *cmd)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
struct test_frame *frame; struct test_frame *frame;
__u8 *info; __u8 *info;
skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame)); tx_skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame));
if (!skb) if (!tx_skb)
return; return;
/* Broadcast frames must include saddr and daddr fields */ /* Broadcast frames must include saddr and daddr fields */
if (caddr == CBROADCAST) { if (caddr == CBROADCAST) {
frame = (struct test_frame *) frame = (struct test_frame *)
skb_put(skb, sizeof(struct test_frame)); skb_put(tx_skb, sizeof(struct test_frame));
/* Insert the swapped addresses */ /* Insert the swapped addresses */
frame->saddr = cpu_to_le32(self->saddr); frame->saddr = cpu_to_le32(self->saddr);
frame->daddr = cpu_to_le32(daddr); frame->daddr = cpu_to_le32(daddr);
} else } else
frame = (struct test_frame *) skb_put(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); frame = (struct test_frame *) skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
frame->caddr = caddr; frame->caddr = caddr;
frame->control = TEST_RSP | PF_BIT; frame->control = TEST_RSP | PF_BIT;
/* Copy info */ /* Copy info */
info = skb_put(skb, cmd->len); info = skb_put(tx_skb, cmd->len);
memcpy(info, cmd->data, cmd->len); memcpy(info, cmd->data, cmd->len);
/* Return to sender */ /* Return to sender */
irlap_wait_min_turn_around(self, &self->qos_tx); irlap_wait_min_turn_around(self, &self->qos_tx);
irlap_queue_xmit(self, skb); irlap_queue_xmit(self, tx_skb);
} }
/* /*
...@@ -1263,6 +1267,15 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, ...@@ -1263,6 +1267,15 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
* Called when a frame is received. Dispatches the right receive function * Called when a frame is received. Dispatches the right receive function
* for processing of the frame. * for processing of the frame.
* *
* Note on skb management :
* After calling the higher layers of the IrDA stack, we always
* kfree() the skb, which drop the reference count (and potentially
* destroy it).
* If a higher layer of the stack want to keep the skb around (to put
* in a queue or pass it to the higher layer), it will need to use
* skb_get() to keep a reference on it. This is usually done at the
* LMP level in irlmp.c.
* Jean II
*/ */
int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype) struct packet_type *ptype)
...@@ -1286,6 +1299,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -1286,6 +1299,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
* we don't need to be clever about it. Jean II */ * we don't need to be clever about it. Jean II */
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
ERROR("%s: can't clone shared skb!\n", __FUNCTION__); ERROR("%s: can't clone shared skb!\n", __FUNCTION__);
dev_kfree_skb(skb);
return -1; return -1;
} }
if (skb_is_nonlinear(skb)) if (skb_is_nonlinear(skb))
...@@ -1390,6 +1404,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -1390,6 +1404,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
break; break;
} }
out: out:
/* Always drop our reference on the skb */
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
} }
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -345,9 +345,10 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, ...@@ -345,9 +345,10 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
__u32 saddr, __u32 daddr, __u32 saddr, __u32 daddr,
struct qos_info *qos, struct sk_buff *userdata) struct qos_info *qos, struct sk_buff *userdata)
{ {
struct sk_buff *skb = NULL; struct sk_buff *tx_skb = userdata;
struct lap_cb *lap; struct lap_cb *lap;
struct lsap_cb *lsap; struct lsap_cb *lsap;
int ret;
ASSERT(self != NULL, return -EBADR;); ASSERT(self != NULL, return -EBADR;);
ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
...@@ -356,26 +357,29 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, ...@@ -356,26 +357,29 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
"%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
__FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr); __FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr);
if (test_bit(0, &self->connected)) if (test_bit(0, &self->connected)) {
return -EISCONN; ret = -EISCONN;
goto err;
}
/* Client must supply destination device address */ /* Client must supply destination device address */
if (!daddr) if (!daddr) {
return -EINVAL; ret = -EINVAL;
goto err;
}
/* Any userdata? */ /* Any userdata? */
if (userdata == NULL) { if (tx_skb == NULL) {
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return -ENOMEM; return -ENOMEM;
skb_reserve(skb, LMP_MAX_HEADER); skb_reserve(tx_skb, LMP_MAX_HEADER);
} else }
skb = userdata;
/* Make room for MUX control header (3 bytes) */ /* Make room for MUX control header (3 bytes) */
ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;); ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;);
skb_push(skb, LMP_CONTROL_HEADER); skb_push(tx_skb, LMP_CONTROL_HEADER);
self->dlsap_sel = dlsap_sel; self->dlsap_sel = dlsap_sel;
...@@ -409,7 +413,8 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, ...@@ -409,7 +413,8 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
lap = hashbin_lock_find(irlmp->links, saddr, NULL); lap = hashbin_lock_find(irlmp->links, saddr, NULL);
if (lap == NULL) { if (lap == NULL) {
IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__); IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__);
return -EHOSTUNREACH; ret = -EHOSTUNREACH;
goto err;
} }
/* Check if LAP is disconnected or already connected */ /* Check if LAP is disconnected or already connected */
...@@ -423,13 +428,15 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, ...@@ -423,13 +428,15 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
* Maybe we could give LAP a bit of help in this case. * Maybe we could give LAP a bit of help in this case.
*/ */
IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__);
return -EAGAIN; ret = -EAGAIN;
goto err;
} }
/* LAP is already connected to a different node, and LAP /* LAP is already connected to a different node, and LAP
* can only talk to one node at a time */ * can only talk to one node at a time */
IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__);
return -EBUSY; ret = -EBUSY;
goto err;
} }
self->lap = lap; self->lap = lap;
...@@ -456,9 +463,18 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, ...@@ -456,9 +463,18 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
if (qos) if (qos)
self->qos = *qos; self->qos = *qos;
irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, skb); irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb);
/* Drop reference count - see irlap_data_request(). */
dev_kfree_skb(tx_skb);
return 0; return 0;
err:
/* Cleanup */
if(tx_skb)
dev_kfree_skb(tx_skb);
return ret;
} }
/* /*
...@@ -495,12 +511,13 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) ...@@ -495,12 +511,13 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP_CONTROL_HEADER header from layer above */ /* Hide LMP_CONTROL_HEADER header from layer above */
skb_pull(skb, LMP_CONTROL_HEADER); skb_pull(skb, LMP_CONTROL_HEADER);
if (self->notify.connect_indication) if (self->notify.connect_indication) {
/* Don't forget to refcount it - see irlap_driver_rcv(). */
skb_get(skb);
self->notify.connect_indication(self->notify.instance, self, self->notify.connect_indication(self->notify.instance, self,
&self->qos, max_seg_size, &self->qos, max_seg_size,
max_header_size, skb); max_header_size, skb);
else }
dev_kfree_skb(skb);
} }
/* /*
...@@ -526,6 +543,9 @@ int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) ...@@ -526,6 +543,9 @@ int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata); irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
/* Drop reference count - see irlap_data_request(). */
dev_kfree_skb(userdata);
return 0; return 0;
} }
...@@ -560,11 +580,12 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) ...@@ -560,11 +580,12 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
skb_pull(skb, LMP_CONTROL_HEADER); skb_pull(skb, LMP_CONTROL_HEADER);
if (self->notify.connect_confirm) { if (self->notify.connect_confirm) {
/* Don't forget to refcount it - see irlap_driver_rcv() */
skb_get(skb);
self->notify.connect_confirm(self->notify.instance, self, self->notify.connect_confirm(self->notify.instance, self,
&self->qos, max_seg_size, &self->qos, max_seg_size,
max_header_size, skb); max_header_size, skb);
} else }
dev_kfree_skb(skb);
} }
/* /*
...@@ -602,6 +623,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) ...@@ -602,6 +623,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
memcpy(new, orig, sizeof(struct lsap_cb)); memcpy(new, orig, sizeof(struct lsap_cb));
/* new->lap = orig->lap; => done in the memcpy() */ /* new->lap = orig->lap; => done in the memcpy() */
/* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */ /* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */
new->conn_skb = NULL;
spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
...@@ -653,6 +675,9 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) ...@@ -653,6 +675,9 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
*/ */
irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata); irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);
/* Drop reference count - see irlap_data_request(). */
dev_kfree_skb(userdata);
/* /*
* Remove LSAP from list of connected LSAPs for the particular link * Remove LSAP from list of connected LSAPs for the particular link
* and insert it into the list of unconnected LSAPs * and insert it into the list of unconnected LSAPs
...@@ -686,7 +711,7 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) ...@@ -686,7 +711,7 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
* LSAP is being closed! * LSAP is being closed!
*/ */
void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
struct sk_buff *userdata) struct sk_buff *skb)
{ {
struct lsap_cb *lsap; struct lsap_cb *lsap;
...@@ -703,8 +728,6 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, ...@@ -703,8 +728,6 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
* Jean II */ * Jean II */
if (! test_and_clear_bit(0, &self->connected)) { if (! test_and_clear_bit(0, &self->connected)) {
IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
if (userdata)
dev_kfree_skb(userdata);
return; return;
} }
...@@ -730,13 +753,14 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, ...@@ -730,13 +753,14 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
/* /*
* Inform service user * Inform service user
*/ */
if (self->notify.disconnect_indication) if (self->notify.disconnect_indication) {
/* Don't forget to refcount it - see irlap_driver_rcv(). */
if(skb)
skb_get(skb);
self->notify.disconnect_indication(self->notify.instance, self->notify.disconnect_indication(self->notify.instance,
self, reason, userdata); self, reason, skb);
else { } else {
IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__);
if (userdata)
dev_kfree_skb(userdata);
} }
} }
...@@ -1047,17 +1071,31 @@ discovery_t *irlmp_get_discovery_response() ...@@ -1047,17 +1071,31 @@ discovery_t *irlmp_get_discovery_response()
* *
* Send some data to peer device * Send some data to peer device
* *
* Note on skb management :
* After calling the lower layers of the IrDA stack, we always
* kfree() the skb, which drop the reference count (and potentially
* destroy it).
* IrLMP and IrLAP may queue the packet, and in those cases will need
* to use skb_get() to keep it around.
* Jean II
*/ */
int irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb) int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata)
{ {
int ret;
ASSERT(self != NULL, return -1;); ASSERT(self != NULL, return -1;);
ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
/* Make room for MUX header */ /* Make room for MUX header */
ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;); ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
skb_push(skb, LMP_HEADER); skb_push(userdata, LMP_HEADER);
ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata);
return irlmp_do_lsap_event(self, LM_DATA_REQUEST, skb); /* Drop reference count - see irlap_data_request(). */
dev_kfree_skb(userdata);
return ret;
} }
/* /*
...@@ -1071,26 +1109,34 @@ void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) ...@@ -1071,26 +1109,34 @@ void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP header from layer above */ /* Hide LMP header from layer above */
skb_pull(skb, LMP_HEADER); skb_pull(skb, LMP_HEADER);
if (self->notify.data_indication) if (self->notify.data_indication) {
/* Don't forget to refcount it - see irlap_driver_rcv(). */
skb_get(skb);
self->notify.data_indication(self->notify.instance, self, skb); self->notify.data_indication(self->notify.instance, self, skb);
else }
dev_kfree_skb(skb);
} }
/* /*
* Function irlmp_udata_request (self, skb) * Function irlmp_udata_request (self, skb)
*/ */
int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb) int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata)
{ {
int ret;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
ASSERT(skb != NULL, return -1;); ASSERT(userdata != NULL, return -1;);
/* Make room for MUX header */ /* Make room for MUX header */
ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;); ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
skb_push(skb, LMP_HEADER); skb_push(userdata, LMP_HEADER);
ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata);
return irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb); /* Drop reference count - see irlap_data_request(). */
dev_kfree_skb(userdata);
return ret;
} }
/* /*
...@@ -1110,51 +1156,57 @@ void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) ...@@ -1110,51 +1156,57 @@ void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP header from layer above */ /* Hide LMP header from layer above */
skb_pull(skb, LMP_HEADER); skb_pull(skb, LMP_HEADER);
if (self->notify.udata_indication) if (self->notify.udata_indication) {
/* Don't forget to refcount it - see irlap_driver_rcv(). */
skb_get(skb);
self->notify.udata_indication(self->notify.instance, self, self->notify.udata_indication(self->notify.instance, self,
skb); skb);
else }
dev_kfree_skb(skb);
} }
/* /*
* Function irlmp_connless_data_request (self, skb) * Function irlmp_connless_data_request (self, skb)
*/ */
#ifdef CONFIG_IRDA_ULTRA #ifdef CONFIG_IRDA_ULTRA
int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *skb) int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata)
{ {
struct sk_buff *clone_skb; struct sk_buff *clone_skb;
struct lap_cb *lap; struct lap_cb *lap;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
ASSERT(skb != NULL, return -1;); ASSERT(userdata != NULL, return -1;);
/* Make room for MUX and PID header */ /* Make room for MUX and PID header */
ASSERT(skb_headroom(skb) >= LMP_HEADER+LMP_PID_HEADER, return -1;); ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER,
return -1;);
/* Insert protocol identifier */ /* Insert protocol identifier */
skb_push(skb, LMP_PID_HEADER); skb_push(userdata, LMP_PID_HEADER);
skb->data[0] = self->pid; userdata->data[0] = self->pid;
/* Connectionless sockets must use 0x70 */ /* Connectionless sockets must use 0x70 */
skb_push(skb, LMP_HEADER); skb_push(userdata, LMP_HEADER);
skb->data[0] = skb->data[1] = LSAP_CONNLESS; userdata->data[0] = userdata->data[1] = LSAP_CONNLESS;
/* Try to send Connectionless packets out on all links */ /* Try to send Connectionless packets out on all links */
lap = (struct lap_cb *) hashbin_get_first(irlmp->links); lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
while (lap != NULL) { while (lap != NULL) {
ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;); ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
clone_skb = skb_clone(skb, GFP_ATOMIC); clone_skb = skb_clone(userdata, GFP_ATOMIC);
if (!clone_skb) if (!clone_skb) {
dev_kfree_skb(userdata);
return -ENOMEM; return -ENOMEM;
}
irlap_unitdata_request(lap->irlap, clone_skb); irlap_unitdata_request(lap->irlap, clone_skb);
/* irlap_unitdata_request() don't increase refcount,
* so no dev_kfree_skb() - Jean II */
lap = (struct lap_cb *) hashbin_get_next(irlmp->links); lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
} }
dev_kfree_skb(skb); dev_kfree_skb(userdata);
return 0; return 0;
} }
...@@ -1178,11 +1230,12 @@ void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) ...@@ -1178,11 +1230,12 @@ void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP and PID header from layer above */ /* Hide LMP and PID header from layer above */
skb_pull(skb, LMP_HEADER+LMP_PID_HEADER); skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
if (self->notify.udata_indication) if (self->notify.udata_indication) {
/* Don't forget to refcount it - see irlap_driver_rcv(). */
skb_get(skb);
self->notify.udata_indication(self->notify.instance, self, self->notify.udata_indication(self->notify.instance, self,
skb); skb);
else }
dev_kfree_skb(skb);
} }
#endif /* CONFIG_IRDA_ULTRA */ #endif /* CONFIG_IRDA_ULTRA */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -295,8 +295,6 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, ...@@ -295,8 +295,6 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n", IRDA_DEBUG(0, "%s(), Unknown event %s\n",
__FUNCTION__, irlmp_event[event]); __FUNCTION__, irlmp_event[event]);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
} }
...@@ -373,8 +371,6 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, ...@@ -373,8 +371,6 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n", IRDA_DEBUG(0, "%s(), Unknown event %s\n",
__FUNCTION__, irlmp_event[event]); __FUNCTION__, irlmp_event[event]);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
} }
...@@ -468,8 +464,6 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, ...@@ -468,8 +464,6 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n", IRDA_DEBUG(0, "%s(), Unknown event %s\n",
__FUNCTION__, irlmp_event[event]); __FUNCTION__, irlmp_event[event]);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
} }
...@@ -499,6 +493,9 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -499,6 +493,9 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
switch (event) { switch (event) {
#ifdef CONFIG_IRDA_ULTRA #ifdef CONFIG_IRDA_ULTRA
case LM_UDATA_INDICATION: case LM_UDATA_INDICATION:
/* This is most bizzare. Those packets are aka unreliable
* connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA.
* Why do we pass them as Ultra ??? Jean II */
irlmp_connless_data_indication(self, skb); irlmp_connless_data_indication(self, skb);
break; break;
#endif /* CONFIG_IRDA_ULTRA */ #endif /* CONFIG_IRDA_ULTRA */
...@@ -510,6 +507,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -510,6 +507,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
__FUNCTION__); __FUNCTION__);
return -EBUSY; return -EBUSY;
} }
/* Don't forget to refcount it (see irlmp_connect_request()) */
skb_get(skb);
self->conn_skb = skb; self->conn_skb = skb;
irlmp_next_lsap_state(self, LSAP_SETUP_PEND); irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
...@@ -525,6 +524,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -525,6 +524,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
__FUNCTION__); __FUNCTION__);
return -EBUSY; return -EBUSY;
} }
/* Don't forget to refcount it (see irlap_driver_rcv()) */
skb_get(skb);
self->conn_skb = skb; self->conn_skb = skb;
irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
...@@ -547,8 +548,6 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -547,8 +548,6 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n", IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel); __FUNCTION__, irlmp_event[event], self->slsap_sel);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
return ret; return ret;
...@@ -606,8 +605,6 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -606,8 +605,6 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel); __FUNCTION__, irlmp_event[event], self->slsap_sel);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
return ret; return ret;
...@@ -622,6 +619,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -622,6 +619,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct sk_buff *tx_skb;
int ret = 0; int ret = 0;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
...@@ -647,10 +645,12 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -647,10 +645,12 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __FUNCTION__); IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __FUNCTION__);
irlmp_next_lsap_state(self, LSAP_CONNECT); irlmp_next_lsap_state(self, LSAP_CONNECT);
skb = self->conn_skb; tx_skb = self->conn_skb;
self->conn_skb = NULL; self->conn_skb = NULL;
irlmp_connect_indication(self, skb); irlmp_connect_indication(self, tx_skb);
/* Drop reference count - see irlmp_connect_indication(). */
dev_kfree_skb(tx_skb);
break; break;
case LM_WATCHDOG_TIMEOUT: case LM_WATCHDOG_TIMEOUT:
/* Will happen in some rare cases because of a race condition. /* Will happen in some rare cases because of a race condition.
...@@ -668,8 +668,6 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -668,8 +668,6 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel); __FUNCTION__, irlmp_event[event], self->slsap_sel);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
return ret; return ret;
...@@ -759,8 +757,6 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -759,8 +757,6 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel); __FUNCTION__, irlmp_event[event], self->slsap_sel);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
return ret; return ret;
...@@ -832,8 +828,6 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -832,8 +828,6 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel); __FUNCTION__, irlmp_event[event], self->slsap_sel);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
return ret; return ret;
...@@ -850,6 +844,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -850,6 +844,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct sk_buff *tx_skb;
LM_REASON reason; LM_REASON reason;
int ret = 0; int ret = 0;
...@@ -862,11 +857,13 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -862,11 +857,13 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
case LM_LAP_CONNECT_CONFIRM: case LM_LAP_CONNECT_CONFIRM:
ASSERT(self->conn_skb != NULL, return -1;); ASSERT(self->conn_skb != NULL, return -1;);
skb = self->conn_skb; tx_skb = self->conn_skb;
self->conn_skb = NULL; self->conn_skb = NULL;
irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
self->slsap_sel, CONNECT_CMD, skb); self->slsap_sel, CONNECT_CMD, tx_skb);
/* Drop reference count - see irlap_data_request(). */
dev_kfree_skb(tx_skb);
irlmp_next_lsap_state(self, LSAP_SETUP); irlmp_next_lsap_state(self, LSAP_SETUP);
break; break;
...@@ -891,8 +888,6 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, ...@@ -891,8 +888,6 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
default: default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel); __FUNCTION__, irlmp_event[event], self->slsap_sel);
if (skb)
dev_kfree_skb(skb);
break; break;
} }
return ret; return ret;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no> * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -144,7 +144,6 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, ...@@ -144,7 +144,6 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
} else { } else {
IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__); IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__);
} }
dev_kfree_skb(skb);
return; return;
} }
...@@ -168,16 +167,13 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, ...@@ -168,16 +167,13 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
break; break;
case ACCESSMODE_CMD: case ACCESSMODE_CMD:
IRDA_DEBUG(0, "Access mode cmd not implemented!\n"); IRDA_DEBUG(0, "Access mode cmd not implemented!\n");
dev_kfree_skb(skb);
break; break;
case ACCESSMODE_CNF: case ACCESSMODE_CNF:
IRDA_DEBUG(0, "Access mode cnf not implemented!\n"); IRDA_DEBUG(0, "Access mode cnf not implemented!\n");
dev_kfree_skb(skb);
break; break;
default: default:
IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n", IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n",
__FUNCTION__, fp[2]); __FUNCTION__, fp[2]);
dev_kfree_skb(skb);
break; break;
} }
} else if (unreliable) { } else if (unreliable) {
...@@ -230,16 +226,12 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) ...@@ -230,16 +226,12 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
if (pid & 0x80) { if (pid & 0x80) {
IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", IRDA_DEBUG(0, "%s(), extension in PID not supp!\n",
__FUNCTION__); __FUNCTION__);
dev_kfree_skb(skb);
return; return;
} }
/* Check if frame is addressed to the connectionless LSAP */ /* Check if frame is addressed to the connectionless LSAP */
if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) { if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__);
dev_kfree_skb(skb);
return; return;
} }
...@@ -264,7 +256,6 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) ...@@ -264,7 +256,6 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
irlmp_connless_data_indication(lsap, skb); irlmp_connless_data_indication(lsap, skb);
else { else {
IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__);
dev_kfree_skb(skb);
} }
} }
#endif /* CONFIG_IRDA_ULTRA */ #endif /* CONFIG_IRDA_ULTRA */
...@@ -278,7 +269,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) ...@@ -278,7 +269,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
void irlmp_link_disconnect_indication(struct lap_cb *lap, void irlmp_link_disconnect_indication(struct lap_cb *lap,
struct irlap_cb *irlap, struct irlap_cb *irlap,
LAP_REASON reason, LAP_REASON reason,
struct sk_buff *userdata) struct sk_buff *skb)
{ {
IRDA_DEBUG(2, "%s()\n", __FUNCTION__); IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
...@@ -288,9 +279,7 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap, ...@@ -288,9 +279,7 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap,
lap->reason = reason; lap->reason = reason;
lap->daddr = DEV_ADDR_ANY; lap->daddr = DEV_ADDR_ANY;
/* FIXME: must do something with the userdata if any */ /* FIXME: must do something with the skb if any */
if (userdata)
dev_kfree_skb(userdata);
/* /*
* Inform station state machine * Inform station state machine
...@@ -327,7 +316,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, ...@@ -327,7 +316,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr,
* *
*/ */
void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
struct sk_buff *userdata) struct sk_buff *skb)
{ {
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
...@@ -335,9 +324,7 @@ void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, ...@@ -335,9 +324,7 @@ void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
ASSERT(self->magic == LMP_LAP_MAGIC, return;); ASSERT(self->magic == LMP_LAP_MAGIC, return;);
ASSERT(qos != NULL, return;); ASSERT(qos != NULL, return;);
/* Don't need use the userdata for now */ /* Don't need use the skb for now */
if (userdata)
dev_kfree_skb(userdata);
/* Copy QoS settings for this session */ /* Copy QoS settings for this session */
self->qos = qos; self->qos = qos;
......
...@@ -229,6 +229,11 @@ ...@@ -229,6 +229,11 @@
* v14 - 20.2.03 - Jean II * v14 - 20.2.03 - Jean II
* o Add discovery hint bits in the control channel. * o Add discovery hint bits in the control channel.
* o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner * o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner
*
* v15 - 7.4.03 - Jean II
* o Replace spin_lock_irqsave() with spin_lock_bh() so that we can
* use ppp_unit_number(). It's probably also better overall...
* o Disable call to ppp_unregister_channel(), because we can't do it.
*/ */
/***************************** INCLUDES *****************************/ /***************************** INCLUDES *****************************/
...@@ -276,6 +281,7 @@ ...@@ -276,6 +281,7 @@
#undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */ #undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */
#undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */ #undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */
#undef PASS_CONNECT_PACKETS /* Not needed ? Safe */ #undef PASS_CONNECT_PACKETS /* Not needed ? Safe */
#undef MISSING_PPP_API /* Stuff I wish I could do */
/* PPP side of the business */ /* PPP side of the business */
#define BLOCK_WHEN_CONNECT /* Block packets when connecting */ #define BLOCK_WHEN_CONNECT /* Block packets when connecting */
......
...@@ -31,7 +31,6 @@ irnet_post_event(irnet_socket * ap, ...@@ -31,7 +31,6 @@ irnet_post_event(irnet_socket * ap,
char * name, char * name,
__u16 hints) __u16 hints)
{ {
unsigned long flags; /* For spinlock */
int index; /* In the log */ int index; /* In the log */
DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n", DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n",
...@@ -41,7 +40,7 @@ irnet_post_event(irnet_socket * ap, ...@@ -41,7 +40,7 @@ irnet_post_event(irnet_socket * ap,
* Note : as we are the only event producer, we only need to exclude * Note : as we are the only event producer, we only need to exclude
* ourself when touching the log, which is nice and easy. * ourself when touching the log, which is nice and easy.
*/ */
spin_lock_irqsave(&irnet_events.spinlock, flags); spin_lock_bh(&irnet_events.spinlock);
/* Copy the event in the log */ /* Copy the event in the log */
index = irnet_events.index; index = irnet_events.index;
...@@ -69,7 +68,7 @@ irnet_post_event(irnet_socket * ap, ...@@ -69,7 +68,7 @@ irnet_post_event(irnet_socket * ap,
DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index); DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index);
/* Spin lock end */ /* Spin lock end */
spin_unlock_irqrestore(&irnet_events.spinlock, flags); spin_unlock_bh(&irnet_events.spinlock);
/* Now : wake up everybody waiting for events... */ /* Now : wake up everybody waiting for events... */
wake_up_interruptible_all(&irnet_events.rwait); wake_up_interruptible_all(&irnet_events.rwait);
...@@ -536,10 +535,9 @@ irda_irnet_connect(irnet_socket * self) ...@@ -536,10 +535,9 @@ irda_irnet_connect(irnet_socket * self)
* Can't re-insert (MUST remove first) so check for that... */ * Can't re-insert (MUST remove first) so check for that... */
if((irnet_server.running) && (self->q.q_next == NULL)) if((irnet_server.running) && (self->q.q_next == NULL))
{ {
unsigned long flags; spin_lock_bh(&irnet_server.spinlock);
spin_lock_irqsave(&irnet_server.spinlock, flags);
hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname); hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname);
spin_unlock_irqrestore(&irnet_server.spinlock, flags); spin_unlock_bh(&irnet_server.spinlock);
DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname); DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname);
} }
...@@ -596,12 +594,11 @@ irda_irnet_destroy(irnet_socket * self) ...@@ -596,12 +594,11 @@ irda_irnet_destroy(irnet_socket * self)
if((irnet_server.running) && (self->q.q_next != NULL)) if((irnet_server.running) && (self->q.q_next != NULL))
{ {
struct irnet_socket * entry; struct irnet_socket * entry;
unsigned long flags;
DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n"); DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n");
spin_lock_irqsave(&irnet_server.spinlock, flags); spin_lock_bh(&irnet_server.spinlock);
entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self); entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self);
self->q.q_next = NULL; self->q.q_next = NULL;
spin_unlock_irqrestore(&irnet_server.spinlock, flags); spin_unlock_bh(&irnet_server.spinlock);
DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n"); DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n");
} }
...@@ -723,7 +720,6 @@ static inline irnet_socket * ...@@ -723,7 +720,6 @@ static inline irnet_socket *
irnet_find_socket(irnet_socket * self) irnet_find_socket(irnet_socket * self)
{ {
irnet_socket * new = (irnet_socket *) NULL; irnet_socket * new = (irnet_socket *) NULL;
unsigned long flags;
int err; int err;
DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);
...@@ -736,7 +732,7 @@ irnet_find_socket(irnet_socket * self) ...@@ -736,7 +732,7 @@ irnet_find_socket(irnet_socket * self)
err = irnet_daddr_to_dname(self); err = irnet_daddr_to_dname(self);
/* Protect access to the instance list */ /* Protect access to the instance list */
spin_lock_irqsave(&irnet_server.spinlock, flags); spin_lock_bh(&irnet_server.spinlock);
/* So now, try to get an socket having specifically /* So now, try to get an socket having specifically
* requested that nickname */ * requested that nickname */
...@@ -790,7 +786,7 @@ irnet_find_socket(irnet_socket * self) ...@@ -790,7 +786,7 @@ irnet_find_socket(irnet_socket * self)
} }
/* Spin lock end */ /* Spin lock end */
spin_unlock_irqrestore(&irnet_server.spinlock, flags); spin_unlock_bh(&irnet_server.spinlock);
DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new); DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new);
return new; return new;
...@@ -1135,10 +1131,15 @@ irnet_disconnect_indication(void * instance, ...@@ -1135,10 +1131,15 @@ irnet_disconnect_indication(void * instance,
{ {
if(test_open) if(test_open)
{ {
#ifdef MISSING_PPP_API
/* ppp_unregister_channel() wants a user context, which we
* are guaranteed to NOT have here. What are we supposed
* to do here ? Jean II */
/* If we were connected, cleanup & close the PPP channel, /* If we were connected, cleanup & close the PPP channel,
* which will kill pppd (hangup) and the rest */ * which will kill pppd (hangup) and the rest */
ppp_unregister_channel(&self->chan); ppp_unregister_channel(&self->chan);
self->ppp_open = 0; self->ppp_open = 0;
#endif
} }
else else
{ {
...@@ -1711,7 +1712,6 @@ irnet_proc_read(char * buf, ...@@ -1711,7 +1712,6 @@ irnet_proc_read(char * buf,
{ {
irnet_socket * self; irnet_socket * self;
char * state; char * state;
unsigned long flags;
int i = 0; int i = 0;
len = 0; len = 0;
...@@ -1728,7 +1728,7 @@ irnet_proc_read(char * buf, ...@@ -1728,7 +1728,7 @@ irnet_proc_read(char * buf,
return len; return len;
/* Protect access to the instance list */ /* Protect access to the instance list */
spin_lock_irqsave(&irnet_server.spinlock, flags); spin_lock_bh(&irnet_server.spinlock);
/* Get the sockets one by one... */ /* Get the sockets one by one... */
self = (irnet_socket *) hashbin_get_first(irnet_server.list); self = (irnet_socket *) hashbin_get_first(irnet_server.list);
...@@ -1780,7 +1780,7 @@ irnet_proc_read(char * buf, ...@@ -1780,7 +1780,7 @@ irnet_proc_read(char * buf,
} }
/* Spin lock end */ /* Spin lock end */
spin_unlock_irqrestore(&irnet_server.spinlock, flags); spin_unlock_bh(&irnet_server.spinlock);
return len; return len;
} }
......
...@@ -927,7 +927,7 @@ ppp_irnet_send(struct ppp_channel * chan, ...@@ -927,7 +927,7 @@ ppp_irnet_send(struct ppp_channel * chan,
* Jean II * Jean II
*/ */
DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret); DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret);
dev_kfree_skb(skb); /* irttp_data_request already free the packet */
} }
DEXIT(PPP_TRACE, "\n"); DEXIT(PPP_TRACE, "\n");
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -259,11 +259,17 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self) ...@@ -259,11 +259,17 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
dev_kfree_skb(frag); dev_kfree_skb(frag);
} }
IRDA_DEBUG(2, "%s(), frame len=%d\n", __FUNCTION__, n);
IRDA_DEBUG(2, "%s(), rx_sdu_size=%d\n", __FUNCTION__, IRDA_DEBUG(2,
self->rx_sdu_size); "%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",
ASSERT(n <= self->rx_sdu_size, return NULL;); __FUNCTION__, n, self->rx_sdu_size, self->rx_max_sdu_size);
/* Note : irttp_run_rx_queue() calculate self->rx_sdu_size
* by summing the size of all fragments, so we should always
* have n == self->rx_sdu_size, except in cases where we
* droped the last fragment (when self->rx_sdu_size exceed
* self->rx_max_sdu_size), where n < self->rx_sdu_size.
* Jean II */
ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;);
/* Set the new length */ /* Set the new length */
skb_trim(skb, n); skb_trim(skb, n);
...@@ -537,19 +543,23 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) ...@@ -537,19 +543,23 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
if ((skb->len == 0) || (!self->connected)) { if ((skb->len == 0) || (!self->connected)) {
IRDA_DEBUG(1, "%s(), No data, or not connected\n", IRDA_DEBUG(1, "%s(), No data, or not connected\n",
__FUNCTION__); __FUNCTION__);
return -1; goto err;
} }
if (skb->len > self->max_seg_size) { if (skb->len > self->max_seg_size) {
IRDA_DEBUG(1, "%s(), UData is to large for IrLAP!\n", IRDA_DEBUG(1, "%s(), UData is to large for IrLAP!\n",
__FUNCTION__); __FUNCTION__);
return -1; goto err;
} }
irlmp_udata_request(self->lsap, skb); irlmp_udata_request(self->lsap, skb);
self->stats.tx_packets++; self->stats.tx_packets++;
return 0; return 0;
err:
dev_kfree_skb(skb);
return -1;
} }
/* /*
...@@ -561,6 +571,7 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) ...@@ -561,6 +571,7 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
{ {
__u8 *frame; __u8 *frame;
int ret;
ASSERT(self != NULL, return -1;); ASSERT(self != NULL, return -1;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
...@@ -572,7 +583,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) ...@@ -572,7 +583,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
/* Check that nothing bad happens */ /* Check that nothing bad happens */
if ((skb->len == 0) || (!self->connected)) { if ((skb->len == 0) || (!self->connected)) {
WARNING("%s: No data, or not connected\n", __FUNCTION__); WARNING("%s: No data, or not connected\n", __FUNCTION__);
return -ENOTCONN; ret = -ENOTCONN;
goto err;
} }
/* /*
...@@ -582,7 +594,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) ...@@ -582,7 +594,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) { if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
ERROR("%s: SAR disabled, and data is to large for IrLAP!\n", ERROR("%s: SAR disabled, and data is to large for IrLAP!\n",
__FUNCTION__); __FUNCTION__);
return -EMSGSIZE; ret = -EMSGSIZE;
goto err;
} }
/* /*
...@@ -595,7 +608,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) ...@@ -595,7 +608,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
{ {
ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n", ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
__FUNCTION__); __FUNCTION__);
return -EMSGSIZE; ret = -EMSGSIZE;
goto err;
} }
/* /*
* Check if transmit queue is full * Check if transmit queue is full
...@@ -607,8 +621,9 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) ...@@ -607,8 +621,9 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
irttp_run_tx_queue(self); irttp_run_tx_queue(self);
/* Drop packet. This error code should trigger the caller /* Drop packet. This error code should trigger the caller
* to requeue the packet in the client code - Jean II */ * to resend the data in the client code - Jean II */
return -ENOBUFS; ret = -ENOBUFS;
goto err;
} }
/* Queue frame, or queue frame segments */ /* Queue frame, or queue frame segments */
...@@ -651,6 +666,10 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) ...@@ -651,6 +666,10 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
irttp_run_tx_queue(self); irttp_run_tx_queue(self);
return 0; return 0;
err:
dev_kfree_skb(skb);
return ret;
} }
/* /*
...@@ -822,6 +841,7 @@ static int irttp_udata_indication(void *instance, void *sap, ...@@ -822,6 +841,7 @@ static int irttp_udata_indication(void *instance, void *sap,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct tsap_cb *self; struct tsap_cb *self;
int err;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
...@@ -831,14 +851,19 @@ static int irttp_udata_indication(void *instance, void *sap, ...@@ -831,14 +851,19 @@ static int irttp_udata_indication(void *instance, void *sap,
ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
ASSERT(skb != NULL, return -1;); ASSERT(skb != NULL, return -1;);
/* Just pass data to layer above */
if (self->notify.udata_indication)
self->notify.udata_indication(self->notify.instance, self,skb);
else
dev_kfree_skb(skb);
self->stats.rx_packets++; self->stats.rx_packets++;
/* Just pass data to layer above */
if (self->notify.udata_indication) {
err = self->notify.udata_indication(self->notify.instance,
self,skb);
/* Same comment as in irttp_do_data_indication() */
if (err != -ENOMEM)
return 0;
}
/* Either no handler, or -ENOMEM */
dev_kfree_skb(skb);
return 0; return 0;
} }
...@@ -1040,7 +1065,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, ...@@ -1040,7 +1065,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
struct qos_info *qos, __u32 max_sdu_size, struct qos_info *qos, __u32 max_sdu_size,
struct sk_buff *userdata) struct sk_buff *userdata)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
__u8 *frame; __u8 *frame;
__u8 n; __u8 n;
...@@ -1049,19 +1074,22 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, ...@@ -1049,19 +1074,22 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
ASSERT(self != NULL, return -EBADR;); ASSERT(self != NULL, return -EBADR;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;); ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
if (self->connected) if (self->connected) {
if(userdata)
dev_kfree_skb(userdata);
return -EISCONN; return -EISCONN;
}
/* Any userdata supplied? */ /* Any userdata supplied? */
if (userdata == NULL) { if (userdata == NULL) {
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return -ENOMEM; return -ENOMEM;
/* Reserve space for MUX_CONTROL and LAP header */ /* Reserve space for MUX_CONTROL and LAP header */
skb_reserve(skb, TTP_MAX_HEADER); skb_reserve(tx_skb, TTP_MAX_HEADER);
} else { } else {
skb = userdata; tx_skb = userdata;
/* /*
* Check that the client has reserved enough space for * Check that the client has reserved enough space for
* headers * headers
...@@ -1094,11 +1122,11 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, ...@@ -1094,11 +1122,11 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
/* SAR enabled? */ /* SAR enabled? */
if (max_sdu_size > 0) { if (max_sdu_size > 0) {
ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
return -1;); return -1;);
/* Insert SAR parameters */ /* Insert SAR parameters */
frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER); frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
frame[0] = TTP_PARAMETERS | n; frame[0] = TTP_PARAMETERS | n;
frame[1] = 0x04; /* Length */ frame[1] = 0x04; /* Length */
...@@ -1109,7 +1137,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, ...@@ -1109,7 +1137,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
(__u16 *)(frame+4)); (__u16 *)(frame+4));
} else { } else {
/* Insert plain TTP header */ /* Insert plain TTP header */
frame = skb_push(skb, TTP_HEADER); frame = skb_push(tx_skb, TTP_HEADER);
/* Insert initial credit in frame */ /* Insert initial credit in frame */
frame[0] = n & 0x7f; frame[0] = n & 0x7f;
...@@ -1117,7 +1145,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, ...@@ -1117,7 +1145,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
/* Connect with IrLMP. No QoS parameters for now */ /* Connect with IrLMP. No QoS parameters for now */
return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos,
skb); tx_skb);
} }
/* /*
...@@ -1201,7 +1229,8 @@ static void irttp_connect_confirm(void *instance, void *sap, ...@@ -1201,7 +1229,8 @@ static void irttp_connect_confirm(void *instance, void *sap,
self->notify.connect_confirm(self->notify.instance, self, qos, self->notify.connect_confirm(self->notify.instance, self, qos,
self->tx_max_sdu_size, self->tx_max_sdu_size,
self->max_header_size, skb); self->max_header_size, skb);
} } else
dev_kfree_skb(skb);
} }
/* /*
...@@ -1286,7 +1315,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos, ...@@ -1286,7 +1315,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
struct sk_buff *userdata) struct sk_buff *userdata)
{ {
struct sk_buff *skb; struct sk_buff *tx_skb;
__u8 *frame; __u8 *frame;
int ret; int ret;
__u8 n; __u8 n;
...@@ -1299,19 +1328,19 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, ...@@ -1299,19 +1328,19 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
/* Any userdata supplied? */ /* Any userdata supplied? */
if (userdata == NULL) { if (userdata == NULL) {
skb = dev_alloc_skb(64); tx_skb = dev_alloc_skb(64);
if (!skb) if (!tx_skb)
return -ENOMEM; return -ENOMEM;
/* Reserve space for MUX_CONTROL and LAP header */ /* Reserve space for MUX_CONTROL and LAP header */
skb_reserve(skb, TTP_MAX_HEADER); skb_reserve(tx_skb, TTP_MAX_HEADER);
} else { } else {
skb = userdata; tx_skb = userdata;
/* /*
* Check that the client has reserved enough space for * Check that the client has reserved enough space for
* headers * headers
*/ */
ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return -1;); ASSERT(skb_headroom(tx_skb) >= TTP_MAX_HEADER, return -1;);
} }
self->avail_credit = 0; self->avail_credit = 0;
...@@ -1333,11 +1362,11 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, ...@@ -1333,11 +1362,11 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
/* SAR enabled? */ /* SAR enabled? */
if (max_sdu_size > 0) { if (max_sdu_size > 0) {
ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER), ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER),
return -1;); return -1;);
/* Insert TTP header with SAR parameters */ /* Insert TTP header with SAR parameters */
frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER); frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
frame[0] = TTP_PARAMETERS | n; frame[0] = TTP_PARAMETERS | n;
frame[1] = 0x04; /* Length */ frame[1] = 0x04; /* Length */
...@@ -1352,12 +1381,12 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, ...@@ -1352,12 +1381,12 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
(__u16 *)(frame+4)); (__u16 *)(frame+4));
} else { } else {
/* Insert TTP header */ /* Insert TTP header */
frame = skb_push(skb, TTP_HEADER); frame = skb_push(tx_skb, TTP_HEADER);
frame[0] = n & 0x7f; frame[0] = n & 0x7f;
} }
ret = irlmp_connect_response(self->lsap, skb); ret = irlmp_connect_response(self->lsap, tx_skb);
return ret; return ret;
} }
...@@ -1423,7 +1452,6 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) ...@@ -1423,7 +1452,6 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
int priority) int priority)
{ {
struct sk_buff *skb;
int ret; int ret;
ASSERT(self != NULL, return -1;); ASSERT(self != NULL, return -1;);
...@@ -1488,16 +1516,17 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, ...@@ -1488,16 +1516,17 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
self->connected = FALSE; self->connected = FALSE;
if (!userdata) { if (!userdata) {
skb = dev_alloc_skb(64); struct sk_buff *tx_skb;
if (!skb) tx_skb = dev_alloc_skb(64);
if (!tx_skb)
return -ENOMEM; return -ENOMEM;
/* /*
* Reserve space for MUX and LAP header * Reserve space for MUX and LAP header
*/ */
skb_reserve(skb, TTP_MAX_HEADER); skb_reserve(tx_skb, TTP_MAX_HEADER);
userdata = skb; userdata = tx_skb;
} }
ret = irlmp_disconnect_request(self->lsap, userdata); ret = irlmp_disconnect_request(self->lsap, userdata);
...@@ -1556,7 +1585,7 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason, ...@@ -1556,7 +1585,7 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason,
/* /*
* Function irttp_do_data_indication (self, skb) * Function irttp_do_data_indication (self, skb)
* *
* Try to deliver reassebled skb to layer above, and requeue it if that * Try to deliver reassembled skb to layer above, and requeue it if that
* for some reason should fail. We mark rx sdu as busy to apply back * for some reason should fail. We mark rx sdu as busy to apply back
* pressure is necessary. * pressure is necessary.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment