diff options
Diffstat (limited to 'drivers/net/irda/irtty.c')
-rw-r--r-- | drivers/net/irda/irtty.c | 623 |
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>"); |