Hi,

This patch against 2.4.11-pre1 updates the usb-serial pl2303 driver.  It
fixes a number of bugs and has been reported to be stable for a number
of users.  It is based on the code that has been in the -ac tree for a
while.

thanks,

greg k-h
(temporary USB maintainer)


diff --minimal -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c       Mon Oct  1 10:48:29 2001
+++ b/drivers/usb/serial/pl2303.c       Mon Oct  1 10:48:29 2001
@@ -12,6 +12,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2001_Sep_19 gkh
+ *     Added break support.
+ *
  * 2001_Aug_30 gkh
  *     fixed oops in write_bulk_callback.
  *
@@ -53,7 +56,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.7"
+#define DRIVER_VERSION "v0.8"
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
 
@@ -67,6 +70,26 @@
 MODULE_DEVICE_TABLE (usb, id_table);
 
 
+#define SET_LINE_REQUEST_TYPE          0x21
+#define SET_LINE_REQUEST               0x20
+
+#define SET_CONTROL_REQUEST_TYPE       0x21
+#define SET_CONTROL_REQUEST            0x22
+
+#define BREAK_REQUEST_TYPE             0x21
+#define BREAK_REQUEST                  0x23    
+#define BREAK_ON                       0xffff
+#define BREAK_OFF                      0x0000
+
+#define GET_LINE_REQUEST_TYPE          0xa1
+#define GET_LINE_REQUEST               0x21
+
+#define VENDOR_WRITE_REQUEST_TYPE      0x40
+#define VENDOR_WRITE_REQUEST           0x01
+
+#define VENDOR_READ_REQUEST_TYPE       0xc0
+#define VENDOR_READ_REQUEST            0x01
+
 /* 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);
@@ -80,6 +103,7 @@
 static int pl2303_write (struct usb_serial_port *port, int from_user,
                         const unsigned char *buf, int count);
 static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
+static void pl2303_shutdown (struct usb_serial *serial);
 
 
 /* All of the device info needed for the PL2303 SIO serial converter */
@@ -102,6 +126,7 @@
        read_bulk_callback:     pl2303_read_bulk_callback,
        read_int_callback:      pl2303_read_int_callback,
        write_bulk_callback:    pl2303_write_bulk_callback,
+       shutdown:               pl2303_shutdown,
 };
 
 
@@ -145,54 +170,60 @@
 
 
 
-static void
-pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{                              /* pl2303_set_termios */
+static void pl2303_set_termios (struct usb_serial_port *port, struct termios 
+*old_termios)
+{
        struct usb_serial *serial = port->serial;
-       unsigned int cflag = port->tty->termios->c_cflag;
-       unsigned char buf[7] = { 0, 0, 0, 0, 0, 0, 0};
+       unsigned int cflag;
+       unsigned char *buf;
        int baud;
        int i;
 
+       dbg (__FUNCTION__ " -  port %d", port->number);
 
-       dbg ("pl2303_set_termios port %d", port->number);
+       if ((!port->tty) || (!port->tty->termios)) {
+               dbg(__FUNCTION__" - no tty structures");
+               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(__FUNCTION__ " - nothing to change...");
+                   return;
+               }
+       }
 
+       buf = kmalloc (7, GFP_KERNEL);
+       if (!buf) {
+               err(__FUNCTION__ " - out of memory.");
+               return;
+       }
+       memset (buf, 0x00, 0x07);
+       
        i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
-                            0x21, 0xa1, 0, 0, buf, 7, 100);
-
+                            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_sndctrlpipe (serial->dev, 0),
-                            1, 0x40, 0, 1, NULL, 0, 100);
+                            VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
+                            0, 1, NULL, 0, 100);
 
        dbg ("0x40:1:0:1  %d", i);
 
-
-
        if (cflag & CSIZE) {
                switch (cflag & CSIZE) {
-                       case CS5:
-                               buf[6] = 5;
-                               dbg ("Setting CS5");
-                               break;
-                       case CS6:
-                               buf[6] = 6;
-                               dbg ("Setting CS6");
-                               break;
-                       case CS7:
-                               buf[6] = 7;
-                               dbg ("Setting CS7");
-                               break;
-                       case CS8:
-                               buf[6] = 8;
-                               dbg ("Setting CS8");
-                               break;
+                       case CS5:       buf[6] = 5;     break;
+                       case CS6:       buf[6] = 6;     break;
+                       case CS7:       buf[6] = 7;     break;
                        default:
-                               err ("CSIZE was set but not CS5-CS8");
+                       case CS8:       buf[6] = 8;     break;
                }
+               dbg (__FUNCTION__ " - data bits = %d", buf[6]);
        }
 
        baud = 0;
@@ -216,7 +247,7 @@
                        err ("pl2303 driver does not support the baudrate requested 
(fix it)");
                        break;
        }
-
+       dbg (__FUNCTION__ " - baud = %d", baud);
        if (baud) {
                buf[0] = baud & 0xff;
                buf[1] = (baud >> 8) & 0xff;
@@ -224,16 +255,17 @@
                buf[3] = (baud >> 24) & 0xff;
        }
 
-
        /* For reference buf[4]=0 is 1 stop bits */
        /* 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(__FUNCTION__ " - stop bits = 2");
+       } else {
+               buf[4] = 0;
+               dbg(__FUNCTION__ " - stop bits = 1");
        }
 
-
        if (cflag & PARENB) {
                /* For reference buf[5]=0 is none parity */
                /* For reference buf[5]=1 is odd parity */
@@ -242,45 +274,52 @@
                /* For reference buf[5]=4 is space parity */
                if (cflag & PARODD) {
                        buf[5] = 1;
+                       dbg(__FUNCTION__ " - parity = odd");
                } else {
                        buf[5] = 2;
+                       dbg(__FUNCTION__ " - parity = even");
                }
+       } else {
+               buf[5] = 0;
+               dbg(__FUNCTION__ " - parity = none");
        }
 
        i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-                            0x20, 0x21, 0, 0, buf, 7, 100);
-
+                            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),
-                            0x22, 0x21, 1, 0, NULL, 0, 100);
-
+                            SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
+                            1, 0, NULL, 0, 100);
        dbg ("0x21:0x22:1:0  %d", i);
-
+#if 0
        i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-                            0x22, 0x21, 3, 0, NULL, 0, 100);
+                            SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
+                            1, 0, NULL, 0, 100);
+       dbg ("0x21:0x22:1:0  %d", i);
 
+       i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+                            SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
+                            3, 0, NULL, 0, 100);
        dbg ("0x21:0x22:3:0  %d", i);
-
+#endif
        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),
-                            0x21, 0xa1, 0, 0, buf, 7, 100);
-
+                            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) {
-
                i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-                                    0x01, 0x40, 0x0, 0x41, NULL, 0, 100);
-
+                                    VENDOR_WRITE_REQUEST_TYPE, 
+VENDOR_WRITE_REQUEST_TYPE,
+                                    0x0, 0x41, NULL, 0, 100);
                dbg ("0x40:0x1:0x0:0x41  %d", i);
-
        }
 
-
-       return;
+       kfree (buf);
 }       
 
 
@@ -294,7 +333,7 @@
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
                
-       dbg (__FUNCTION__ "-  port %d", port->number);
+       dbg (__FUNCTION__ " -  port %d", port->number);
 
        down (&port->sem);
 
@@ -311,20 +350,20 @@
 
 #define SOUP(a,b,c,d)                                                                 
 \
                result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),    
 \
-                                      b, a, c , d, NULL, 0, 100);                     
 \
+                                      b, a, c, d, NULL, 0, 100);                      
+ \
                dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
 
-               FISH (0xc0, 1, 0x8484, 0);
-               SOUP (0x40, 1, 0x0404, 0);
-               FISH (0xc0, 1, 0x8484, 0);
-               FISH (0xc0, 1, 0x8383, 0);
-               FISH (0xc0, 1, 0x8484, 0);
-               SOUP (0x40, 1, 0x0404, 1);
-               FISH (0xc0, 1, 0x8484, 0);
-               FISH (0xc0, 1, 0x8383, 0);
-               SOUP (0x40, 1, 0, 1);
-               SOUP (0x40, 1, 1, 0xc0);
-               SOUP (0x40, 1, 2, 4);
+               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, 0xc0);
+               SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
 
                /* Setup termios */
                *(port->tty->termios) = tty_std_termios;
@@ -334,6 +373,7 @@
 
                //FIXME: need to assert RTS and DTR if CRTSCTS off
 
+               dbg (__FUNCTION__ " - submitting read urb");
                port->read_urb->dev = serial->dev;
                result = usb_submit_urb (port->read_urb);
                if (result) {
@@ -343,6 +383,7 @@
                        return -EPROTO;
                }
 
+               dbg (__FUNCTION__ " - submitting interrupt urb");
                port->interrupt_in_urb->dev = serial->dev;
                result = usb_submit_urb (port->interrupt_in_urb);
                if (result) {
@@ -360,6 +401,7 @@
 static void pl2303_close (struct usb_serial_port *port, struct file *filp)
 {
        unsigned int c_cflag;
+       int result;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return;
@@ -377,28 +419,30 @@
                }
 
                /* shutdown our urbs */
-               usb_unlink_urb (port->write_urb);
-               usb_unlink_urb (port->read_urb);
-               usb_unlink_urb (port->interrupt_in_urb);
+               dbg (__FUNCTION__ " - shutting down urbs");
+               result = usb_unlink_urb (port->write_urb);
+               if (result)
+                       dbg (__FUNCTION__ " - usb_unlink_urb (write_urb) failed with 
+reason: %d", result);
+
+               result = usb_unlink_urb (port->read_urb);
+               if (result)
+                       dbg (__FUNCTION__ " - usb_unlink_urb (read_urb) failed with 
+reason: %d", result);
+
+               result = usb_unlink_urb (port->interrupt_in_urb);
+               if (result)
+                       dbg (__FUNCTION__ " - usb_unlink_urb (interrupt_in_urb) failed 
+with reason: %d", result);
 
                port->active = 0;
                port->open_count = 0;
        }
 
        up (&port->sem);
+       MOD_DEC_USE_COUNT;
 }
 
 
-static int
-pl2303_ioctl (struct usb_serial_port *port, struct file *file,
-             unsigned int cmd, unsigned long arg)
+static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned 
+int cmd, unsigned long arg)
 {
-// struct usb_serial *serial = port->serial;
-// __u16 urb_value=0; /* Will hold the new flags */
-// char buf[1];
-// int  ret, mask;
-
-
        dbg ("pl2303_sio ioctl 0x%04x", cmd);
 
        /* Based on code from acm.c and others */
@@ -423,23 +467,50 @@
                        return(-ENOIOCTLCMD);
                        break;
        }
-       dbg ("pl2303_ioctl returning 0");
 
        return 0;
-}                              /* pl2303_ioctl */
+}
 
 
-static void pl2303_break_ctl(struct usb_serial_port *port,int break_state)
+static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
 {
-//FIXME
+       struct usb_serial *serial = port->serial;
+       u16 state;
+       int result;
+
+       dbg (__FUNCTION__ " - port %d", port->number);
+
+       if (break_state == 0)
+               state = BREAK_OFF;
+       else
+               state = BREAK_ON;
+       dbg (__FUNCTION__" - turning break %s", state==BREAK_OFF ? "off" : "on");
+
+       result = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+                                 BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 
+                                 0, NULL, 0, 100);
+       if (result)
+               dbg (__FUNCTION__" - error sending break = %d", result);
 }
 
 
-static void
-pl2303_read_int_callback (struct urb *urb)
+static void pl2303_shutdown (struct usb_serial *serial)
+{
+       int i;
+
+       dbg (__FUNCTION__);
+
+       /* stop everything on all ports */
+       for (i = 0; i < serial->num_ports; ++i)
+               while (serial->port[i].open_count > 0)
+                       pl2303_close (&serial->port[i], NULL);
+}
+
+
+static void pl2303_read_int_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
-       struct usb_serial *serial = get_usb_serial (port, "pl2303_read_int_callback");
+       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        //unsigned char *data = urb->transfer_buffer;
        //int i;
 
@@ -482,13 +553,23 @@
                return;
        }
 
-       /* PL2303 mysteriously fails with -EPROTO reschedule the read */
        if (urb->status) {
-               urb->status = 0;
-               urb->dev = serial->dev;
-               result = usb_submit_urb(urb);
-               if (result)
-                       err(__FUNCTION__ " - failed resubmitting read urb, error %d", 
result);
+               dbg (__FUNCTION__ " - urb->status = %d", urb->status);
+               if (!port->active) {
+                       dbg (__FUNCTION__ " - port is closed, exiting.");
+                       return;
+               }
+               if (urb->status == -EPROTO) {
+                       /* PL2303 mysteriously fails with -EPROTO reschedule the read 
+*/
+                       dbg (__FUNCTION__ " - caught -EPROTO, resubmitting the urb");
+                       urb->status = 0;
+                       urb->dev = serial->dev;
+                       result = usb_submit_urb(urb);
+                       if (result)
+                               err(__FUNCTION__ " - failed resubmitting read urb, 
+error %d", result);
+                       return;
+               }
+               dbg (__FUNCTION__ " - unable to handle the error, exiting.");
                return;
        }
 
@@ -505,11 +586,13 @@
                tty_flip_buffer_push (tty);
        }
 
-       /* Schedule the next read*/
-       urb->dev = serial->dev;
-       result = usb_submit_urb(urb);
-       if (result)
-               err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+       /* Schedule the next read _if_ we are still open */
+       if (port->active) {
+               urb->dev = serial->dev;
+               result = usb_submit_urb(urb);
+               if (result)
+                       err(__FUNCTION__ " - failed resubmitting read urb, error %d", 
+result);
+       }
 
        return;
 }


_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to