summaryrefslogtreecommitdiffstats
path: root/drivers/net/irda/irtty.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/irda/irtty.c')
-rw-r--r--drivers/net/irda/irtty.c623
1 files changed, 439 insertions, 184 deletions
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index 6a439a1a8..b6a9dad59 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
- * Modified at: Tue Sep 28 08:39:29 1999
+ * Modified at: Wed Oct 20 00:05:43 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -29,6 +29,8 @@
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
@@ -36,7 +38,6 @@
#include <net/irda/irda.h>
#include <net/irda/irtty.h>
#include <net/irda/wrapper.h>
-#include <net/irda/irlap.h>
#include <net/irda/timer.h>
#include <net/irda/irda_device.h>
@@ -46,27 +47,31 @@ static struct tty_ldisc irda_ldisc;
static int qos_mtt_bits = 0x03; /* 5 ms or more */
+/* Network device fuction prototypes */
static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev);
-static void irtty_wait_until_sent(struct irda_device *driver);
-static int irtty_is_receiving(struct irda_device *idev);
-static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
-static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len);
-static int irtty_raw_read(struct irda_device *idev, __u8 *buf, int len,
- int timeout);
-static void irtty_set_raw_mode(struct irda_device *dev, int mode);
static int irtty_net_init(struct net_device *dev);
static int irtty_net_open(struct net_device *dev);
static int irtty_net_close(struct net_device *dev);
+static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *irtty_net_get_stats(struct net_device *dev);
+/* Line discipline function prototypes */
static int irtty_open(struct tty_struct *tty);
static void irtty_close(struct tty_struct *tty);
static int irtty_ioctl(struct tty_struct *, void *, int, void *);
static int irtty_receive_room(struct tty_struct *tty);
-static void irtty_change_speed(struct irda_device *dev, __u32 speed);
static void irtty_write_wakeup(struct tty_struct *tty);
-
static void irtty_receive_buf(struct tty_struct *, const unsigned char *,
char *, int);
+
+/* IrDA specific function protoctypes */
+static int irtty_is_receiving(struct irtty_cb *self);
+static int irtty_set_dtr_rts(struct net_device *dev, int dtr, int rts);
+static int irtty_raw_write(struct net_device *dev, __u8 *buf, int len);
+static int irtty_raw_read(struct net_device *dev, __u8 *buf, int len);
+static int irtty_set_mode(struct net_device *dev, int mode);
+static int irtty_change_speed(struct irda_task *task);
+
char *driver_name = "irtty";
int __init irtty_init(void)
@@ -140,13 +145,16 @@ static void irtty_cleanup(void)
*/
static int irtty_open(struct tty_struct *tty)
{
+ struct net_device *dev;
struct irtty_cb *self;
char name[16];
+ int err;
ASSERT(tty != NULL, return -EEXIST;);
/* First make sure we're not already connected. */
self = (struct irtty_cb *) tty->disc_data;
+
if (self != NULL && self->magic == IRTTY_MAGIC)
return -EEXIST;
@@ -168,9 +176,8 @@ static int irtty_open(struct tty_struct *tty)
sprintf(name, "%s%d", tty->driver.name,
MINOR(tty->device) - tty->driver.minor_start +
tty->driver.name_base);
-
- /* hashbin_insert( irtty, (QUEUE*) self, 0, self->name); */
- hashbin_insert(irtty, (QUEUE*) self, (int) self, NULL);
+
+ hashbin_insert(irtty, (queue_t *) self, (int) self, NULL);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
@@ -179,11 +186,7 @@ static int irtty_open(struct tty_struct *tty)
tty->ldisc.flush_buffer(tty);
self->magic = IRTTY_MAGIC;
-
- /*
- * Initialize driver
- */
- self->idev.rx_buff.state = OUTSIDE_FRAME;
+ self->rx_buff.state = OUTSIDE_FRAME;
/*
* Initialize QoS capabilities, we fill in all the stuff that
@@ -191,40 +194,71 @@ static int irtty_open(struct tty_struct *tty)
* that are not device dependent (such as link disconnect time) so
* this parameter can be set by IrLAP (or the user) instead. DB
*/
- irda_init_max_qos_capabilies(&self->idev.qos);
+ irda_init_max_qos_capabilies(&self->qos);
/* The only value we must override it the baudrate */
- self->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;
- self->idev.qos.min_turn_time.bits = qos_mtt_bits;
- self->idev.flags = IFF_SIR | IFF_PIO;
- irda_qos_bits_to_value(&self->idev.qos);
-
- /* Specify which buffer allocation policy we need */
- self->idev.rx_buff.flags = GFP_KERNEL;
- self->idev.tx_buff.flags = GFP_KERNEL;
+ self->qos.min_turn_time.bits = qos_mtt_bits;
+ self->flags = IFF_SIR | IFF_PIO;
+ irda_qos_bits_to_value(&self->qos);
/* Specify how much memory we want */
- self->idev.rx_buff.truesize = 4000;
- self->idev.tx_buff.truesize = 4000;
-
- /* Initialize callbacks */
- self->idev.change_speed = irtty_change_speed;
- self->idev.is_receiving = irtty_is_receiving;
- self->idev.wait_until_sent = irtty_wait_until_sent;
- self->idev.set_dtr_rts = irtty_set_dtr_rts;
- self->idev.set_raw_mode = irtty_set_raw_mode;
- self->idev.raw_write = irtty_raw_write;
- self->idev.raw_read = irtty_raw_read;
+ 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 -ENOMEM;
+ 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 -ENOMEM;
+ }
+ memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+ }
+
+ self->magic = IRTTY_MAGIC;
+
+ self->rx_buff.in_frame = FALSE;
+ self->rx_buff.state = OUTSIDE_FRAME;
+ self->tx_buff.data = self->tx_buff.head;
+ self->rx_buff.data = self->rx_buff.head;
+
+ if (!(dev = dev_alloc("irda%d", &err))) {
+ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+ return -ENOMEM;
+ }
+ /* dev_alloc doesn't clear the struct */
+ memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
+
+ dev->priv = (void *) self;
+ self->netdev = dev;
/* Override the network functions we need to use */
- self->idev.netdev.init = irtty_net_init;
- self->idev.netdev.hard_start_xmit = irtty_hard_xmit;
- self->idev.netdev.open = irtty_net_open;
- self->idev.netdev.stop = irtty_net_close;
+ dev->init = irtty_net_init;
+ dev->hard_start_xmit = irtty_hard_xmit;
+ dev->open = irtty_net_open;
+ dev->stop = irtty_net_close;
+ dev->get_stats = irtty_net_get_stats;
+ dev->do_ioctl = irtty_net_ioctl;
+
+ rtnl_lock();
+ err = register_netdevice(dev);
+ rtnl_unlock();
+ if (err) {
+ ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+ return -1;
+ }
- /* Open the IrDA device */
- irda_device_open(&self->idev, name, self);
+ MESSAGE("IrDA: Registered device %s\n", dev->name);
MOD_INC_USE_COUNT;
@@ -245,39 +279,50 @@ static void irtty_close(struct tty_struct *tty)
/* First make sure we're connected. */
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRTTY_MAGIC, return;);
-
- /* Remove driver */
- irda_device_close(&self->idev);
-
+
/* Stop tty */
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
tty->disc_data = 0;
-
+
+ /* 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();
+ }
+
self->tty = NULL;
self->magic = 0;
self = hashbin_remove(irtty, (int) self, NULL);
-
- if (self != NULL)
- kfree(self);
+ if (self->tx_buff.head)
+ kfree(self->tx_buff.head);
+
+ if (self->rx_buff.head)
+ kfree(self->rx_buff.head);
+
+ kfree(self);
+
MOD_DEC_USE_COUNT;
}
/*
- * Function irtty_stop_receiver (irda_device, stop)
+ * Function irtty_stop_receiver (self, stop)
*
*
*
*/
-static void irtty_stop_receiver(struct irda_device *idev, int stop)
+static void irtty_stop_receiver(struct irtty_cb *self, int stop)
{
struct termios old_termios;
- struct irtty_cb *self;
int cflag;
- self = (struct irtty_cb *) idev->priv;
-
old_termios = *(self->tty->termios);
cflag = self->tty->termios->c_cflag;
@@ -291,24 +336,16 @@ static void irtty_stop_receiver(struct irda_device *idev, int stop)
}
/*
- * Function irtty_change_speed (self, speed)
+ * Function irtty_do_change_speed (self, speed)
*
- * Change the speed of the serial port. The driver layer must check that
- * all transmission has finished using the irtty_wait_until_sent()
- * function.
+ * Change the speed of the serial port.
*/
-static void irtty_change_speed(struct irda_device *idev, __u32 speed)
+static void __irtty_change_speed(struct irtty_cb *self, __u32 speed)
{
struct termios old_termios;
- struct irtty_cb *self;
int cflag;
- DEBUG(4, __FUNCTION__ "(), <%ld>\n", jiffies);
-
- ASSERT(idev != NULL, return;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-
- self = (struct irtty_cb *) idev->priv;
+ IRDA_DEBUG(0, __FUNCTION__ "(), <%ld>\n", jiffies);
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRTTY_MAGIC, return;);
@@ -318,7 +355,7 @@ static void irtty_change_speed(struct irda_device *idev, __u32 speed)
cflag &= ~CBAUD;
- DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", speed);
+ IRDA_DEBUG(0, __FUNCTION__ "(), Setting speed to %d\n", speed);
switch (speed) {
case 1200:
@@ -350,6 +387,81 @@ static void irtty_change_speed(struct irda_device *idev, __u32 speed)
self->tty->termios->c_cflag = cflag;
self->tty->driver.set_termios(self->tty, &old_termios);
+
+ self->io.speed = speed;
+}
+
+/*
+ * Function irtty_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
+ */
+static int irtty_change_speed(struct irda_task *task)
+{
+ struct irtty_cb *self;
+ __u32 speed = (__u32) task->param;
+ int ret = 0;
+
+ IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies);
+
+ self = (struct irtty_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->tty->driver.chars_in_buffer(self->tty)) {
+ 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 */
+ __irtty_change_speed(self, 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 */
+ __irtty_change_speed(self, 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;
}
/*
@@ -360,9 +472,11 @@ static void irtty_change_speed(struct irda_device *idev, __u32 speed)
*/
static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
{
+ dongle_t *dongle;
+ struct irtty_info info;
struct irtty_cb *self;
- int err = 0;
int size = _IOC_SIZE(cmd);
+ int err = 0;
self = (struct irtty_cb *) tty->disc_data;
@@ -370,13 +484,13 @@ static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
ASSERT(self->magic == IRTTY_MAGIC, return -EBADR;);
if (_IOC_DIR(cmd) & _IOC_READ)
- err = verify_area( VERIFY_WRITE, (void *) arg, size);
+ err = verify_area(VERIFY_WRITE, (void *) arg, size);
else if (_IOC_DIR(cmd) & _IOC_WRITE)
- err = verify_area( VERIFY_READ, (void *) arg, size);
+ err = verify_area(VERIFY_READ, (void *) arg, size);
if (err)
return err;
- switch(cmd) {
+ switch (cmd) {
case TCGETS:
case TCGETA:
return n_tty_ioctl(tty, (struct file *) file, cmd,
@@ -384,7 +498,34 @@ static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
break;
case IRTTY_IOCTDONGLE:
/* Initialize dongle */
- irda_device_init_dongle(&self->idev, (int) arg);
+ dongle = irda_device_dongle_init(self->netdev, (int) arg);
+ if (!dongle)
+ break;
+
+ /* Initialize callbacks */
+ dongle->set_mode = irtty_set_mode;
+ dongle->read = irtty_raw_read;
+ dongle->write = irtty_raw_write;
+ dongle->set_dtr_rts = irtty_set_dtr_rts;
+
+ /* Bind dongle */
+ self->dongle = dongle;
+
+ /* Now initialize the dongle! */
+ dongle->issue->open(dongle, &self->qos);
+
+ /* Reset dongle */
+ irda_task_execute(dongle, dongle->issue->reset, NULL, NULL,
+ NULL);
+ break;
+ case IRTTY_IOCGET:
+ ASSERT(self->netdev != NULL, return -1;);
+
+ memset(&info, 0, sizeof(struct irtty_info));
+ strncpy(info.name, self->netdev->name, 5);
+
+ if (copy_to_user(arg, &info, sizeof(struct irtty_info)))
+ return -EFAULT;
break;
default:
return -ENOIOCTLCMD;
@@ -405,34 +546,61 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
{
struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
- DEBUG(5, __FUNCTION__ "(,,,count=%d)\n", count);
/* Read the characters out of the buffer */
while (count--) {
/*
* Characters received with a parity error, etc?
*/
if (fp && *fp++) {
- DEBUG( 0, "Framing or parity error!\n");
- irda_device_set_media_busy(&self->idev.netdev, TRUE);
-
+ IRDA_DEBUG(0, "Framing or parity error!\n");
+ irda_device_set_media_busy(self->netdev, TRUE);
+
cp++;
continue;
}
+
+ switch (self->mode) {
+ case IRDA_IRLAP:
+ /* Unwrap and destuff one byte */
+ async_unwrap_char(self->netdev, &self->rx_buff, *cp++);
+ break;
+ case IRDA_RAW:
+ /* What should we do when the buffer is full? */
+ if (self->rx_buff.len == self->rx_buff.truesize)
+ self->rx_buff.len = 0;
+
+ self->rx_buff.data[self->rx_buff.len++] = *cp++;
+ break;
+ default:
+ break;
+ }
+ }
+}
- DEBUG(6, __FUNCTION__ " char=0x%02x\n", *cp);
- if (self->idev.raw_mode) {
- struct irda_device *idev = &self->idev;
+/*
+ * Function irtty_change_speed_complete (task)
+ *
+ * Called when the change speed operation completes
+ *
+ */
+static int irtty_change_speed_complete(struct irda_task *task)
+{
+ struct irtty_cb *self;
- /* What should we do when the buffer is full? */
- if (idev->rx_buff.len == idev->rx_buff.truesize)
- idev->rx_buff.len = 0;
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
- idev->rx_buff.data[idev->rx_buff.len++] = *cp++;
- } else {
- /* Unwrap and destuff one byte */
- async_unwrap_char(&self->idev, *cp++);
- }
- }
+ self = (struct irtty_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;
}
/*
@@ -444,29 +612,34 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct irtty_cb *self;
- struct irda_device *idev;
int actual = 0;
+ __u32 speed;
- idev = (struct irda_device *) dev->priv;
-
- ASSERT(idev != NULL, return 0;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
-
- self = (struct irtty_cb *) idev->priv;
-
+ self = (struct irtty_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
- ASSERT(self->magic == IRTTY_MAGIC, return 0;);
/* Lock transmit buffer */
if (irda_lock((void *) &dev->tbusy) == FALSE)
return -EBUSY;
+
+ /* Check if we need to change the speed */
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ if (irda_task_execute(self, irtty_change_speed,
+ irtty_change_speed_complete, NULL,
+ (void *) speed))
+ /*
+ * Task not finished yet, so make the netdevice
+ * layer requeue the frame
+ */
+ return -EBUSY;
+ }
/* 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);
self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
@@ -474,22 +647,22 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
if (self->tty->driver.write)
actual = self->tty->driver.write(self->tty, 0,
- idev->tx_buff.data,
- idev->tx_buff.len);
+ self->tx_buff.data,
+ self->tx_buff.len);
/* Hide the part we just transmitted */
- idev->tx_buff.data += actual;
- idev->tx_buff.len -= actual;
+ self->tx_buff.data += actual;
+ self->tx_buff.len -= actual;
- idev->stats.tx_packets++;
- idev->stats.tx_bytes += idev->tx_buff.len;
+ self->stats.tx_packets++;
+ self->stats.tx_bytes += self->tx_buff.len;
#if 0
/*
* Did we transmit the whole frame? Commented out for now since
* I must check if this optimalization really works. DB.
*/
- if ((idev->tx_buff.len) == 0) {
- DEBUG( 4, "irtty_xmit_buf: finished with frame!\n");
+ if ((self->tx_buff.len) == 0) {
+ IRDA_DEBUG( 4, "irtty_xmit_buf: finished with frame!\n");
self->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
irda_unlock( &self->tbusy);
}
@@ -507,7 +680,7 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
*/
static int irtty_receive_room(struct tty_struct *tty)
{
- DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
return 65536; /* We can handle an infinite amount of data. :-) */
}
@@ -521,7 +694,6 @@ static int irtty_receive_room(struct tty_struct *tty)
static void irtty_write_wakeup(struct tty_struct *tty)
{
struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
- struct irda_device *idev;
int actual = 0;
/*
@@ -530,26 +702,24 @@ static void irtty_write_wakeup(struct tty_struct *tty)
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRTTY_MAGIC, return;);
- idev = &self->idev;
-
/* Finished with frame? */
- if (idev->tx_buff.len > 0) {
+ if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
- actual = tty->driver.write(tty, 0, idev->tx_buff.data,
- idev->tx_buff.len);
+ actual = tty->driver.write(tty, 0, self->tx_buff.data,
+ self->tx_buff.len);
- idev->tx_buff.data += actual;
- idev->tx_buff.len -= actual;
+ self->tx_buff.data += actual;
+ self->tx_buff.len -= actual;
} else {
/*
* Now serial buffer is almost free & we can start
* transmission of another packet
*/
- DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
+ IRDA_DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- idev->netdev.tbusy = 0; /* Unlock */
+ self->netdev->tbusy = 0; /* Unlock */
/* Tell network layer that we want more frames */
mark_bh(NET_BH);
@@ -557,34 +727,14 @@ static void irtty_write_wakeup(struct tty_struct *tty)
}
/*
- * Function irtty_is_receiving (idev)
+ * Function irtty_is_receiving (self)
*
* Return TRUE is we are currently receiving a frame
*
*/
-static int irtty_is_receiving(struct irda_device *idev)
+static int irtty_is_receiving(struct irtty_cb *self)
{
- return (idev->rx_buff.state != OUTSIDE_FRAME);
-}
-
-/*
- * Function irtty_change_speed_ready (idev)
- *
- * Are we completely finished with transmitting frames so its possible
- * to change the speed of the serial port. Warning this function must
- * be called with a process context!
- */
-static void irtty_wait_until_sent(struct irda_device *idev)
-{
- struct irtty_cb *self = (struct irtty_cb *) idev->priv;
-
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRTTY_MAGIC, return;);
-
- DEBUG(4, "Chars in buffer %d\n",
- self->tty->driver.chars_in_buffer(self->tty));
-
- tty_wait_until_sent(self->tty, 0);
+ return (self->rx_buff.state != OUTSIDE_FRAME);
}
/*
@@ -593,15 +743,14 @@ static void irtty_wait_until_sent(struct irda_device *idev)
* This function can be used by dongles etc. to set or reset the status
* of the dtr and rts lines
*/
-static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
+static int irtty_set_dtr_rts(struct net_device *dev, int dtr, int rts)
{
- struct tty_struct *tty;
struct irtty_cb *self;
+ struct tty_struct *tty;
mm_segment_t fs;
int arg = 0;
- self = (struct irtty_cb *) idev->priv;
-
+ self = (struct irtty_cb *) dev->priv;
tty = self->tty;
#ifdef TIOCM_OUT2 /* Not defined for ARM */
@@ -627,52 +776,62 @@ static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
ERROR(__FUNCTION__ "(), error doing ioctl!\n");
}
set_fs(fs);
+
+ return 0;
}
/*
- * Function irtty_set_raw_mode (idev, status)
+ * Function irtty_set_mode (self, status)
*
* For the airport dongle, we need support for reading raw characters
* from the IrDA device. This function switches between those modes.
* FALSE is the default mode, and will then treat incoming data as IrDA
* packets.
*/
-void irtty_set_raw_mode(struct irda_device *idev, int status)
+int irtty_set_mode(struct net_device *dev, int mode)
{
struct irtty_cb *self;
- DEBUG(2, __FUNCTION__ "(), status=%s\n", status ? "TRUE" : "FALSE");
+ self = (struct irtty_cb *) dev->priv;
- ASSERT(idev != NULL, return;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-
- self = (struct irtty_cb *) idev->priv;
+ ASSERT(self != NULL, return -1;);
+ IRDA_DEBUG(2, __FUNCTION__ "(), mode=%s\n", infrared_mode[mode]);
+
/* save status for driver */
- self->idev.raw_mode = status;
+ self->mode = mode;
/* reset the buffer state */
- idev->rx_buff.data = idev->rx_buff.head;
- idev->rx_buff.len = 0;
- idev->rx_buff.state = OUTSIDE_FRAME;
+ self->rx_buff.data = self->rx_buff.head;
+ self->rx_buff.len = 0;
+ self->rx_buff.state = OUTSIDE_FRAME;
+
+ return 0;
}
/*
- * Function irtty_raw_read (idev, buf, len)
+ * Function irtty_raw_read (self, buf, len)
*
* Receive incomming data. This function sleeps, so it must only be
* called with a process context. Timeout is currently defined to be
* a multiple of 10 ms.
*/
-static int irtty_raw_read(struct irda_device *idev, __u8 *buf, int len,
- int timeout)
+static int irtty_raw_read(struct net_device *dev, __u8 *buf, int len)
{
+ struct irtty_cb *self;
int count;
- buf = idev->rx_buff.data;
+ self = (struct irtty_cb *) dev->priv;
+
+ ASSERT(self != NULL, return 0;);
+ ASSERT(self->magic == IRTTY_MAGIC, return 0;);
+
+ return 0;
+#if 0
+ buf = self->rx_buff.data;
/* Wait for the requested amount of data to arrive */
- while (len < idev->rx_buff.len) {
+ while (len < self->rx_buff.len) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(MSECS_TO_JIFFIES(10));
@@ -680,30 +839,27 @@ static int irtty_raw_read(struct irda_device *idev, __u8 *buf, int len,
break;
}
- count = idev->rx_buff.len < len ? idev->rx_buff.len : len;
+ count = self->rx_buff.len < len ? self->rx_buff.len : len;
/*
* Reset the state, this mean that a raw read is sort of a
* datagram read, and _not_ a stream style read. Be aware of the
* difference. Implementing it the other way will just be painful ;-)
*/
- idev->rx_buff.data = idev->rx_buff.head;
- idev->rx_buff.len = 0;
- idev->rx_buff.state = OUTSIDE_FRAME;
-
+ self->rx_buff.data = self->rx_buff.head;
+ self->rx_buff.len = 0;
+ self->rx_buff.state = OUTSIDE_FRAME;
+#endif
/* Return the amount we were able to get */
return count;
}
-static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len)
+static int irtty_raw_write(struct net_device *dev, __u8 *buf, int len)
{
struct irtty_cb *self;
int actual = 0;
- ASSERT(idev != NULL, return 0;);
- ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
-
- self = (struct irtty_cb *) idev->priv;
+ self = (struct irtty_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
ASSERT(self->magic == IRTTY_MAGIC, return 0;);
@@ -714,8 +870,6 @@ static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len)
return actual;
}
-
-
static int irtty_net_init(struct net_device *dev)
{
/* Set up to be a normal IrDA network device driver */
@@ -728,12 +882,26 @@ static int irtty_net_init(struct net_device *dev)
static int irtty_net_open(struct net_device *dev)
{
- struct irda_device *idev = dev->priv;
+ struct irtty_cb *self = (struct irtty_cb *) dev->priv;
- irda_device_net_open(dev);
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == IRTTY_MAGIC, return -1;);
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ /* Ready to play! */
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
/* Make sure we can receive more data */
- irtty_stop_receiver(idev, FALSE);
+ irtty_stop_receiver(self, FALSE);
+
+ /*
+ * Open new IrLAP layer instance, now that everything should be
+ * initialized properly
+ */
+ self->irlap = irlap_open(dev, &self->qos);
MOD_INC_USE_COUNT;
@@ -742,18 +910,105 @@ static int irtty_net_open(struct net_device *dev)
static int irtty_net_close(struct net_device *dev)
{
- struct irda_device *idev = dev->priv;
+ struct irtty_cb *self = (struct irtty_cb *) dev->priv;
+
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == IRTTY_MAGIC, return -1;);
/* Make sure we don't receive more data */
- irtty_stop_receiver(idev, TRUE);
+ irtty_stop_receiver(self, TRUE);
- irda_device_net_close(dev);
+ /* Stop device */
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ /* Stop and remove instance of IrLAP */
+ if (self->irlap)
+ irlap_close(self->irlap);
+ self->irlap = NULL;
MOD_DEC_USE_COUNT;
return 0;
}
+/*
+ * Function irtty_net_ioctl (dev, rq, cmd)
+ *
+ * Process IOCTL commands for this device
+ *
+ */
+static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *) rq;
+ struct irtty_cb *self;
+ dongle_t *dongle;
+ unsigned long flags;
+ int ret = 0;
+
+ ASSERT(dev != NULL, return -1;);
+
+ self = dev->priv;
+
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == IRTTY_MAGIC, 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 */
+ irda_task_execute(self, irtty_change_speed, NULL, NULL,
+ (void *) irq->ifr_baudrate);
+ break;
+ case SIOCSDONGLE: /* Set dongle */
+ /* Initialize dongle */
+ dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
+ if (!dongle)
+ break;
+
+ dongle->set_mode = irtty_set_mode;
+ dongle->read = irtty_raw_read;
+ dongle->write = irtty_raw_write;
+ dongle->set_dtr_rts = irtty_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 */
+ irda_device_set_media_busy(self->netdev, TRUE);
+ break;
+ case SIOCGRECEIVING: /* Check if we are receiving right now */
+ irq->ifr_receiving = irtty_is_receiving(self);
+ break;
+ case SIOCSDTRRTS:
+ irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ restore_flags(flags);
+
+ return ret;
+}
+
+static struct net_device_stats *irtty_net_get_stats(struct net_device *dev)
+{
+ struct irtty_cb *self = (struct irtty_cb *) dev->priv;
+
+ return &self->stats;
+}
+
#ifdef MODULE
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");