X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fusb%2Fserial%2Fpl2303.c;h=c28b1607eacc961973e2eb054742765eeacfcfdd;hb=3374cd1abd478f767aaedf2c21d109596ff0fe72;hp=f8f4e93e8c0bcb64a917baa4f35b7361d518abff;hpb=269bda1c123c7caf88e1deb2264f9086f0344192;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f8f4e93..c28b160 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1,20 +1,20 @@ /* * Prolific PL2303 USB to serial adaptor driver * - * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2003 IBM Corp. * * Original driver for 2.2.x by anonymous * - * 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. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. * - * See Documentation/usb/usb-serial.txt for more information on using this driver + * See Documentation/usb/usb-serial.txt for more information on using this + * driver * */ -#include #include #include #include @@ -26,15 +26,14 @@ #include #include #include -#include +#include #include -#include "usb-serial.h" +#include #include "pl2303.h" /* * Version Information */ -#define DRIVER_VERSION "v0.12" #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" static int debug; @@ -44,8 +43,6 @@ static int debug; #define PL2303_BUF_SIZE 1024 #define PL2303_TMP_BUF_SIZE 1024 -static DECLARE_MUTEX(pl2303_tmp_buf_sem); - struct pl2303_buf { unsigned int buf_size; char *buf_buf; @@ -53,17 +50,24 @@ struct pl2303_buf { char *buf_put; }; -static struct usb_device_id id_table [] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, @@ -72,20 +76,43 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, - { USB_DEVICE( NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID ) }, + { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, + { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, + { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, + { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, + { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, + { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, + { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, + { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, + { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, + { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, + { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, + { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, + { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, + { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, id_table); +MODULE_DEVICE_TABLE(usb, id_table); static struct usb_driver pl2303_driver = { - .owner = THIS_MODULE, .name = "pl2303", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, + .suspend = usb_serial_suspend, + .resume = usb_serial_resume, + .no_dynamic_id = 1, + .supports_autosuspend = 1, }; #define SET_LINE_REQUEST_TYPE 0x21 @@ -97,7 +124,7 @@ static struct usb_driver pl2303_driver = { #define CONTROL_RTS 0x02 #define BREAK_REQUEST_TYPE 0x21 -#define BREAK_REQUEST 0x23 +#define BREAK_REQUEST 0x23 #define BREAK_ON 0xffff #define BREAK_OFF 0x0000 @@ -121,65 +148,6 @@ static struct usb_driver pl2303_driver = { #define UART_OVERRUN_ERROR 0x40 #define UART_CTS 0x80 -/* function prototypes for a PL2303 serial converter */ -static int pl2303_open (struct usb_serial_port *port, struct file *filp); -static void pl2303_close (struct usb_serial_port *port, struct file *filp); -static void pl2303_set_termios (struct usb_serial_port *port, - struct termios *old); -static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg); -static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs); -static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs); -static int pl2303_write (struct usb_serial_port *port, - const unsigned char *buf, int count); -static void pl2303_send (struct usb_serial_port *port); -static int pl2303_write_room(struct usb_serial_port *port); -static int pl2303_chars_in_buffer(struct usb_serial_port *port); -static void pl2303_break_ctl(struct usb_serial_port *port,int break_state); -static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file); -static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, - unsigned int set, unsigned int clear); -static int pl2303_startup (struct usb_serial *serial); -static void pl2303_shutdown (struct usb_serial *serial); -static struct pl2303_buf *pl2303_buf_alloc(unsigned int size); -static void pl2303_buf_free(struct pl2303_buf *pb); -static void pl2303_buf_clear(struct pl2303_buf *pb); -static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb); -static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb); -static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, - unsigned int count); -static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, - unsigned int count); - - -/* All of the device info needed for the PL2303 SIO serial converter */ -static struct usb_serial_driver pl2303_device = { - .driver = { - .owner = THIS_MODULE, - .name = "pl2303", - }, - .id_table = id_table, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = pl2303_open, - .close = pl2303_close, - .write = pl2303_write, - .ioctl = pl2303_ioctl, - .break_ctl = pl2303_break_ctl, - .set_termios = pl2303_set_termios, - .tiocmget = pl2303_tiocmget, - .tiocmset = pl2303_tiocmset, - .read_bulk_callback = pl2303_read_bulk_callback, - .read_int_callback = pl2303_read_int_callback, - .write_bulk_callback = pl2303_write_bulk_callback, - .write_room = pl2303_write_room, - .chars_in_buffer = pl2303_chars_in_buffer, - .attach = pl2303_startup, - .shutdown = pl2303_shutdown, -}; enum pl2303_type { type_0, /* don't know the difference between type 0 and */ @@ -194,17 +162,201 @@ struct pl2303_private { wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; - u8 termios_initialized; enum pl2303_type type; }; +/* + * pl2303_buf_alloc + * + * Allocate a circular buffer and all associated memory. + */ +static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) +{ + struct pl2303_buf *pb; + + if (size == 0) + return NULL; + + pb = kmalloc(sizeof(struct pl2303_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; +} + +/* + * pl2303_buf_free + * + * Free the buffer and all associated memory. + */ +static void pl2303_buf_free(struct pl2303_buf *pb) +{ + if (pb) { + kfree(pb->buf_buf); + kfree(pb); + } +} + +/* + * pl2303_buf_clear + * + * Clear out all data in the circular buffer. + */ +static void pl2303_buf_clear(struct pl2303_buf *pb) +{ + if (pb != NULL) + pb->buf_get = pb->buf_put; + /* equivalent to a get of all data available */ +} + +/* + * pl2303_buf_data_avail + * + * Return the number of bytes of data available in the circular + * buffer. + */ +static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) +{ + if (pb == NULL) + return 0; + + return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size; +} + +/* + * pl2303_buf_space_avail + * + * Return the number of bytes of space available in the circular + * buffer. + */ +static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) +{ + if (pb == NULL) + return 0; + + return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size; +} + +/* + * pl2303_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 pl2303_buf_put(struct pl2303_buf *pb, const char *buf, + unsigned int count) +{ + unsigned int len; + + if (pb == NULL) + return 0; + + len = pl2303_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; +} + +/* + * pl2303_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 pl2303_buf_get(struct pl2303_buf *pb, char *buf, + unsigned int count) +{ + unsigned int len; + + if (pb == NULL) + return 0; + + len = pl2303_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; +} + +static int pl2303_vendor_read(__u16 value, __u16 index, + struct usb_serial *serial, unsigned char *buf) +{ + int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, + value, index, buf, 1, 100); + dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, + VENDOR_READ_REQUEST, value, index, res, buf[0]); + return res; +} -static int pl2303_startup (struct usb_serial *serial) +static int pl2303_vendor_write(__u16 value, __u16 index, + struct usb_serial *serial) +{ + int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, + value, index, NULL, 0, 100); + dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, + VENDOR_WRITE_REQUEST, value, index, res); + return res; +} + +static int pl2303_startup(struct usb_serial *serial) { struct pl2303_private *priv; enum pl2303_type type = type_0; + unsigned char *buf; int i; + buf = kmalloc(10, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + if (serial->dev->descriptor.bDeviceClass == 0x02) type = type_0; else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) @@ -216,10 +368,9 @@ static int pl2303_startup (struct usb_serial *serial) dbg("device type: %d", type); for (i = 0; i < serial->num_ports; ++i) { - priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); if (!priv) goto cleanup; - memset (priv, 0x00, sizeof (struct pl2303_private)); spin_lock_init(&priv->lock); priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); if (priv->buf == NULL) { @@ -230,10 +381,28 @@ static int pl2303_startup (struct usb_serial *serial) priv->type = type; usb_set_serial_port_data(serial->port[i], priv); } + + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_write(0x0404, 0, serial); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_read(0x8383, 0, serial, buf); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_write(0x0404, 1, serial); + pl2303_vendor_read(0x8484, 0, serial, buf); + pl2303_vendor_read(0x8383, 0, serial, buf); + pl2303_vendor_write(0, 1, serial); + pl2303_vendor_write(1, 0, serial); + if (type == HX) + pl2303_vendor_write(2, 0x44, serial); + else + pl2303_vendor_write(2, 0x24, serial); + + kfree(buf); return 0; cleanup: - for (--i; i>=0; --i) { + kfree(buf); + for (--i; i >= 0; --i) { priv = usb_get_serial_port_data(serial->port[i]); pl2303_buf_free(priv->buf); kfree(priv); @@ -242,34 +411,15 @@ cleanup: return -ENOMEM; } -static int set_control_lines (struct usb_device *dev, u8 value) +static int set_control_lines(struct usb_device *dev, u8 value) { int retval; - - retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0), - SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, - value, 0, NULL, 0, 100); - dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval); - return retval; -} - -static int pl2303_write (struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); - - if (!count) - return count; - - spin_lock_irqsave(&priv->lock, flags); - count = pl2303_buf_put(priv->buf, buf, count); - spin_unlock_irqrestore(&priv->lock, flags); - - pl2303_send(port); - return count; + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, + value, 0, NULL, 0, 100); + dbg("%s - value = %d, retval = %d", __func__, value, retval); + return retval; } static void pl2303_send(struct usb_serial_port *port) @@ -278,7 +428,7 @@ static void pl2303_send(struct usb_serial_port *port) struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); @@ -288,7 +438,7 @@ static void pl2303_send(struct usb_serial_port *port) } count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, - port->bulk_out_size); + port->bulk_out_size); if (count == 0) { spin_unlock_irqrestore(&priv->lock, flags); @@ -299,53 +449,77 @@ static void pl2303_send(struct usb_serial_port *port) spin_unlock_irqrestore(&priv->lock, flags); - usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __func__, count, + port->write_urb->transfer_buffer); 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_ATOMIC); if (result) { - dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); + dev_err(&port->dev, "%s - failed submitting write urb," + " error %d\n", __func__, result); priv->write_urb_in_use = 0; - // TODO: reschedule pl2303_send + /* TODO: reschedule pl2303_send */ } - schedule_work(&port->work); + usb_serial_port_softint(port); +} + +static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + dbg("%s - port %d, %d bytes", __func__, port->number, count); + + if (!count) + return count; + + spin_lock_irqsave(&priv->lock, flags); + count = pl2303_buf_put(priv->buf, buf, count); + spin_unlock_irqrestore(&priv->lock, flags); + + pl2303_send(port); + + return count; } -static int pl2303_write_room(struct usb_serial_port *port) +static int pl2303_write_room(struct tty_struct *tty) { + struct usb_serial_port *port = tty->driver_data; struct pl2303_private *priv = usb_get_serial_port_data(port); int room = 0; unsigned long flags; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); room = pl2303_buf_space_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - returns %d", __FUNCTION__, room); + dbg("%s - returns %d", __func__, room); return room; } -static int pl2303_chars_in_buffer(struct usb_serial_port *port) +static int pl2303_chars_in_buffer(struct tty_struct *tty) { + struct usb_serial_port *port = tty->driver_data; struct pl2303_private *priv = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); chars = pl2303_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - returns %d", __FUNCTION__, chars); + dbg("%s - returns %d", __func__, chars); return chars; } -static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void pl2303_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -355,81 +529,90 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol int baud; int i; u8 control; + const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, + 4800, 7200, 9600, 14400, 19200, 28800, 38400, + 57600, 115200, 230400, 460800, 614400, + 921600, 1228800, 2457600, 3000000, 6000000 }; + int baud_floor, baud_ceil; + int k; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); - if ((!port->tty) || (!port->tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } + /* The PL2303 is reported to lose bytes if you change + serial settings even to the same values as before. Thus + we actually need to filter in this specific case */ - spin_lock_irqsave(&priv->lock, flags); - if (!priv->termios_initialized) { - *(port->tty->termios) = tty_std_termios; - port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - priv->termios_initialized = 1; - } - spin_unlock_irqrestore(&priv->lock, flags); + if (!tty_termios_hw_change(tty->termios, old_termios)) + return; - cflag = port->tty->termios->c_cflag; - /* check that they really want us to change something */ - if (old_termios) { - if ((cflag == old_termios->c_cflag) && - (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { - dbg("%s - nothing to change...", __FUNCTION__); - return; - } - } + cflag = tty->termios->c_cflag; - buf = kmalloc (7, GFP_KERNEL); + buf = kzalloc(7, GFP_KERNEL); if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); + dev_err(&port->dev, "%s - out of memory.\n", __func__); + /* Report back no change occurred */ + *tty->termios = *old_termios; return; } - memset (buf, 0x00, 0x07); - - i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CSIZE) { switch (cflag & CSIZE) { - case CS5: buf[6] = 5; break; - case CS6: buf[6] = 6; break; - case CS7: buf[6] = 7; break; - default: - case CS8: buf[6] = 8; break; - } - dbg("%s - data bits = %d", __FUNCTION__, buf[6]); - } - - baud = 0; - switch (cflag & CBAUD) { - case B0: baud = 0; break; - case B75: baud = 75; break; - case B150: baud = 150; break; - case B300: baud = 300; break; - case B600: baud = 600; break; - case B1200: baud = 1200; break; - case B1800: baud = 1800; break; - case B2400: baud = 2400; break; - case B4800: baud = 4800; break; - case B9600: baud = 9600; break; - case B19200: baud = 19200; break; - case B38400: baud = 38400; break; - case B57600: baud = 57600; break; - case B115200: baud = 115200; break; - case B230400: baud = 230400; break; - case B460800: baud = 460800; break; + case CS5: + buf[6] = 5; + break; + case CS6: + buf[6] = 6; + break; + case CS7: + buf[6] = 7; + break; default: - dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n"); + case CS8: + buf[6] = 8; break; + } + dbg("%s - data bits = %d", __func__, buf[6]); } - dbg("%s - baud = %d", __FUNCTION__, baud); + + /* For reference buf[0]:buf[3] baud rate value */ + /* NOTE: Only the values defined in baud_sup are supported ! + * => if unsupported values are set, the PL2303 seems to use + * 9600 baud (at least my PL2303X always does) + */ + baud = tty_get_baud_rate(tty); + dbg("%s - baud requested = %d", __func__, baud); if (baud) { + /* Set baudrate to nearest supported value */ + for (k=0; k (baud % baud_floor)) + baud = baud_floor; + else + baud = baud_ceil; + } + break; + } + } + if (baud > 1228800) { + /* type_0, type_1 only support up to 1228800 baud */ + if (priv->type != HX) + baud = 1228800; + else if (baud > 6000000) + baud = 6000000; + } + dbg("%s - baud set = %d", __func__, baud); buf[0] = baud & 0xff; buf[1] = (baud >> 8) & 0xff; buf[2] = (baud >> 16) & 0xff; @@ -440,11 +623,19 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ if (cflag & CSTOPB) { - buf[4] = 2; - dbg("%s - stop bits = 2", __FUNCTION__); + /* NOTE: Comply with "real" UARTs / RS232: + * use 1.5 instead of 2 stop bits with 5 data bits + */ + if ((cflag & CSIZE) == CS5) { + buf[4] = 1; + dbg("%s - stop bits = 1.5", __func__); + } else { + buf[4] = 2; + dbg("%s - stop bits = 2", __func__); + } } else { buf[4] = 0; - dbg("%s - stop bits = 1", __FUNCTION__); + dbg("%s - stop bits = 1", __func__); } if (cflag & PARENB) { @@ -454,21 +645,31 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ if (cflag & PARODD) { - buf[5] = 1; - dbg("%s - parity = odd", __FUNCTION__); + if (cflag & CMSPAR) { + buf[5] = 3; + dbg("%s - parity = mark", __func__); + } else { + buf[5] = 1; + dbg("%s - parity = odd", __func__); + } } else { - buf[5] = 2; - dbg("%s - parity = even", __FUNCTION__); + if (cflag & CMSPAR) { + buf[5] = 4; + dbg("%s - parity = space", __func__); + } else { + buf[5] = 2; + dbg("%s - parity = even", __func__); + } } } else { buf[5] = 0; - dbg("%s - parity = none", __FUNCTION__); + dbg("%s - parity = none", __func__); } - i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg ("0x21:0x20:0:0 %d", i); + i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + dbg("0x21:0x20:0:0 %d", i); /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); @@ -484,179 +685,115 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol } else { spin_unlock_irqrestore(&priv->lock, flags); } - + buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; - i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { - __u16 index; if (priv->type == HX) - index = 0x61; + pl2303_vendor_write(0x0, 0x61, serial); else - index = 0x41; - i = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - VENDOR_WRITE_REQUEST, - VENDOR_WRITE_REQUEST_TYPE, - 0x0, index, NULL, 0, 100); - dbg ("0x40:0x1:0x0:0x%x %d", index, i); + pl2303_vendor_write(0x0, 0x41, serial); + } else { + pl2303_vendor_write(0x0, 0x0, serial); } - kfree (buf); + /* Save resulting baud rate */ + if (baud) + tty_encode_baud_rate(tty, baud, baud); + + kfree(buf); +} + +static void pl2303_dtr_rts(struct usb_serial_port *port, int on) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + u8 control; + + spin_lock_irqsave(&priv->lock, flags); + /* Change DTR and RTS */ + if (on) + priv->line_control |= (CONTROL_DTR | CONTROL_RTS); + else + priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); + control = priv->line_control; + spin_unlock_irqrestore(&priv->lock, flags); + set_control_lines(port->serial->dev, control); } -static int pl2303_open (struct usb_serial_port *port, struct file *filp) +static void pl2303_close(struct usb_serial_port *port) { - struct termios tmp_termios; + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + dbg("%s - port %d", __func__, port->number); + + spin_lock_irqsave(&priv->lock, flags); + /* clear out any remaining data in the buffer */ + pl2303_buf_clear(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); + + /* shutdown our urbs */ + dbg("%s - shutting down urbs", __func__); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->interrupt_in_urb); + +} + +static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned char *buf; int result; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); if (priv->type != HX) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - } - - buf = kmalloc(10, GFP_KERNEL); - if (buf==NULL) - return -ENOMEM; - -#define FISH(a,b,c,d) \ - result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ - b, a, c, d, buf, 1, 100); \ - dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]); - -#define SOUP(a,b,c,d) \ - result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \ - b, a, c, d, NULL, 0, 100); \ - dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result); - - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); - FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); - - if (priv->type == HX) { - /* HX chip */ - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); - /* reset upstream data pipes */ - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0); - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0); } else { - SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24); + /* reset upstream data pipes */ + pl2303_vendor_write(8, 0, serial); + pl2303_vendor_write(9, 0, serial); } - kfree(buf); - /* Setup termios */ - if (port->tty) { - pl2303_set_termios (port, &tmp_termios); - } - - //FIXME: need to assert RTS and DTR if CRTSCTS off + if (tty) + pl2303_set_termios(tty, port, &tmp_termios); - dbg("%s - submitting read urb", __FUNCTION__); - port->read_urb->dev = serial->dev; - result = usb_submit_urb (port->read_urb, GFP_KERNEL); + dbg("%s - submitting read urb", __func__); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) { - dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); - pl2303_close (port, NULL); + dev_err(&port->dev, "%s - failed submitting read urb," + " error %d\n", __func__, result); + pl2303_close(port); return -EPROTO; } - dbg("%s - submitting interrupt urb", __FUNCTION__); - port->interrupt_in_urb->dev = serial->dev; - result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL); + dbg("%s - submitting interrupt urb", __func__); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { - dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result); - pl2303_close (port, NULL); + dev_err(&port->dev, "%s - failed submitting interrupt urb," + " error %d\n", __func__, result); + pl2303_close(port); return -EPROTO; } + port->port.drain_delay = 256; return 0; } - -static void pl2303_close (struct usb_serial_port *port, struct file *filp) -{ - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int c_cflag; - int bps; - long timeout; - wait_queue_t wait; \ - - dbg("%s - port %d", __FUNCTION__, port->number); - - /* wait for data to drain from the buffer */ - spin_lock_irqsave(&priv->lock, flags); - timeout = PL2303_CLOSING_WAIT; - init_waitqueue_entry(&wait, current); - add_wait_queue(&port->tty->write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (pl2303_buf_data_avail(priv->buf) == 0 - || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->serial->interface)) /* disconnect */ - break; - spin_unlock_irqrestore(&priv->lock, flags); - timeout = schedule_timeout(timeout); - spin_lock_irqsave(&priv->lock, flags); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->tty->write_wait, &wait); - /* clear out any remaining data in the buffer */ - pl2303_buf_clear(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - - /* wait for characters to drain from the device */ - /* (this is long enough for the entire 256 byte */ - /* pl2303 hardware buffer to drain with no flow */ - /* control for data rates of 1200 bps or more, */ - /* for lower rates we should really know how much */ - /* data is in the buffer to compute a delay */ - /* that is not unnecessarily long) */ - bps = tty_get_baud_rate(port->tty); - if (bps > 1200) - timeout = max((HZ*2560)/bps,HZ/10); - else - timeout = 2*HZ; - schedule_timeout_interruptible(timeout); - - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __FUNCTION__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - - if (port->tty) { - c_cflag = port->tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop DTR and RTS */ - spin_lock_irqsave(&priv->lock, flags); - priv->line_control = 0; - spin_unlock_irqrestore (&priv->lock, flags); - set_control_lines (port->serial->dev, 0); - } - } -} - -static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, - unsigned int set, unsigned int clear) +static int pl2303_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) { + struct usb_serial_port *port = tty->driver_data; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; @@ -664,7 +801,7 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, if (!usb_get_intfdata(port->serial->interface)) return -ENODEV; - spin_lock_irqsave (&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) priv->line_control |= CONTROL_RTS; if (set & TIOCM_DTR) @@ -674,28 +811,29 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, if (clear & TIOCM_DTR) priv->line_control &= ~CONTROL_DTR; control = priv->line_control; - spin_unlock_irqrestore (&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); - return set_control_lines (port->serial->dev, control); + return set_control_lines(port->serial->dev, control); } -static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file) +static int pl2303_tiocmget(struct tty_struct *tty, struct file *file) { + struct usb_serial_port *port = tty->driver_data; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int mcr; unsigned int status; unsigned int result; - dbg("%s (%d)", __FUNCTION__, port->number); + dbg("%s (%d)", __func__, port->number); if (!usb_get_intfdata(port->serial->interface)) return -ENODEV; - spin_lock_irqsave (&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; - spin_unlock_irqrestore (&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) @@ -704,11 +842,19 @@ static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file) | ((status & UART_RING) ? TIOCM_RI : 0) | ((status & UART_DCD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __FUNCTION__, result); + dbg("%s - result = %x", __func__, result); return result; } +static int pl2303_carrier_raised(struct usb_serial_port *port) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + if (priv->line_status & UART_DCD) + return 1; + return 0; +} + static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) { struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -717,26 +863,26 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) unsigned int status; unsigned int changed; - spin_lock_irqsave (&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); prevstatus = priv->line_status; - spin_unlock_irqrestore (&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); while (1) { interruptible_sleep_on(&priv->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; - - spin_lock_irqsave (&priv->lock, flags); + + spin_lock_irqsave(&priv->lock, flags); status = priv->line_status; - spin_unlock_irqrestore (&priv->lock, flags); - - changed=prevstatus^status; - + spin_unlock_irqrestore(&priv->lock, flags); + + changed = prevstatus ^ status; + if (((arg & TIOCM_RNG) && (changed & UART_RING)) || ((arg & TIOCM_DSR) && (changed & UART_DSR)) || ((arg & TIOCM_CD) && (changed & UART_DCD)) || - ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) { + ((arg & TIOCM_CTS) && (changed & UART_CTS))) { return 0; } prevstatus = status; @@ -745,60 +891,73 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) return 0; } -static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) +static int pl2303_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd); + struct serial_struct ser; + struct usb_serial_port *port = tty->driver_data; + dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); switch (cmd) { - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); - return wait_modem_info(port, arg); + case TIOCGSERIAL: + memset(&ser, 0, sizeof ser); + ser.type = PORT_16654; + ser.line = port->serial->minor; + ser.port = port->number; + ser.baud_base = 460800; - default: - dbg("%s not supported = 0x%04x", __FUNCTION__, cmd); - break; - } + if (copy_to_user((void __user *)arg, &ser, sizeof ser)) + return -EFAULT; + + return 0; + case TIOCMIWAIT: + dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + return wait_modem_info(port, arg); + default: + dbg("%s not supported = 0x%04x", __func__, cmd); + break; + } return -ENOIOCTLCMD; } -static void pl2303_break_ctl (struct usb_serial_port *port, int break_state) +static void pl2303_break_ctl(struct tty_struct *tty, int break_state) { + struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; u16 state; int result; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); if (break_state == 0) state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); + dbg("%s - turning break %s", __func__, + state == BREAK_OFF ? "off" : "on"); - result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - BREAK_REQUEST, BREAK_REQUEST_TYPE, state, - 0, NULL, 0, 100); + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + BREAK_REQUEST, BREAK_REQUEST_TYPE, state, + 0, NULL, 0, 100); if (result) - dbg("%s - error sending break = %d", __FUNCTION__, result); + dbg("%s - error sending break = %d", __func__, result); } - -static void pl2303_shutdown (struct usb_serial *serial) +static void pl2303_release(struct usb_serial *serial) { int i; struct pl2303_private *priv; - dbg("%s", __FUNCTION__); + dbg("%s", __func__); for (i = 0; i < serial->num_ports; ++i) { priv = usb_get_serial_port_data(serial->port[i]); if (priv) { pl2303_buf_free(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); } - } + } } static void pl2303_update_line_status(struct usb_serial_port *port, @@ -809,36 +968,46 @@ static void pl2303_update_line_status(struct usb_serial_port *port, struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 status_idx = UART_STATE; - u8 length = UART_STATE; + u8 length = UART_STATE + 1; + u16 idv, idp; - if ((le16_to_cpu(port->serial->dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) && - (le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X65)) { - length = 1; - status_idx = 0; + idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); + idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); + + + if (idv == SIEMENS_VENDOR_ID) { + if (idp == SIEMENS_PRODUCT_ID_X65 || + idp == SIEMENS_PRODUCT_ID_SX1 || + idp == SIEMENS_PRODUCT_ID_X75) { + + length = 1; + status_idx = 0; + } } if (actual_length < length) - goto exit; + return; - /* Save off the uart status for others to look at */ + /* Save off the uart status for others to look at */ spin_lock_irqsave(&priv->lock, flags); priv->line_status = data[status_idx]; spin_unlock_irqrestore(&priv->lock, flags); - -exit: - return; + if (priv->line_status & UART_BREAK_ERROR) + usb_serial_handle_break(port); + wake_up_interruptible(&priv->delta_msr_wait); } -static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs) +static void pl2303_read_int_callback(struct urb *urb) { - struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; unsigned int actual_length = urb->actual_length; - int status; + int status = urb->status; + int retval; - dbg("%s (%d)", __FUNCTION__, port->number); + dbg("%s (%d)", __func__, port->number); - switch (urb->status) { + switch (status) { case 0: /* success */ break; @@ -846,116 +1015,121 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __func__, + status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __func__, + status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __func__, + urb->actual_length, urb->transfer_buffer); + pl2303_update_line_status(port, data, actual_length); exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n", - __FUNCTION__, status); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + dev_err(&urb->dev->dev, + "%s - usb_submit_urb failed with result %d\n", + __func__, retval); } +static void pl2303_push_data(struct tty_struct *tty, + struct usb_serial_port *port, struct urb *urb, + u8 line_status) +{ + unsigned char *data = urb->transfer_buffer; + /* get tty_flag from status */ + char tty_flag = TTY_NORMAL; + /* break takes precedence over parity, */ + /* which takes precedence over framing errors */ + if (line_status & UART_BREAK_ERROR) + tty_flag = TTY_BREAK; + else if (line_status & UART_PARITY_ERROR) + tty_flag = TTY_PARITY; + else if (line_status & UART_FRAME_ERROR) + tty_flag = TTY_FRAME; + dbg("%s - tty_flag = %d", __func__, tty_flag); + + /* overrun is special, not associated with a char */ + if (line_status & UART_OVERRUN_ERROR) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq)) + tty_insert_flip_string(tty, data, urb->actual_length); + else { + int i; + for (i = 0; i < urb->actual_length; ++i) + if (!usb_serial_handle_sysrq_char(tty, port, data[i])) + tty_insert_flip_char(tty, data[i], tty_flag); + } + tty_flip_buffer_push(tty); +} -static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void pl2303_read_bulk_callback(struct urb *urb) { - struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct usb_serial_port *port = urb->context; struct pl2303_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; unsigned long flags; - int i; int result; - u8 status; - char tty_flag; + int status = urb->status; + u8 line_status; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); - if (urb->status) { - dbg("%s - urb->status = %d", __FUNCTION__, urb->status); - if (!port->open_count) { - dbg("%s - port is closed, exiting.", __FUNCTION__); - return; - } - if (urb->status == -EPROTO) { - /* PL2303 mysteriously fails with -EPROTO reschedule the read */ - dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__); - urb->status = 0; - urb->dev = port->serial->dev; + if (status) { + dbg("%s - urb status = %d", __func__, status); + 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", __FUNCTION__, 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.", __FUNCTION__); + dbg("%s - unable to handle the error, exiting.", __func__); return; } - usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); - - /* get tty_flag from status */ - tty_flag = TTY_NORMAL; + usb_serial_debug_data(debug, &port->dev, __func__, + urb->actual_length, urb->transfer_buffer); spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; + line_status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible (&priv->delta_msr_wait); - - /* break takes precedence over parity, */ - /* which takes precedence over framing errors */ - if (status & UART_BREAK_ERROR ) - tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag); + wake_up_interruptible(&priv->delta_msr_wait); - tty = port->tty; + tty = tty_port_tty_get(&port->port); if (tty && urb->actual_length) { - /* overrun is special, not associated with a char */ - if (status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - - for (i = 0; i < urb->actual_length; ++i) { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(tty); - } - tty_insert_flip_char (tty, data[i], tty_flag); - } - tty_flip_buffer_push (tty); + pl2303_push_data(tty, port, urb, line_status); } - + tty_kref_put(tty); /* Schedule the next read _if_ we are still open */ - if (port->open_count) { - urb->dev = port->serial->dev; - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); - } - - return; + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result && result != -EPERM) + dev_err(&urb->dev->dev, "%s - failed resubmitting" + " read urb, error %d\n", __func__, result); } - - -static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void pl2303_write_bulk_callback(struct urb *urb) { - struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct usb_serial_port *port = urb->context; struct pl2303_private *priv = usb_get_serial_port_data(port); int result; + int status = urb->status; - dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - port %d", __func__, port->number); - switch (urb->status) { + switch (status) { case 0: /* success */ break; @@ -963,18 +1137,20 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __func__, + status); priv->write_urb_in_use = 0; return; default: /* error in the urb, so we have to resubmit it */ - dbg("%s - Overflow in write", __FUNCTION__); - dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); + dbg("%s - Overflow in write", __func__); + dbg("%s - nonzero write bulk status received: %d", __func__, + status); port->write_urb->transfer_buffer_length = 1; - port->write_urb->dev = port->serial->dev; - result = usb_submit_urb (port->write_urb, GFP_ATOMIC); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) - dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result); + dev_err(&urb->dev->dev, "%s - failed resubmitting write" + " urb, error %d\n", __func__, result); else return; } @@ -985,198 +1161,45 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs) pl2303_send(port); } +/* All of the device info needed for the PL2303 SIO serial converter */ +static struct usb_serial_driver pl2303_device = { + .driver = { + .owner = THIS_MODULE, + .name = "pl2303", + }, + .id_table = id_table, + .usb_driver = &pl2303_driver, + .num_ports = 1, + .open = pl2303_open, + .close = pl2303_close, + .dtr_rts = pl2303_dtr_rts, + .carrier_raised = pl2303_carrier_raised, + .write = pl2303_write, + .ioctl = pl2303_ioctl, + .break_ctl = pl2303_break_ctl, + .set_termios = pl2303_set_termios, + .tiocmget = pl2303_tiocmget, + .tiocmset = pl2303_tiocmset, + .read_bulk_callback = pl2303_read_bulk_callback, + .read_int_callback = pl2303_read_int_callback, + .write_bulk_callback = pl2303_write_bulk_callback, + .write_room = pl2303_write_room, + .chars_in_buffer = pl2303_chars_in_buffer, + .attach = pl2303_startup, + .release = pl2303_release, +}; -/* - * pl2303_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ - -static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) -{ - - struct pl2303_buf *pb; - - - if (size == 0) - return NULL; - - pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_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; - -} - - -/* - * pl2303_buf_free - * - * Free the buffer and all associated memory. - */ - -static void pl2303_buf_free(struct pl2303_buf *pb) -{ - if (pb) { - kfree(pb->buf_buf); - kfree(pb); - } -} - - -/* - * pl2303_buf_clear - * - * Clear out all data in the circular buffer. - */ - -static void pl2303_buf_clear(struct pl2303_buf *pb) -{ - if (pb != NULL) - pb->buf_get = pb->buf_put; - /* equivalent to a get of all data available */ -} - - -/* - * pl2303_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ - -static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) -{ - if (pb != NULL) - return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size); - else - return 0; -} - - -/* - * pl2303_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ - -static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) -{ - if (pb != NULL) - return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size); - else - return 0; -} - - -/* - * pl2303_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 pl2303_buf_put(struct pl2303_buf *pb, const char *buf, - unsigned int count) -{ - - unsigned int len; - - - if (pb == NULL) - return 0; - - len = pl2303_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; - -} - - -/* - * pl2303_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 pl2303_buf_get(struct pl2303_buf *pb, char *buf, - unsigned int count) -{ - - unsigned int len; - - - if (pb == NULL) - return 0; - - len = pl2303_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; - -} - -static int __init pl2303_init (void) +static int __init pl2303_init(void) { int retval; + retval = usb_serial_register(&pl2303_device); if (retval) goto failed_usb_serial_register; retval = usb_register(&pl2303_driver); if (retval) goto failed_usb_register; - info(DRIVER_DESC " " DRIVER_VERSION); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); return 0; failed_usb_register: usb_serial_deregister(&pl2303_device); @@ -1184,19 +1207,16 @@ failed_usb_serial_register: return retval; } - -static void __exit pl2303_exit (void) +static void __exit pl2303_exit(void) { - usb_deregister (&pl2303_driver); - usb_serial_deregister (&pl2303_device); + usb_deregister(&pl2303_driver); + usb_serial_deregister(&pl2303_device); } - module_init(pl2303_init); module_exit(pl2303_exit); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR);