Commit 329c2084 authored by Stephen Hemminger's avatar Stephen Hemminger

[IRDA]: Kill old irtty driver, as suggested by Jean and Jeff.

parent 71c2e86e
......@@ -68,20 +68,6 @@ config TEKRAM_DONGLE
comment "Old SIR device drivers"
config IRTTY_OLD
tristate "Old IrTTY (broken)"
depends on IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the IrTTY line
discipline. If you want to compile it as a module (irtty), say M
here and read <file:Documentation/modules.txt>. IrTTY makes it
possible to use Linux's own serial driver for all IrDA ports that
are 16550 compatible. Most IrDA chips are 16550 compatible so you
should probably say Y to this option. Using IrTTY will however
limit the speed of the connection to 115200 bps (IrDA SIR mode).
If unsure, say N.
config IRPORT_SIR
tristate "IrPORT (IrDA serial driver)"
depends on IRDA
......
......@@ -5,8 +5,7 @@
# Rewritten to use lists instead of if-statements.
#
# Old SIR drivers (irtty is broken)
obj-$(CONFIG_IRTTY_OLD) += irtty.o
# Old SIR drivers
obj-$(CONFIG_IRPORT_SIR) += irport.o
# FIR drivers
obj-$(CONFIG_USB_IRDA) += irda-usb.o
......
/*********************************************************************
*
* Filename: irtty.c
* Version: 1.1
* Description: IrDA line discipline implementation
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
* Modified at: Sat Mar 11 07:43:30 2000
* 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>
*
* Copyright (c) 1998-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.
*
* Neither Dag Brattli nor University of Troms admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
********************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <asm/uaccess.h>
#include <net/irda/irda.h>
#include <net/irda/irtty.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
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 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 *, struct file *,
unsigned int, unsigned long);
static int irtty_receive_room(struct tty_struct *tty);
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);
static struct tty_ldisc irda_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "irda",
.open = irtty_open,
.close = irtty_close,
.ioctl = irtty_ioctl,
.receive_buf = irtty_receive_buf,
.receive_room = irtty_receive_room,
.write_wakeup = irtty_write_wakeup,
};
int __init irtty_init(void)
{
int status;
if ((status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) {
ERROR("IrDA: can't register line discipline (err = %d)\n",
status);
}
return status;
}
/*
* Function irtty_cleanup ( )
*
* Called when the irda module is removed. Here we remove all instances
* of the driver, and the master array.
*/
static void __exit irtty_cleanup(void)
{
int ret;
/* Unregister tty line-discipline */
if ((ret = tty_register_ldisc(N_IRDA, NULL))) {
ERROR("%s(), can't unregister line discipline (err = %d)\n",
__FUNCTION__, ret);
}
}
/*
* Function irtty_open(tty)
*
* This function is called by the TTY module when the IrDA line
* discipline is called for. Because we are sure the tty line exists,
* we only have to link it to a free IrDA channel.
*/
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;
/*
* Allocate new instance of the driver
*/
self = kmalloc(sizeof(struct irtty_cb), GFP_KERNEL);
if (self == NULL) {
printk(KERN_ERR "IrDA: Can't allocate memory for "
"IrDA control block!\n");
return -ENOMEM;
}
memset(self, 0, sizeof(struct irtty_cb));
spin_lock_init(&self->lock);
self->tty = tty;
tty->disc_data = self;
/* Give self a name */
strcpy(name, tty->name);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
self->magic = IRTTY_MAGIC;
self->mode = IRDA_IRLAP;
/*
* Initialize QoS capabilities, we fill in all the stuff that
* we support. Be careful not to place any restrictions on values
* 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->qos);
/* The only value we must override it the baudrate */
self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
IR_115200;
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->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->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("%s(), dev_alloc() failed!\n", __FUNCTION__);
return -ENOMEM;
}
dev->priv = (void *) self;
self->netdev = dev;
/* Override the network functions we need to use */
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("%s(), register_netdev() failed!\n", __FUNCTION__);
return -1;
}
MESSAGE("IrDA: Registered device %s\n", dev->name);
return 0;
}
/*
* Function irtty_close (tty)
*
* Close down a IrDA channel. This means flushing out any pending queues,
* and then restoring the TTY line discipline to what it was before it got
* hooked to IrDA (which usually is TTY again).
*/
static void irtty_close(struct tty_struct *tty)
{
struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
unsigned long flags;
/* First make sure we're connected. */
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRTTY_MAGIC, return;);
/* Stop tty */
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
tty->disc_data = 0;
/* We are not using any dongle anymore! */
if (self->dongle)
irda_device_dongle_cleanup(self->dongle);
self->dongle = NULL;
/* Remove netdevice */
if (self->netdev)
unregister_netdev(self->netdev);
/* Protect access to self->task and self->?x_buff - Jean II */
spin_lock_irqsave(&self->lock, flags);
/* Remove speed changing task if any */
if (self->task)
irda_task_delete(self->task);
self->tty = NULL;
self->magic = 0;
if (self->tx_buff.head)
kfree(self->tx_buff.head);
if (self->rx_buff.head)
kfree(self->rx_buff.head);
spin_unlock_irqrestore(&self->lock, flags);
kfree(self);
}
/*
* Function irtty_stop_receiver (self, stop)
*
*
*
*/
static void irtty_stop_receiver(struct irtty_cb *self, int stop)
{
struct termios old_termios;
int cflag;
old_termios = *(self->tty->termios);
cflag = self->tty->termios->c_cflag;
if (stop)
cflag &= ~CREAD;
else
cflag |= CREAD;
/* This is unsafe, but currently under discussion - Jean II */
self->tty->termios->c_cflag = cflag;
self->tty->driver->set_termios(self->tty, &old_termios);
}
/*
* Function irtty_do_change_speed (self, speed)
*
* Change the speed of the serial port.
*/
static void __irtty_change_speed(struct irtty_cb *self, __u32 speed)
{
struct termios old_termios;
int cflag;
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRTTY_MAGIC, return;);
old_termios = *(self->tty->termios);
cflag = self->tty->termios->c_cflag;
cflag &= ~CBAUD;
IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
switch (speed) {
case 1200:
cflag |= B1200;
break;
case 2400:
cflag |= B2400;
break;
case 4800:
cflag |= B4800;
break;
case 19200:
cflag |= B19200;
break;
case 38400:
cflag |= B38400;
break;
case 57600:
cflag |= B57600;
break;
case 115200:
cflag |= B115200;
break;
case 9600:
default:
cflag |= B9600;
break;
}
/* This is unsafe, but currently under discussion - Jean II */
self->tty->termios->c_cflag = cflag;
self->tty->driver->set_termios(self->tty, &old_termios);
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;
unsigned long flags;
__u32 speed = (__u32) task->param;
int ret = 0;
IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies);
self = (struct irtty_cb *) task->instance;
ASSERT(self != NULL, return -1;);
/* Protect access to self->task - Jean II */
spin_lock_irqsave(&self->lock, flags);
/* Check if busy */
if (self->task && self->task != task) {
IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
spin_unlock_irqrestore(&self->lock, flags);
return MSECS_TO_JIFFIES(10);
} else
self->task = task;
spin_unlock_irqrestore(&self->lock, flags);
switch (task->state) {
case IRDA_TASK_INIT:
/*
* Make sure all data is sent before changing the speed of the
* serial port.
*/
if (self->tty->driver->chars_in_buffer(self->tty)) {
/* Keep state, and try again later */
ret = MSECS_TO_JIFFIES(10);
break;
} else {
/* Transmit buffer is now empty, but it may still
* take over 13 ms for the FIFO to become empty, so
* wait some more to be sure all data is sent
*/
irda_task_next_state(task, IRDA_TASK_WAIT);
ret = MSECS_TO_JIFFIES(13);
}
case IRDA_TASK_WAIT:
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("%s(), changing speed of dongle timed out!\n", __FUNCTION__);
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);
self->task = NULL;
break;
default:
ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
irda_task_next_state(task, IRDA_TASK_DONE);
self->task = NULL;
ret = -1;
break;
}
return ret;
}
/*
* Function irtty_ioctl (tty, file, cmd, arg)
*
* The Swiss army knife of system calls :-)
*
*/
static int irtty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
dongle_t *dongle;
struct irtty_info info;
struct irtty_cb *self;
int size = _IOC_SIZE(cmd);
int err = 0;
self = (struct irtty_cb *) tty->disc_data;
ASSERT(self != NULL, return -ENODEV;);
ASSERT(self->magic == IRTTY_MAGIC, return -EBADR;);
if (_IOC_DIR(cmd) & _IOC_READ)
err = verify_area(VERIFY_WRITE, (void *) arg, size);
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = verify_area(VERIFY_READ, (void *) arg, size);
if (err)
return err;
switch (cmd) {
case TCGETS:
case TCGETA:
/* Unsure about locking here, to check - Jean II */
return n_tty_ioctl(tty, (struct file *) file, cmd, arg);
break;
case IRTTY_IOCTDONGLE:
/* Initialize dongle */
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;
/* Now initialize the dongle! */
dongle->issue->open(dongle, &self->qos);
/* Reset dongle */
irda_task_execute(dongle, dongle->issue->reset, NULL, NULL,
NULL);
/* Make dongle available to driver only now to avoid
* race conditions - Jean II */
self->dongle = dongle;
break;
case IRTTY_IOCGET:
ASSERT(self->netdev != NULL, return -1;);
memset(&info, 0, sizeof(struct irtty_info));
strncpy(info.name, self->netdev->name, 5);
if (copy_to_user((void *) arg, &info, sizeof(struct irtty_info)))
return -EFAULT;
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
/*
* Function irtty_receive_buf( tty, cp, count)
*
* Handle the 'receiver data ready' interrupt. This function is called
* by the 'tty_io' module in the kernel when a block of IrDA data has
* been received, which can now be decapsulated and delivered for
* further processing
*/
static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
if (!self || !self->netdev) {
IRDA_DEBUG(0, "%s(), not ready yet!\n", __FUNCTION__);
return;
}
// Are we in interrupt context ? What locking is done ? - Jean II
//spin_lock_irqsave(&self->lock, flags);
/* Read the characters out of the buffer */
while (count--) {
/*
* Characters received with a parity error, etc?
*/
if (fp && *fp++) {
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->stats,
&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;
}
}
//spin_unlock_irqrestore(&self->lock, flags);
}
/*
* 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;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
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 */
/* Signal network layer so it can try to send the frame */
netif_wake_queue(self->netdev);
return 0;
}
/*
* Function irtty_hard_xmit (skb, dev)
*
* Transmit frame
*
*/
static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct irtty_cb *self;
int actual = 0;
__s32 speed;
unsigned long flags;
self = (struct irtty_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
/* Lock transmit buffer
* this serialise operations, no need to spinlock - Jean II */
netif_stop_queue(dev);
/* 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) {
irda_task_execute(self, irtty_change_speed,
irtty_change_speed_complete,
NULL, (void *) speed);
dev_kfree_skb(skb);
return 0;
} else
self->new_speed = speed;
}
/* Protect access to self->tx_buff - Jean II */
spin_lock_irqsave(&self->lock, flags);
/* Init tx buffer*/
self->tx_buff.data = self->tx_buff.head;
/* 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->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
dev->trans_start = jiffies;
self->stats.tx_bytes += self->tx_buff.len;
if (self->tty->driver->write)
actual = self->tty->driver->write(self->tty, 0,
self->tx_buff.data,
self->tx_buff.len);
/* Hide the part we just transmitted */
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
}
/*
* Function irtty_receive_room (tty)
*
* Used by the TTY to find out how much data we can receive at a time
*
*/
static int irtty_receive_room(struct tty_struct *tty)
{
IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
return 65536; /* We can handle an infinite amount of data. :-) */
}
/*
* Function irtty_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 irtty_write_wakeup(struct tty_struct *tty)
{
struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
int actual = 0;
unsigned long flags;
/*
* First make sure we're connected.
*/
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRTTY_MAGIC, return;);
/* Protected via netif_stop_queue(dev); - Jean II */
/* Protect access to self->tx_buff - Jean II */
spin_lock_irqsave(&self->lock, flags);
/* Finished with frame? */
if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
actual = tty->driver->write(tty, 0, self->tx_buff.data,
self->tx_buff.len);
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
spin_unlock_irqrestore(&self->lock, flags);
} else {
/*
* Now serial buffer is almost free & we can start
* transmission of another packet
*/
IRDA_DEBUG(5, "%s(), finished with frame!\n", __FUNCTION__);
self->stats.tx_packets++;
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
/* Don't change speed with irq off */
spin_unlock_irqrestore(&self->lock, flags);
if (self->new_speed) {
IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__);
irda_task_execute(self, irtty_change_speed,
irtty_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);
}
}
}
/*
* Function irtty_is_receiving (self)
*
* Return TRUE is we are currently receiving a frame
*
*/
static int irtty_is_receiving(struct irtty_cb *self)
{
return (self->rx_buff.state != OUTSIDE_FRAME);
}
/*
* Function irtty_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 int irtty_set_dtr_rts(struct net_device *dev, int dtr, int rts)
{
struct irtty_cb *self;
struct tty_struct *tty;
//unsigned long flags;
mm_segment_t fs;
int arg = 0;
self = (struct irtty_cb *) dev->priv;
tty = self->tty;
/* Was protected in ioctl handler, but the serial driver doesn't
* like it. This may need to change. - Jean II */
//spin_lock_irqsave(&self->lock, flags);
#ifdef TIOCM_OUT2 /* Not defined for ARM */
arg = TIOCM_OUT2;
#endif
if (rts)
arg |= TIOCM_RTS;
if (dtr)
arg |= TIOCM_DTR;
/*
* The ioctl() function, or actually set_modem_info() in serial.c
* expects a pointer to the argument in user space. To hack us
* around this, we use the set_fs() function to fool the routines
* that check if they are called from user space. We also need
* to send a pointer to the argument so get_user() gets happy. DB.
*/
fs = get_fs();
set_fs(get_ds());
/* This is probably unsafe, but currently under discussion - Jean II */
if (tty->driver->ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) {
IRDA_DEBUG(2, "%s(), error doing ioctl!\n", __FUNCTION__);
}
set_fs(fs);
//spin_unlock_irqrestore(&self->lock, flags);
return 0;
}
/*
* 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.
*/
int irtty_set_mode(struct net_device *dev, int mode)
{
struct irtty_cb *self;
unsigned long flags;
self = (struct irtty_cb *) dev->priv;
ASSERT(self != NULL, return -1;);
IRDA_DEBUG(2, "%s(), mode=%s\n", __FUNCTION__, infrared_mode[mode]);
/* Protect access to self->rx_buff - Jean II */
spin_lock_irqsave(&self->lock, flags);
/* save status for driver */
self->mode = mode;
/* reset the buffer state */
self->rx_buff.data = self->rx_buff.head;
self->rx_buff.len = 0;
self->rx_buff.state = OUTSIDE_FRAME;
spin_unlock_irqrestore(&self->lock, flags);
return 0;
}
/*
* Function irtty_raw_read (self, buf, len)
*
* Receive incoming 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 net_device *dev, __u8 *buf, int len)
{
struct irtty_cb *self;
int count;
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 < self->rx_buff.len) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(MSECS_TO_JIFFIES(10));
if (!timeout--)
break;
}
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 ;-)
*/
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 net_device *dev, __u8 *buf, int len)
{
struct irtty_cb *self;
int actual = 0;
self = (struct irtty_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
ASSERT(self->magic == IRTTY_MAGIC, return 0;);
if (self->tty->driver->write)
actual = self->tty->driver->write(self->tty, 0, buf, len);
return actual;
}
static int irtty_net_init(struct net_device *dev)
{
/* Set up to be a normal IrDA network device driver */
irda_device_setup(dev);
/* Insert overrides below this line! */
return 0;
}
static int irtty_net_open(struct net_device *dev)
{
struct irtty_cb *self = (struct irtty_cb *) dev->priv;
struct tty_struct *tty = self->tty;
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRTTY_MAGIC, return -1;);
IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
/* Ready to play! */
netif_start_queue(dev);
/* Make sure we can receive more data */
irtty_stop_receiver(self, FALSE);
/*
* Open new IrLAP layer instance, now that everything should be
* initialized properly
*/
self->irlap = irlap_open(dev, &self->qos, tty->name);
return 0;
}
static int irtty_net_close(struct net_device *dev)
{
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(self, TRUE);
/* Stop device */
netif_stop_queue(dev);
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
self->irlap = NULL;
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;
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(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
/* Locking :
* irda_device_dongle_init() can't be locked.
* irda_task_execute() doesn't need to be locked (but
* irtty_change_speed() should protect itself).
* Other calls protect themselves.
* Jean II
*/
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else
irda_task_execute(self, irtty_change_speed, NULL, NULL,
(void *) irq->ifr_baudrate);
break;
case SIOCSDONGLE: /* Set dongle */
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
/* 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;
/* Now initialize the dongle!
* Safe to do unlocked : self->dongle is still NULL. */
dongle->issue->open(dongle, &self->qos);
/* Reset dongle */
irda_task_execute(dongle, dongle->issue->reset, NULL, NULL,
NULL);
/* Make dongle available to driver only now to avoid
* race conditions - Jean II */
self->dongle = dongle;
break;
case SIOCSMEDIABUSY: /* Set media busy */
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else
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:
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else {
irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
}
break;
case SIOCSMODE:
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else {
irtty_set_mode(dev, irq->ifr_mode);
}
break;
default:
ret = -EOPNOTSUPP;
}
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;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("IrDA TTY device driver");
MODULE_LICENSE("GPL");
MODULE_PARM(qos_mtt_bits, "i");
MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
/*
* Function init_module (void)
*
* Initialize IrTTY module
*
*/
module_init(irtty_init);
/*
* Function cleanup_module (void)
*
* Cleanup IrTTY module
*
*/
module_exit(irtty_cleanup);
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