diff options
Diffstat (limited to 'drivers/usb/serial/oti6858.c')
| -rw-r--r-- | drivers/usb/serial/oti6858.c | 664 |
1 files changed, 149 insertions, 515 deletions
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 7de54781fe6..a4b88bc038b 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -39,7 +39,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -51,42 +50,20 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/uaccess.h> +#include <linux/kfifo.h> #include "oti6858.h" #define OTI6858_DESCRIPTION \ "Ours Technology Inc. OTi-6858 USB to serial adapter driver" #define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>" -#define OTI6858_VERSION "0.1" -static struct usb_device_id id_table [] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) }, { } }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver oti6858_driver = { - .name = "oti6858", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static int debug; - - -/* buffering code, copied from pl2303 driver */ -#define PL2303_BUF_SIZE 1024 -#define PL2303_TMP_BUF_SIZE 1024 - -struct oti6858_buf { - unsigned int buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - /* requests */ #define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00) #define OTI6858_REQ_T_GET_STATUS 0x01 @@ -125,6 +102,7 @@ struct oti6858_control_pkt { #define TX_BUFFER_EMPTIED 0x09 u8 pin_state; #define PIN_MASK 0x3f +#define PIN_MSR_MASK 0x1b #define PIN_RTS 0x20 /* output pin */ #define PIN_CTS 0x10 /* input pin, active low */ #define PIN_DSR 0x08 /* input pin, active low */ @@ -141,13 +119,11 @@ struct oti6858_control_pkt { && ((a)->frame_fmt == (priv)->pending_setup.frame_fmt)) /* function prototypes */ -static int oti6858_open(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port); static void oti6858_close(struct usb_serial_port *port); static void oti6858_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static int oti6858_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); +static void oti6858_init_termios(struct tty_struct *tty); static void oti6858_read_int_callback(struct urb *urb); static void oti6858_read_bulk_callback(struct urb *urb); static void oti6858_write_bulk_callback(struct urb *urb); @@ -155,23 +131,11 @@ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int oti6858_write_room(struct tty_struct *tty); static int oti6858_chars_in_buffer(struct tty_struct *tty); -static int oti6858_tiocmget(struct tty_struct *tty, struct file *file); -static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, +static int oti6858_tiocmget(struct tty_struct *tty); +static int oti6858_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int oti6858_startup(struct usb_serial *serial); -static void oti6858_shutdown(struct usb_serial *serial); - -/* functions operating on buffers */ -static struct oti6858_buf *oti6858_buf_alloc(unsigned int size); -static void oti6858_buf_free(struct oti6858_buf *pb); -static void oti6858_buf_clear(struct oti6858_buf *pb); -static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb); -static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb); -static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, - unsigned int count); -static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, - unsigned int count); - +static int oti6858_port_probe(struct usb_serial_port *port); +static int oti6858_port_remove(struct usb_serial_port *port); /* device info */ static struct usb_serial_driver oti6858_device = { @@ -184,29 +148,32 @@ static struct usb_serial_driver oti6858_device = { .open = oti6858_open, .close = oti6858_close, .write = oti6858_write, - .ioctl = oti6858_ioctl, .set_termios = oti6858_set_termios, + .init_termios = oti6858_init_termios, .tiocmget = oti6858_tiocmget, .tiocmset = oti6858_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, .read_bulk_callback = oti6858_read_bulk_callback, .read_int_callback = oti6858_read_int_callback, .write_bulk_callback = oti6858_write_bulk_callback, .write_room = oti6858_write_room, .chars_in_buffer = oti6858_chars_in_buffer, - .attach = oti6858_startup, - .shutdown = oti6858_shutdown, + .port_probe = oti6858_port_probe, + .port_remove = oti6858_port_remove, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &oti6858_device, NULL }; struct oti6858_private { spinlock_t lock; - struct oti6858_buf *buf; struct oti6858_control_pkt status; struct { u8 read_urb_in_use; u8 write_urb_in_use; - u8 termios_initialized; } flags; struct delayed_work delayed_write_work; @@ -219,7 +186,6 @@ struct oti6858_private { u8 setup_done; struct delayed_work delayed_setup_work; - wait_queue_head_t intr_wait; struct usb_serial_port *port; /* USB port with which associated */ }; @@ -232,11 +198,8 @@ static void setup_line(struct work_struct *work) unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); - if (new_setup == NULL) { - dev_err(&port->dev, "%s(): out of memory!\n", __func__); + if (!new_setup) { /* we will try again */ schedule_delayed_work(&priv->delayed_setup_work, msecs_to_jiffies(2)); @@ -286,25 +249,22 @@ static void setup_line(struct work_struct *work) priv->setup_done = 1; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s(): submitting interrupt urb", __func__); - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); } } -void send_data(struct work_struct *work) +static void send_data(struct work_struct *work) { struct oti6858_private *priv = container_of(work, struct oti6858_private, delayed_write_work.work); struct usb_serial_port *port = priv->port; int count = 0, result; unsigned long flags; - unsigned char allow; - - dbg("%s(port = %d)", __func__, port->number); + u8 *allow; spin_lock_irqsave(&priv->lock, flags); if (priv->flags.write_urb_in_use) { @@ -314,103 +274,93 @@ void send_data(struct work_struct *work) return; } priv->flags.write_urb_in_use = 1; - - count = oti6858_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); + + spin_lock_irqsave(&port->lock, flags); + count = kfifo_len(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); + if (count > port->bulk_out_size) count = port->bulk_out_size; if (count != 0) { + allow = kmalloc(1, GFP_KERNEL); + if (!allow) + return; + result = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), OTI6858_REQ_T_CHECK_TXBUFF, OTI6858_REQ_CHECK_TXBUFF, - count, 0, &allow, 1, 100); - if (result != 1 || allow != 0) + count, 0, allow, 1, 100); + if (result != 1 || *allow != 0) count = 0; + kfree(allow); } if (count == 0) { priv->flags.write_urb_in_use = 0; - dbg("%s(): submitting interrupt urb", __func__); - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); + result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); } return; } - spin_lock_irqsave(&priv->lock, flags); - oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count); - spin_unlock_irqrestore(&priv->lock, flags); - + count = kfifo_out_locked(&port->write_fifo, + port->write_urb->transfer_buffer, + count, &port->lock); port->write_urb->transfer_buffer_length = count; - port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + result = usb_submit_urb(port->write_urb, GFP_NOIO); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err_console(port, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); priv->flags.write_urb_in_use = 0; } usb_serial_port_softint(port); } -static int oti6858_startup(struct usb_serial *serial) +static int oti6858_port_probe(struct usb_serial_port *port) { - struct usb_serial_port *port = serial->port[0]; struct oti6858_private *priv; - int i; - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL); - if (!priv) - break; - priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE); - if (priv->buf == NULL) { - kfree(priv); - break; - } - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->intr_wait); -/* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */ -/* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */ - priv->port = port; - INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line); - INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - usb_set_serial_port_data(serial->port[i], priv); - } - if (i == serial->num_ports) - return 0; - - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - oti6858_buf_free(priv->buf); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; + spin_lock_init(&priv->lock); + priv->port = port; + INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line); + INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); + + usb_set_serial_port_data(port, priv); + + port->port.drain_delay = 256; /* FIXME: check the FIFO length */ + + return 0; } -static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) +static int oti6858_port_remove(struct usb_serial_port *port) { - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; + struct oti6858_private *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); - dbg("%s(port = %d, count = %d)", __func__, port->number, count); + return 0; +} +static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ if (!count) return count; - spin_lock_irqsave(&priv->lock, flags); - count = oti6858_buf_put(priv->buf, buf, count); - spin_unlock_irqrestore(&priv->lock, flags); + count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); return count; } @@ -418,15 +368,12 @@ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, static int oti6858_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct oti6858_private *priv = usb_get_serial_port_data(port); int room = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - room = oti6858_buf_space_avail(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&port->lock, flags); + room = kfifo_avail(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); return room; } @@ -434,19 +381,24 @@ static int oti6858_write_room(struct tty_struct *tty) static int oti6858_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct oti6858_private *priv = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - chars = oti6858_buf_data_avail(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&port->lock, flags); + chars = kfifo_len(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); return chars; } +static void oti6858_init_termios(struct tty_struct *tty) +{ + tty->termios = tty_std_termios; + tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios.c_ispeed = 38400; + tty->termios.c_ospeed = 38400; +} + static void oti6858_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -457,24 +409,7 @@ static void oti6858_set_termios(struct tty_struct *tty, __le16 divisor; int br; - dbg("%s(port = %d)", __func__, port->number); - - if (!tty) { - dbg("%s(): no tty structures", __func__); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - if (!priv->flags.termios_initialized) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 38400; - tty->termios->c_ospeed = 38400; - priv->flags.termios_initialized = 1; - } - spin_unlock_irqrestore(&priv->lock, flags); - - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; spin_lock_irqsave(&priv->lock, flags); divisor = priv->pending_setup.divisor; @@ -566,29 +501,20 @@ static void oti6858_set_termios(struct tty_struct *tty, spin_unlock_irqrestore(&priv->lock, flags); } -static int oti6858_open(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) { struct oti6858_private *priv = usb_get_serial_port_data(port); - struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct oti6858_control_pkt *buf; unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - if (port->port.count != 1) - return 0; - buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); - if (buf == NULL) { - dev_err(&port->dev, "%s(): out of memory!\n", __func__); + if (!buf) return -ENOMEM; - } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), OTI6858_REQ_T_GET_STATUS, @@ -615,20 +541,19 @@ static int oti6858_open(struct tty_struct *tty, spin_unlock_irqrestore(&priv->lock, flags); kfree(buf); - dbg("%s(): submitting interrupt urb", __func__); - port->interrupt_in_urb->dev = serial->dev; + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); oti6858_close(port); - return -EPROTO; + return result; } /* setup termios */ if (tty) - oti6858_set_termios(tty, port, &tmp_termios); - port->port.drain_delay = 256; /* FIXME: check the FIFO length */ + oti6858_set_termios(tty, port, NULL); + return 0; } @@ -637,28 +562,25 @@ static void oti6858_close(struct usb_serial_port *port) struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&port->lock, flags); /* clear out any remaining data in the buffer */ - oti6858_buf_clear(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); + kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); - dbg("%s(): after buf_clear()", __func__); + dev_dbg(&port->dev, "%s(): after buf_clear()\n", __func__); /* cancel scheduled setup */ - cancel_delayed_work(&priv->delayed_setup_work); - cancel_delayed_work(&priv->delayed_write_work); - flush_scheduled_work(); + cancel_delayed_work_sync(&priv->delayed_setup_work); + cancel_delayed_work_sync(&priv->delayed_write_work); /* shutdown our urbs */ - dbg("%s(): shutting down urbs", __func__); + dev_dbg(&port->dev, "%s(): shutting down urbs\n", __func__); usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); } -static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, +static int oti6858_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -666,11 +588,8 @@ static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, unsigned long flags; u8 control; - dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)", - __func__, port->number, set, clear); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; + dev_dbg(&port->dev, "%s(set = 0x%08x, clear = 0x%08x)\n", + __func__, set, clear); /* FIXME: check if this is correct (active high/low) */ spin_lock_irqsave(&priv->lock, flags); @@ -691,7 +610,7 @@ static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int oti6858_tiocmget(struct tty_struct *tty, struct file *file) +static int oti6858_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct oti6858_private *priv = usb_get_serial_port_data(port); @@ -699,11 +618,6 @@ static int oti6858_tiocmget(struct tty_struct *tty, struct file *file) unsigned pin_state; unsigned result = 0; - dbg("%s(port = %d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); pin_state = priv->status.pin_state & PIN_MASK; spin_unlock_irqrestore(&priv->lock, flags); @@ -722,83 +636,11 @@ static int oti6858_tiocmget(struct tty_struct *tty, struct file *file) if ((pin_state & PIN_DCD) != 0) result |= TIOCM_CD; - dbg("%s() = 0x%08x", __func__, result); + dev_dbg(&port->dev, "%s() = 0x%08x\n", __func__, result); return result; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prev, status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prev = priv->status.pin_state; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - wait_event_interruptible(priv->intr_wait, - priv->status.pin_state != prev); - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->status.pin_state & PIN_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prev ^ status; - /* FIXME: check if this is correct (active high/low) */ - if (((arg & TIOCM_RNG) && (changed & PIN_RI)) || - ((arg & TIOCM_DSR) && (changed & PIN_DSR)) || - ((arg & TIOCM_CD) && (changed & PIN_DCD)) || - ((arg & TIOCM_CTS) && (changed & PIN_CTS))) - return 0; - prev = status; - } - - /* NOTREACHED */ - return 0; -} - -static int oti6858_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)", - __func__, port->number, cmd, arg); - - switch (cmd) { - case TIOCMIWAIT: - dbg("%s(): TIOCMIWAIT", __func__); - return wait_modem_info(port, arg); - default: - dbg("%s(): 0x%04x not supported", __func__, cmd); - break; - } - return -ENOIOCTLCMD; -} - - -static void oti6858_shutdown(struct usb_serial *serial) -{ - struct oti6858_private *priv; - int i; - - dbg("%s()", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - oti6858_buf_free(priv->buf); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - } -} - static void oti6858_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -806,9 +648,6 @@ static void oti6858_read_int_callback(struct urb *urb) int transient = 0, can_recv = 0, resubmit = 1; int status = urb->status; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -817,12 +656,12 @@ static void oti6858_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s(): nonzero urb status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): nonzero urb status received: %d\n", + __func__, status); break; } @@ -838,8 +677,7 @@ static void oti6858_read_int_callback(struct urb *urb) priv->transient = 4; priv->setup_done = 0; resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); + dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__); schedule_delayed_work(&priv->delayed_setup_work, 0); } } @@ -853,16 +691,28 @@ static void oti6858_read_int_callback(struct urb *urb) priv->transient = 4; priv->setup_done = 0; resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); + dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__); schedule_delayed_work(&priv->delayed_setup_work, 0); } } } if (!priv->transient) { - if (xs->pin_state != priv->status.pin_state) - wake_up_interruptible(&priv->intr_wait); + u8 delta = xs->pin_state ^ priv->status.pin_state; + + if (delta & PIN_MSR_MASK) { + if (delta & PIN_CTS) + port->icount.cts++; + if (delta & PIN_DSR) + port->icount.dsr++; + if (delta & PIN_RI) + port->icount.rng++; + if (delta & PIN_DCD) + port->icount.dcd++; + + wake_up_interruptible(&port->port.delta_msr_wait); + } + memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE); } @@ -878,7 +728,6 @@ static void oti6858_read_int_callback(struct urb *urb) if (can_recv) { int result; - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result != 0) { priv->flags.read_urb_in_use = 0; @@ -889,10 +738,14 @@ static void oti6858_read_int_callback(struct urb *urb) } } else if (!transient) { unsigned long flags; + int count; + + spin_lock_irqsave(&port->lock, flags); + count = kfifo_len(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); spin_lock_irqsave(&priv->lock, flags); - if (priv->flags.write_urb_in_use == 0 - && oti6858_buf_data_avail(priv->buf) != 0) { + if (priv->flags.write_urb_in_use == 0 && count != 0) { schedule_delayed_work(&priv->delayed_write_work, 0); resubmit = 0; } @@ -902,8 +755,7 @@ static void oti6858_read_int_callback(struct urb *urb) if (resubmit) { int result; -/* dbg("%s(): submitting interrupt urb", __func__); */ - urb->dev = port->serial->dev; +/* dev_dbg(&urb->dev->dev, "%s(): submitting interrupt urb\n", __func__); */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result != 0) { dev_err(&urb->dev->dev, @@ -917,55 +769,30 @@ static void oti6858_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct oti6858_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - spin_lock_irqsave(&priv->lock, flags); priv->flags.read_urb_in_use = 0; spin_unlock_irqrestore(&priv->lock, flags); if (status != 0) { - if (!port->port.count) { - dbg("%s(): port is closed, exiting", __func__); - return; - } - /* - if (status == -EPROTO) { - * PL2303 mysteriously fails with -EPROTO reschedule - the read * - dbg("%s - caught -EPROTO, resubmitting the urb", - __func__); - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); - return; - } - */ - dbg("%s(): unable to handle the error, exiting", __func__); + dev_dbg(&urb->dev->dev, "%s(): unable to handle the error, exiting\n", __func__); return; } - tty = tty_port_tty_get(&port->port); - if (tty != NULL && urb->actual_length > 0) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + if (urb->actual_length > 0) { + tty_insert_flip_string(&port->port, data, urb->actual_length); + tty_flip_buffer_push(&port->port); } - tty_kref_put(tty); - /* schedule the interrupt urb if we are still open */ - if (port->port.count != 0) { - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed," - " error %d\n", __func__, result); - } + /* schedule the interrupt urb */ + result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + if (result != 0 && result != -EPERM) { + dev_err(&port->dev, "%s(): usb_submit_urb() failed," + " error %d\n", __func__, result); } } @@ -976,9 +803,6 @@ static void oti6858_write_bulk_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -987,21 +811,18 @@ static void oti6858_write_bulk_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n", __func__, status); priv->flags.write_urb_in_use = 0; return; default: /* error in the urb, so we have to resubmit it */ - dbg("%s(): nonzero write bulk status received: %d", - __func__, status); - dbg("%s(): overflow in write", __func__); + dev_dbg(&urb->dev->dev, "%s(): nonzero write bulk status received: %d\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s(): overflow in write\n", __func__); port->write_urb->transfer_buffer_length = 1; - port->write_urb->dev = port->serial->dev; result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed," + dev_err_console(port, "%s(): usb_submit_urb() failed," " error %d\n", __func__, result); } else { return; @@ -1011,8 +832,7 @@ static void oti6858_write_bulk_callback(struct urb *urb) priv->flags.write_urb_in_use = 0; /* schedule the interrupt urb if we are still open */ - port->interrupt_in_urb->dev = port->serial->dev; - dbg("%s(): submitting interrupt urb", __func__); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result != 0) { dev_err(&port->dev, "%s(): failed submitting int urb," @@ -1020,194 +840,8 @@ static void oti6858_write_bulk_callback(struct urb *urb) } } - -/* - * oti6858_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ -static struct oti6858_buf *oti6858_buf_alloc(unsigned int size) -{ - struct oti6858_buf *pb; - - if (size == 0) - return NULL; - - pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL); - if (pb == NULL) - return NULL; - - pb->buf_buf = kmalloc(size, GFP_KERNEL); - if (pb->buf_buf == NULL) { - kfree(pb); - return NULL; - } - - pb->buf_size = size; - pb->buf_get = pb->buf_put = pb->buf_buf; - - return pb; -} - -/* - * oti6858_buf_free - * - * Free the buffer and all associated memory. - */ -static void oti6858_buf_free(struct oti6858_buf *pb) -{ - if (pb) { - kfree(pb->buf_buf); - kfree(pb); - } -} - -/* - * oti6858_buf_clear - * - * Clear out all data in the circular buffer. - */ -static void oti6858_buf_clear(struct oti6858_buf *pb) -{ - if (pb != NULL) { - /* equivalent to a get of all data available */ - pb->buf_get = pb->buf_put; - } -} - -/* - * oti6858_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ -static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb) -{ - if (pb == NULL) - return 0; - return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size; -} - -/* - * oti6858_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ -static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb) -{ - if (pb == NULL) - return 0; - return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size; -} - -/* - * oti6858_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ -static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL) - return 0; - - len = oti6858_buf_space_avail(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_put; - if (count > len) { - memcpy(pb->buf_put, buf, len); - memcpy(pb->buf_buf, buf+len, count - len); - pb->buf_put = pb->buf_buf + count - len; - } else { - memcpy(pb->buf_put, buf, count); - if (count < len) - pb->buf_put += count; - else /* count == len */ - pb->buf_put = pb->buf_buf; - } - - return count; -} - -/* - * oti6858_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ -static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL) - return 0; - - len = oti6858_buf_data_avail(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_get; - if (count > len) { - memcpy(buf, pb->buf_get, len); - memcpy(buf+len, pb->buf_buf, count - len); - pb->buf_get = pb->buf_buf + count - len; - } else { - memcpy(buf, pb->buf_get, count); - if (count < len) - pb->buf_get += count; - else /* count == len */ - pb->buf_get = pb->buf_buf; - } - - return count; -} - -/* module description and (de)initialization */ - -static int __init oti6858_init(void) -{ - int retval; - - retval = usb_serial_register(&oti6858_device); - if (retval == 0) { - retval = usb_register(&oti6858_driver); - if (retval) - usb_serial_deregister(&oti6858_device); - } - return retval; -} - -static void __exit oti6858_exit(void) -{ - usb_deregister(&oti6858_driver); - usb_serial_deregister(&oti6858_device); -} - -module_init(oti6858_init); -module_exit(oti6858_exit); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(OTI6858_DESCRIPTION); MODULE_AUTHOR(OTI6858_AUTHOR); -MODULE_VERSION(OTI6858_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "enable debug output"); - |
