VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / usb / serial / pl2303.c
index 81f712c..af0d230 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Prolific PL2303 USB to serial adaptor driver
  *
- * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2003 IBM Corp.
  *
  * Original driver for 2.2.x by anonymous
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
-       static int debug = 1;
-#else
-       static int debug;
-#endif
-
 #include "usb-serial.h"
 #include "pl2303.h"
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.10"
+#define DRIVER_VERSION "v0.11"
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
-
+static int debug;
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
@@ -80,6 +74,8 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
        { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
        { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
+       { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
+       { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -170,20 +166,38 @@ static struct usb_serial_device_type pl2303_device = {
        .shutdown =             pl2303_shutdown,
 };
 
+enum pl2303_type {
+       type_0,         /* don't know the difference between type 0 and */
+       type_1,         /* type 1, until someone from prolific tells us... */
+       HX,             /* HX version of the pl2303 chip */
+};
+
 struct pl2303_private {
        spinlock_t lock;
        wait_queue_head_t delta_msr_wait;
        u8 line_control;
        u8 line_status;
        u8 termios_initialized;
+       enum pl2303_type type;
 };
 
 
 static int pl2303_startup (struct usb_serial *serial)
 {
        struct pl2303_private *priv;
+       enum pl2303_type type = type_0;
        int i;
 
+       if (serial->dev->descriptor.bDeviceClass == 0x02)
+               type = type_0;
+       else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
+               type = HX;
+       else if (serial->dev->descriptor.bDeviceClass == 0x00)
+               type = type_1;
+       else if (serial->dev->descriptor.bDeviceClass == 0xFF)
+               type = type_1;
+       dbg("device type: %d", type);
+
        for (i = 0; i < serial->num_ports; ++i) {
                priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
                if (!priv)
@@ -191,6 +205,7 @@ static int pl2303_startup (struct usb_serial *serial)
                memset (priv, 0x00, sizeof (struct pl2303_private));
                spin_lock_init(&priv->lock);
                init_waitqueue_head(&priv->delta_msr_wait);
+               priv->type = type;
                usb_set_serial_port_data(serial->port[i], priv);
        }
        return 0;
@@ -229,7 +244,7 @@ static int pl2303_write (struct usb_serial_port *port, int from_user,  const uns
                memcpy (port->write_urb->transfer_buffer, buf, count);
        }
        
-       usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
 
        port->write_urb->transfer_buffer_length = count;
        port->write_urb->dev = port->serial->dev;
@@ -393,26 +408,30 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
             buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
        if (cflag & CRTSCTS) {
-               i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-                                    VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
-                                    0x0, 0x41, NULL, 0, 100);
-               dbg ("0x40:0x1:0x0:0x41  %d", i);
+               __u16 index;
+               if (priv->type == HX)
+                       index = 0x61;
+               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);
        }
 
        kfree (buf);
-}       
-
+} 
 
 static int pl2303_open (struct usb_serial_port *port, struct file *filp)
 {
        struct termios tmp_termios;
        struct usb_serial *serial = port->serial;
+       struct pl2303_private *priv = usb_get_serial_port_data(port);
        unsigned char *buf;
        int result;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return -ENODEV;
-               
        dbg("%s -  port %d", __FUNCTION__, port->number);
 
        usb_clear_halt(serial->dev, port->write_urb->pipe);
@@ -440,6 +459,18 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
        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);
+       }
 
        kfree(buf);
 
@@ -473,18 +504,11 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
 
 static void pl2303_close (struct usb_serial_port *port, struct file *filp)
 {
-       struct usb_serial *serial;
        struct pl2303_private *priv;
        unsigned long flags;
        unsigned int c_cflag;
        int result;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return;
-       serial = get_usb_serial (port, __FUNCTION__);
-       if (!serial)
-               return;
-       
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        /* shutdown our urbs */
@@ -661,7 +685,6 @@ static void pl2303_shutdown (struct usb_serial *serial)
 static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        unsigned char *data = urb->transfer_buffer;
        unsigned long flags;
@@ -685,11 +708,8 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
                goto exit;
        }
 
-       if (!serial) {
-               return;
-       }
 
-       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
        if (urb->actual_length < UART_STATE)
                goto exit;
@@ -712,7 +732,6 @@ exit:
 static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
@@ -722,16 +741,8 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
        u8 status;
        char tty_flag;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return;
-
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (!serial) {
-               dbg("%s - bad serial pointer, exiting", __FUNCTION__);
-               return;
-       }
-
        if (urb->status) {
                dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
                if (!port->open_count) {
@@ -742,7 +753,7 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
                        /* PL2303 mysteriously fails with -EPROTO reschedule the read */
                        dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
                        urb->status = 0;
-                       urb->dev = serial->dev;
+                       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);
@@ -752,7 +763,7 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
                return;
        }
 
-       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
 
        /* get tty_flag from status */
        tty_flag = TTY_NORMAL;
@@ -790,7 +801,7 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 
        /* Schedule the next read _if_ we are still open */
        if (port->open_count) {
-               urb->dev = serial->dev;
+               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);
@@ -806,16 +817,10 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
        struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
        int result;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return;
-       
        dbg("%s - port %d", __FUNCTION__, port->number);
        
        if (urb->status) {
                /* error in the urb, so we have to resubmit it */
-               if (serial_paranoia_check (port->serial, __FUNCTION__)) {
-                       return;
-               }
                dbg("%s - Overflow in write", __FUNCTION__);
                dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
                port->write_urb->transfer_buffer_length = 1;
@@ -862,6 +867,6 @@ module_exit(pl2303_exit);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");