patch-2.2.15 linux/drivers/net/irda/irport.c
Next file: linux/drivers/net/irda/irtty.c
Previous file: linux/drivers/net/irda/girbil.c
Back to the patch index
Back to the overall index
- Lines: 1132
- Date:
Fri Apr 21 12:46:17 2000
- Orig file:
v2.2.14/drivers/net/irda/irport.c
- Orig date:
Sat Aug 14 02:26:48 1999
diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
@@ -6,11 +6,11 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 3 13:49:59 1997
- * Modified at: Tue Jun 1 10:02:42 1999
+ * Modified at: Sat Mar 11 07:41:54 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c by Linus Torvalds
*
- * Copyright (c) 1997, 1998, 1999 Dag Brattli, All Rights Reserved.
+ * 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
@@ -47,11 +47,12 @@
#include <linux/serial_reg.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <asm/spinlock.h>
+#include <linux/rtnetlink.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
-#include <asm/spinlock.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
@@ -69,24 +70,33 @@
static unsigned int qos_mtt_bits = 0x03;
-static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL};
+static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL};
static char *driver_name = "irport";
-static int irport_open(int i, unsigned int iobase, unsigned int irq);
-static int irport_close(struct irda_device *idev);
-
-static void irport_write_wakeup(struct irda_device *idev);
+static void irport_write_wakeup(struct irport_cb *self);
static int irport_write(int iobase, int fifo_size, __u8 *buf, int len);
-static void irport_receive(struct irda_device *idev);
+static void irport_receive(struct irport_cb *self);
static int irport_net_init(struct device *dev);
-static int irport_net_open(struct device *dev);
-static int irport_net_close(struct device *dev);
-static int irport_is_receiving(struct irda_device *idev);
-static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
-static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len);
+static int irport_net_ioctl(struct device *dev, struct ifreq *rq,
+ int cmd);
+static int irport_is_receiving(struct irport_cb *self);
+static int irport_set_dtr_rts(struct device *dev, int dtr, int rts);
+static int irport_raw_write(struct device *dev, __u8 *buf, int len);
+static struct net_device_stats *irport_net_get_stats(struct device *dev);
+static int irport_change_speed_complete(struct irda_task *task);
+
+EXPORT_SYMBOL(irport_open);
+EXPORT_SYMBOL(irport_close);
+EXPORT_SYMBOL(irport_start);
+EXPORT_SYMBOL(irport_stop);
+EXPORT_SYMBOL(irport_interrupt);
+EXPORT_SYMBOL(irport_hard_xmit);
+EXPORT_SYMBOL(irport_change_speed);
+EXPORT_SYMBOL(irport_net_open);
+EXPORT_SYMBOL(irport_net_close);
-__initfunc(int irport_init(void))
+int __init irport_init(void)
{
int i;
@@ -94,7 +104,7 @@
int ioaddr = io[i];
if (check_region(ioaddr, IO_EXTENT))
continue;
- if (irport_open(i, io[i], irq[i]) == 0)
+ if (irport_open(i, io[i], irq[i]) != NULL)
return 0;
}
/*
@@ -114,7 +124,7 @@
{
int i;
- DEBUG( 4, __FUNCTION__ "()\n");
+ IRDA_DEBUG( 4, __FUNCTION__ "()\n");
for (i=0; i < 4; i++) {
if (dev_self[i])
@@ -123,110 +133,170 @@
}
#endif /* MODULE */
-static int irport_open(int i, unsigned int iobase, unsigned int irq)
+struct irport_cb *
+irport_open(int i, unsigned int iobase, unsigned int irq)
{
- struct irda_device *idev;
+ struct device *dev;
+ struct irport_cb *self;
int ret;
+ int err;
- DEBUG( 0, __FUNCTION__ "()\n");
-
-/* if (irport_probe(iobase, irq) == -1) */
-/* return -1; */
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
/*
* Allocate new instance of the driver
*/
- idev = kmalloc(sizeof(struct irda_device), GFP_KERNEL);
- if (idev == NULL) {
- printk( KERN_ERR "IrDA: Can't allocate memory for "
- "IrDA control block!\n");
- return -ENOMEM;
+ self = kmalloc(sizeof(struct irport_cb), GFP_KERNEL);
+ if (!self) {
+ ERROR(__FUNCTION__ "(), can't allocate memory for "
+ "control block!\n");
+ return NULL;
}
- memset(idev, 0, sizeof(struct irda_device));
-
+ memset(self, 0, sizeof(struct irport_cb));
+ spin_lock_init(&self->lock);
+
/* Need to store self somewhere */
- dev_self[i] = idev;
+ dev_self[i] = self;
+ self->priv = self;
+ self->index = i;
/* Initialize IO */
- idev->io.iobase2 = iobase;
- idev->io.irq2 = irq;
- idev->io.io_ext = IO_EXTENT;
- idev->io.fifo_size = 16;
-
- idev->netdev.base_addr = iobase;
- idev->netdev.irq = irq;
+ self->io.sir_base = iobase;
+ self->io.sir_ext = IO_EXTENT;
+ self->io.irq = irq;
+ self->io.fifo_size = 16;
/* Lock the port that we need */
- ret = check_region(idev->io.iobase2, idev->io.io_ext);
+ ret = check_region(self->io.sir_base, self->io.sir_ext);
if (ret < 0) {
- DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
- idev->io.iobase2);
- /* irport_cleanup(self->idev); */
- return -ENODEV;
+ IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+ self->io.sir_base);
+ return NULL;
}
- request_region(idev->io.iobase2, idev->io.io_ext, idev->name);
+ request_region(self->io.sir_base, self->io.sir_ext, driver_name);
/* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&idev->qos);
+ irda_init_max_qos_capabilies(&self->qos);
- idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+ self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
IR_115200;
- idev->qos.min_turn_time.bits = qos_mtt_bits;
- irda_qos_bits_to_value(&idev->qos);
+ self->qos.min_turn_time.bits = qos_mtt_bits;
+ irda_qos_bits_to_value(&self->qos);
- idev->flags = IFF_SIR|IFF_PIO;
+ self->flags = IFF_SIR|IFF_PIO;
- /* Specify which buffer allocation policy we need */
- idev->rx_buff.flags = GFP_KERNEL;
- idev->tx_buff.flags = GFP_KERNEL;
-
- idev->rx_buff.truesize = 4000;
- idev->tx_buff.truesize = 4000;
-
- /* Initialize callbacks */
- idev->change_speed = irport_change_speed;
- idev->wait_until_sent = irport_wait_until_sent;
- idev->is_receiving = irport_is_receiving;
- idev->set_dtr_rts = irport_set_dtr_rts;
- idev->raw_write = irport_raw_write;
+ /* Specify how much memory we want */
+ self->rx_buff.truesize = 4000;
+ self->tx_buff.truesize = 4000;
+
+ /* 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) {
+ self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize,
+ GFP_KERNEL);
+ if (self->tx_buff.head == NULL) {
+ kfree(self->rx_buff.head);
+ return NULL;
+ }
+ 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;
+ self->mode = IRDA_IRLAP;
+
+ if (!(dev = dev_alloc("irda%d", &err))) {
+ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+ return NULL;
+ }
+ /* dev_alloc doesn't clear the struct */
+ memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct device)-sizeof(char*));
+
+ self->netdev = dev;
+
+ /* May be overridden by piggyback drivers */
+ dev->priv = (void *) self;
+ self->interrupt = irport_interrupt;
+ self->change_speed = irport_change_speed;
/* Override the network functions we need to use */
- idev->netdev.init = irport_net_init;
- idev->netdev.hard_start_xmit = irport_hard_xmit;
- idev->netdev.open = irport_net_open;
- idev->netdev.stop = irport_net_close;
-
- /* Open the IrDA device */
- irda_device_open(idev, driver_name, NULL);
-
- return 0;
-}
-
-static int irport_close(struct irda_device *idev)
-{
- ASSERT(idev != NULL, return -1;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+ dev->init = irport_net_init;
+ dev->hard_start_xmit = irport_hard_xmit;
+ dev->open = irport_net_open;
+ dev->stop = irport_net_close;
+ dev->get_stats = irport_net_get_stats;
+ dev->do_ioctl = irport_net_ioctl;
+
+ /* Make ifconfig display some details */
+ dev->base_addr = iobase;
+ dev->irq = irq;
+
+ rtnl_lock();
+ err = register_netdevice(dev);
+ rtnl_unlock();
+ if (err) {
+ ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+ return NULL;
+ }
+ MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+ return self;
+}
+
+int irport_close(struct irport_cb *self)
+{
+ ASSERT(self != NULL, return -1;);
+
+ /* We are not using any dongle anymore! */
+ if (self->dongle)
+ irda_device_dongle_cleanup(self->dongle);
+ self->dongle = NULL;
+
+ /* Remove netdevice */
+ if (self->netdev) {
+ rtnl_lock();
+ unregister_netdevice(self->netdev);
+ rtnl_unlock();
+ /* Must free the old-style 2.2.x device */
+ kfree(self->netdev);
+ }
/* Release the IO-port that this driver is using */
- DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n",
- idev->io.iobase2);
- release_region(idev->io.iobase2, idev->io.io_ext);
-
- irda_device_close(idev);
-
- kfree(idev);
-
+ IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n",
+ 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);
+
+ /* Remove ourselves */
+ dev_self[self->index] = NULL;
+ kfree(self);
+
return 0;
}
-void irport_start(struct irda_device *idev, int iobase)
+void irport_start(struct irport_cb *self)
{
unsigned long flags;
+ int iobase;
+
+ iobase = self->io.sir_base;
- spin_lock_irqsave(&idev->lock, flags);
+ spin_lock_irqsave(&self->lock, flags);
- irport_stop(idev, iobase);
+ irport_stop(self);
/* Initialize UART */
outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */
@@ -235,14 +305,17 @@
/* Turn on interrups */
outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
- spin_unlock_irqrestore(&idev->lock, flags);
+ spin_unlock_irqrestore(&self->lock, flags);
}
-void irport_stop(struct irda_device *idev, int iobase)
+void irport_stop(struct irport_cb *self)
{
unsigned long flags;
+ int iobase;
+
+ iobase = self->io.sir_base;
- spin_lock_irqsave(&idev->lock, flags);
+ spin_lock_irqsave(&self->lock, flags);
/* Reset UART */
outb(0, iobase+UART_MCR);
@@ -250,7 +323,7 @@
/* Turn off interrupts */
outb(0, iobase+UART_IER);
- spin_unlock_irqrestore(&idev->lock, flags);
+ spin_unlock_irqrestore(&self->lock, flags);
}
/*
@@ -261,36 +334,36 @@
*/
int irport_probe(int iobase)
{
- DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
+ IRDA_DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
return 0;
}
/*
- * Function irport_change_speed (idev, speed)
+ * Function irport_change_speed (self, speed)
*
* Set speed of IrDA port to specified baudrate
*
*/
-void irport_change_speed(struct irda_device *idev, int speed)
+void irport_change_speed(void *priv, __u32 speed)
{
+ struct irport_cb *self = (struct irport_cb *) priv;
unsigned long flags;
int iobase;
int fcr; /* FIFO control reg */
int lcr; /* Line control reg */
int divisor;
- DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
+ IRDA_DEBUG(2, __FUNCTION__ "(), Setting speed to: %d\n", speed);
- ASSERT(idev != NULL, return;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+ ASSERT(self != NULL, return;);
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
/* Update accounting for new speed */
- idev->io.baudrate = speed;
+ self->io.speed = speed;
- spin_lock_irqsave(&idev->lock, flags);
+ spin_lock_irqsave(&self->lock, flags);
/* Turn off interrupts */
outb(0, iobase+UART_IER);
@@ -304,7 +377,7 @@
* 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 (idev->io.baudrate < 38400)
+ if (self->io.speed < 38400)
fcr |= UART_FCR_TRIGGER_1;
else
fcr |= UART_FCR_TRIGGER_14;
@@ -319,9 +392,82 @@
outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
/* Turn on interrups */
- 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);
- spin_unlock_irqrestore(&idev->lock, flags);
+ spin_unlock_irqrestore(&self->lock, flags);
+}
+
+/*
+ * Function __irport_change_speed (instance, state, param)
+ *
+ * State machine for changing speed of the device. We do it this way since
+ * we cannot use schedule_timeout() when we are in interrupt context
+ */
+int __irport_change_speed(struct irda_task *task)
+{
+ struct irport_cb *self;
+ __u32 speed = (__u32) task->param;
+ int ret = 0;
+
+ IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies);
+
+ self = (struct irport_cb *) task->instance;
+
+ ASSERT(self != NULL, return -1;);
+
+ switch (task->state) {
+ case IRDA_TASK_INIT:
+ case IRDA_TASK_WAIT:
+ /* Are we ready to change speed yet? */
+ if (self->tx_buff.len > 0) {
+ task->state = IRDA_TASK_WAIT;
+
+ /* Try again later */
+ ret = MSECS_TO_JIFFIES(20);
+ break;
+ }
+
+ if (self->dongle)
+ irda_task_next_state(task, IRDA_TASK_CHILD_INIT);
+ else
+ irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+ break;
+ case IRDA_TASK_CHILD_INIT:
+ /* Go to default speed */
+ self->change_speed(self->priv, 9600);
+
+ /* Change speed of dongle */
+ if (irda_task_execute(self->dongle,
+ self->dongle->issue->change_speed,
+ NULL, task, (void *) speed))
+ {
+ /* Dongle need more time to change its speed */
+ irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+ /* Give dongle 1 sec to finish */
+ ret = MSECS_TO_JIFFIES(1000);
+ } else
+ /* Child finished immediately */
+ irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+ break;
+ case IRDA_TASK_CHILD_WAIT:
+ WARNING(__FUNCTION__
+ "(), changing speed of dongle timed out!\n");
+ ret = -1;
+ break;
+ case IRDA_TASK_CHILD_DONE:
+ /* Finally we are ready to change the speed */
+ self->change_speed(self->priv, speed);
+
+ irda_task_next_state(task, IRDA_TASK_DONE);
+ break;
+ default:
+ ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+ irda_task_next_state(task, IRDA_TASK_DONE);
+ ret = -1;
+ break;
+ }
+ return ret;
}
/*
@@ -331,51 +477,63 @@
* more packets to send, we send them here.
*
*/
-static void irport_write_wakeup(struct irda_device *idev)
+static void irport_write_wakeup(struct irport_cb *self)
{
int actual = 0;
int iobase;
int fcr;
- ASSERT(idev != NULL, return;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+ ASSERT(self != NULL, return;);
- DEBUG(4, __FUNCTION__ "()\n");
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+ iobase = self->io.sir_base;
/* Finished with frame? */
- if (idev->tx_buff.len > 0) {
+ if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
- actual = irport_write(idev->io.iobase2, idev->io.fifo_size,
- idev->tx_buff.data, idev->tx_buff.len);
- idev->tx_buff.data += actual;
- idev->tx_buff.len -= actual;
+ 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 {
- iobase = idev->io.iobase2;
+
/*
* Now serial buffer is almost free & we can start
- * transmission of another packet
+ * transmission of another packet. But first we must check
+ * if we need to change the speed of the hardware
*/
- idev->netdev.tbusy = 0; /* Unlock */
- idev->stats.tx_packets++;
+ if (self->new_speed) {
+ IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
+ irda_task_execute(self, __irport_change_speed,
+ irport_change_speed_complete,
+ NULL, (void *) self->new_speed);
+ self->new_speed = 0;
+ } else {
+ self->netdev->tbusy = 0; /* Unlock */
+
+ /* Tell network layer that we want more frames */
+ mark_bh(NET_BH);
+ }
+ self->stats.tx_packets++;
/* Schedule network layer, so we can get some more frames */
mark_bh(NET_BH);
+ /*
+ * 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 (idev->io.baudrate < 38400)
+ if (self->io.speed < 38400)
fcr |= UART_FCR_TRIGGER_1;
else
fcr |= UART_FCR_TRIGGER_14;
- /*
- * Reset Rx FIFO to make sure that all reflected transmit data
- * will be discarded
- */
outb(fcr, iobase+UART_FCR);
/* Turn on receive interrupts */
- outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER);
+ outb(UART_IER_RDI, iobase+UART_IER);
}
}
@@ -391,8 +549,8 @@
/* Tx FIFO should be empty! */
if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
- return -1;
+ IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
+ return 0;
}
/* Fill FIFO with current frame */
@@ -407,6 +565,32 @@
}
/*
+ * Function irport_change_speed_complete (task)
+ *
+ * Called when the change speed operation completes
+ *
+ */
+static int irport_change_speed_complete(struct irda_task *task)
+{
+ struct irport_cb *self;
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ self = (struct irport_cb *) task->instance;
+
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->netdev != NULL, return -1;);
+
+ /* Finished changing speed, so we are not busy any longer */
+ self->netdev->tbusy = 0;
+
+ /* Signal network layer so it can try to send the frame */
+ mark_bh(NET_BH);
+
+ return 0;
+}
+
+/*
* Function irport_xmit (void)
*
* Transmits the current frame until FIFO is full, then
@@ -415,49 +599,50 @@
*/
int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
{
- struct irda_device *idev;
+ struct irport_cb *self;
unsigned long flags;
- int actual = 0;
int iobase;
+ __u32 speed;
ASSERT(dev != NULL, return 0;);
- idev = (struct irda_device *) dev->priv;
-
- ASSERT(idev != NULL, return 0;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+ self = (struct irport_cb *) dev->priv;
+ ASSERT(self != NULL, return 0;);
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
/* Lock transmit buffer */
if (irda_lock((void *) &dev->tbusy) == FALSE) {
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
+ if ((tickssofar < 5) || !dev->start)
return -EBUSY;
WARNING("%s: transmit timed out\n", dev->name);
- irport_start(idev, iobase);
- irport_change_speed(idev, idev->io.baudrate);
+ irport_start(self);
+ self->change_speed(self->priv, self->io.speed);
dev->trans_start = jiffies;
}
- spin_lock_irqsave(&idev->lock, flags);
-
+ /* Check if we need to change the speed */
+ if ((speed = irda_get_speed(skb)) != self->io.speed)
+ self->new_speed = speed;
+
+ spin_lock_irqsave(&self->lock, flags);
+
/* Init tx buffer */
- idev->tx_buff.data = idev->tx_buff.head;
+ self->tx_buff.data = self->tx_buff.head;
/* Copy skb to tx_buff while wrapping, stuffing and making CRC */
- idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data,
- idev->tx_buff.truesize);
+ self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
+ self->tx_buff.truesize);
- idev->tx_buff.data += actual;
- idev->tx_buff.len -= actual;
+ 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(&idev->lock, flags);
+ spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
@@ -465,30 +650,31 @@
}
/*
- * Function irport_receive (void)
+ * Function irport_receive (self)
*
* Receive one frame from the infrared port
*
*/
-static void irport_receive(struct irda_device *idev)
+static void irport_receive(struct irport_cb *self)
{
- int iobase;
int boguscount = 0;
+ int iobase;
- ASSERT(idev != NULL, return;);
+ ASSERT(self != NULL, return;);
- iobase = idev->io.iobase2;
+ 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(idev, inb(iobase+UART_RX));
+ 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) {
- DEBUG(0,__FUNCTION__ "(), breaking!\n");
+ IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n");
break;
}
} while (inb(iobase+UART_LSR) & UART_LSR_DR);
@@ -501,58 +687,60 @@
*/
void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct irda_device *idev = (struct irda_device *) dev_id;
+ struct device *dev = (struct device *) dev_id;
+ struct irport_cb *self;
+ int boguscount = 0;
int iobase;
int iir, lsr;
- int boguscount = 0;
- if (!idev) {
+ if (!dev) {
WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq);
return;
}
+ self = (struct irport_cb *) dev->priv;
- spin_lock(&idev->lock);
+ spin_lock(&self->lock);
- idev->netdev.interrupt = 1;
+ dev->interrupt = 1;
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
iir = inb(iobase+UART_IIR) & UART_IIR_ID;
while (iir) {
/* Clear interrupt */
lsr = inb(iobase+UART_LSR);
- DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n",
- iir, lsr, iobase);
+ IRDA_DEBUG(4, __FUNCTION__
+ "(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ iir, lsr, iobase);
switch (iir) {
case UART_IIR_RLSI:
- DEBUG(0, __FUNCTION__ "(), RLSI\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n");
break;
case UART_IIR_RDI:
- if (lsr & UART_LSR_DR)
- /* Receive interrupt */
- irport_receive(idev);
+ /* Receive interrupt */
+ irport_receive(self);
break;
case UART_IIR_THRI:
if (lsr & UART_LSR_THRE)
/* Transmitter ready for data */
- irport_write_wakeup(idev);
+ irport_write_wakeup(self);
break;
default:
- DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+ IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
break;
}
/* Make sure we don't stay here to long */
- if (boguscount++ > 32)
+ if (boguscount++ > 100)
break;
iir = inb(iobase + UART_IIR) & UART_IIR_ID;
}
- idev->netdev.interrupt = 0;
+ dev->interrupt = 0;
- spin_unlock(&idev->lock);
+ spin_unlock(&self->lock);
}
static int irport_net_init(struct device *dev)
@@ -568,64 +756,75 @@
/*
* Function irport_net_open (dev)
*
- *
- *
+ * Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ *
*/
-static int irport_net_open(struct device *dev)
+int irport_net_open(struct device *dev)
{
- struct irda_device *idev;
+ struct irport_cb *self;
int iobase;
ASSERT(dev != NULL, return -1;);
- idev = (struct irda_device *) dev->priv;
+ self = (struct irport_cb *) dev->priv;
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
- if (request_irq(idev->io.irq2, irport_interrupt, 0, idev->name,
- (void *) idev))
+ if (request_irq(self->io.irq, self->interrupt, 0, dev->name,
+ (void *) dev))
return -EAGAIN;
- irport_start(idev, iobase);
-
- MOD_INC_USE_COUNT;
+ irport_start(self);
/* Ready to play! */
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
- /* Change speed to make sure dongles follow us again */
- if (idev->change_speed)
- idev->change_speed(idev, 9600);
+ /*
+ * Open new IrLAP layer instance, now that everything should be
+ * initialized properly
+ */
+ self->irlap = irlap_open(dev, &self->qos);
+
+ /* FIXME: change speed of dongle */
+
+ MOD_INC_USE_COUNT;
return 0;
}
/*
- * Function irport_net_close (idev)
- *
- *
+ * Function irport_net_close (self)
*
+ * Network device is taken down. Usually this is done by
+ * "ifconfig irda0 down"
*/
-static int irport_net_close(struct device *dev)
+int irport_net_close(struct device *dev)
{
- struct irda_device *idev;
+ struct irport_cb *self;
int iobase;
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
ASSERT(dev != NULL, return -1;);
- idev = (struct irda_device *) dev->priv;
+ self = (struct irport_cb *) dev->priv;
- DEBUG(4, __FUNCTION__ "()\n");
+ ASSERT(self != NULL, return -1;);
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
/* Stop device */
dev->tbusy = 1;
dev->start = 0;
- irport_stop(idev, iobase);
+ /* Stop and remove instance of IrLAP */
+ if (self->irlap)
+ irlap_close(self->irlap);
+ self->irlap = NULL;
+
+ irport_stop(self);
- free_irq(idev->io.irq2, idev);
+ free_irq(self->io.irq, dev);
MOD_DEC_USE_COUNT;
@@ -633,50 +832,52 @@
}
/*
- * Function irport_wait_until_sent (idev)
+ * Function irport_wait_until_sent (self)
*
* Delay exectution until finished transmitting
*
*/
-void irport_wait_until_sent(struct irda_device *idev)
+#if 0
+void irport_wait_until_sent(struct irport_cb *self)
{
int iobase;
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
/* Wait until Tx FIFO is empty */
while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- DEBUG(2, __FUNCTION__ "(), waiting!\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), waiting!\n");
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(MSECS_TO_JIFFIES(60));
}
}
+#endif
/*
- * Function irport_is_receiving (idev)
+ * Function irport_is_receiving (self)
*
* Returns true is we are currently receiving data
*
*/
-static int irport_is_receiving(struct irda_device *idev)
+static int irport_is_receiving(struct irport_cb *self)
{
- return (idev->rx_buff.state != OUTSIDE_FRAME);
+ return (self->rx_buff.state != OUTSIDE_FRAME);
}
/*
- * Function irtty_set_dtr_rts (tty, dtr, rts)
+ * Function irport_set_dtr_rts (tty, dtr, rts)
*
* This function can be used by dongles etc. to set or reset the status
* of the dtr and rts lines
*/
-static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
+static int irport_set_dtr_rts(struct device *dev, int dtr, int rts)
{
+ struct irport_cb *self = dev->priv;
int iobase;
- ASSERT(idev != NULL, return;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+ ASSERT(self != NULL, return -1;);
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
if (dtr)
dtr = UART_MCR_DTR;
@@ -684,21 +885,23 @@
rts = UART_MCR_RTS;
outb(dtr|rts|UART_MCR_OUT2, iobase+UART_MCR);
+
+ return 0;
}
-static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len)
+static int irport_raw_write(struct device *dev, __u8 *buf, int len)
{
- int iobase;
+ struct irport_cb *self = (struct irport_cb *) dev->priv;
int actual = 0;
+ int iobase;
- ASSERT(idev != NULL, return -1;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+ ASSERT(self != NULL, return -1;);
- iobase = idev->io.iobase2;
+ iobase = self->io.sir_base;
/* Tx FIFO should be empty! */
if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+ IRDA_DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
return -1;
}
@@ -712,34 +915,105 @@
return actual;
}
-#ifdef MODULE
+/*
+ * Function irport_net_ioctl (dev, rq, cmd)
+ *
+ * Process IOCTL commands for this device
+ *
+ */
+static int irport_net_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *) rq;
+ struct irport_cb *self;
+ dongle_t *dongle;
+ unsigned long flags;
+ int ret = 0;
+
+ ASSERT(dev != NULL, return -1;);
+
+ self = dev->priv;
+
+ ASSERT(self != NULL, return -1;);
+
+ IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+
+ /* Disable interrupts & save flags */
+ save_flags(flags);
+ cli();
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ irda_task_execute(self, __irport_change_speed, NULL, NULL,
+ (void *) irq->ifr_baudrate);
+ break;
+ case SIOCSDONGLE: /* Set dongle */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ /* Initialize dongle */
+ dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
+ if (!dongle)
+ break;
+
+ dongle->set_mode = NULL;
+ dongle->read = NULL;
+ dongle->write = irport_raw_write;
+ dongle->set_dtr_rts = irport_set_dtr_rts;
+
+ self->dongle = dongle;
+
+ /* Now initialize the dongle! */
+ dongle->issue->open(dongle, &self->qos);
+
+ /* Reset dongle */
+ irda_task_execute(dongle, dongle->issue->reset, NULL, NULL,
+ NULL);
+ break;
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ irda_device_set_media_busy(self->netdev, TRUE);
+ break;
+ case SIOCGRECEIVING: /* Check if we are receiving right now */
+ irq->ifr_receiving = irport_is_receiving(self);
+ break;
+ case SIOCSDTRRTS:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ restore_flags(flags);
+
+ return ret;
+}
+
+static struct net_device_stats *irport_net_get_stats(struct device *dev)
+{
+ struct irport_cb *self = (struct irport_cb *) dev->priv;
+
+ return &self->stats;
+}
+#ifdef MODULE
MODULE_PARM(io, "1-4i");
MODULE_PARM(irq, "1-4i");
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode");
-/*
- * Function cleanup_module (void)
- *
- *
- *
- */
void cleanup_module(void)
{
irport_cleanup();
}
-/*
- * Function init_module (void)
- *
- *
- */
int init_module(void)
{
return irport_init();
}
-
#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)