Hi,

Here's a patch against 2.4.10-ac7 that adds proper RTS/DTR control for
the pl2303 driver.  Parts of this patch was done by Johannes
Deisenhofer.

thanks,

greg k-h

diff --minimal -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c       Sat Oct  6 22:20:45 2001
+++ b/drivers/usb/serial/pl2303.c       Sat Oct  6 22:20:45 2001
@@ -12,6 +12,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2001_Oct_06 gkh
+ *     Added RTS and DTR line control.  Thanks to [EMAIL PROTECTED] for parts of it.
+ *
  * 2001_Sep_19 gkh
  *     Added break support.
  *
@@ -56,13 +59,15 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.8"
+#define DRIVER_VERSION "v0.9"
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
 
 
 static __devinitdata 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(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
@@ -75,6 +80,8 @@
 
 #define SET_CONTROL_REQUEST_TYPE       0x21
 #define SET_CONTROL_REQUEST            0x22
+#define CONTROL_DTR                    0x01
+#define CONTROL_RTS                    0x02
 
 #define BREAK_REQUEST_TYPE             0x21
 #define BREAK_REQUEST                  0x23    
@@ -103,6 +110,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 int pl2303_startup (struct usb_serial *serial);
 static void pl2303_shutdown (struct usb_serial *serial);
 
 
@@ -126,10 +134,40 @@
        read_bulk_callback:     pl2303_read_bulk_callback,
        read_int_callback:      pl2303_read_int_callback,
        write_bulk_callback:    pl2303_write_bulk_callback,
+       startup:                pl2303_startup,
        shutdown:               pl2303_shutdown,
 };
 
+struct pl2303_private { 
+       u8 line_control;
+};
+
 
+static int pl2303_startup (struct usb_serial *serial)
+{
+       struct pl2303_private *priv;
+       int i;
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
+               if (!priv)
+                       return -ENOMEM;
+               memset (priv, 0x00, sizeof (struct pl2303_private));
+               serial->port[i].private = priv;
+       }
+       return 0;
+}
+
+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 (__FUNCTION__" - value = %d, retval = %d", value, retval);
+       return retval;
+}
 
 static int pl2303_write (struct usb_serial_port *port, int from_user,  const unsigned 
char *buf, int count)
 {
@@ -173,6 +211,7 @@
 static void pl2303_set_termios (struct usb_serial_port *port, struct termios 
*old_termios)
 {
        struct usb_serial *serial = port->serial;
+       struct pl2303_private *priv;
        unsigned int cflag;
        unsigned char *buf;
        int baud;
@@ -228,6 +267,7 @@
 
        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;
@@ -289,21 +329,15 @@
                             0, 0, buf, 7, 100);
        dbg ("0x21:0x20:0:0  %d", i);
 
-       i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-                            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),
-                            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
+       if (cflag && CBAUD) {
+               priv = port->private;
+               if ((cflag && CBAUD) == B0)
+                       priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
+               else
+                       priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
+               set_control_lines (serial->dev, priv->line_control);
+       }
+       
        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),
@@ -400,6 +434,7 @@
 
 static void pl2303_close (struct usb_serial_port *port, struct file *filp)
 {
+       struct pl2303_private *priv;
        unsigned int c_cflag;
        int result;
 
@@ -414,8 +449,10 @@
        if (port->open_count <= 0) {
                c_cflag = port->tty->termios->c_cflag;
                if (c_cflag & HUPCL) {
-                       //FIXME: Do drop DTR
-                       //FIXME: Do drop RTS
+                       /* drop DTR and RTS */
+                       priv = port->private;
+                       priv->line_control = 0;
+                       set_control_lines (port->serial->dev, priv->line_control);
                }
 
                /* shutdown our urbs */
@@ -440,35 +477,79 @@
        MOD_DEC_USE_COUNT;
 }
 
+static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned 
+int *value)
+{
+       struct pl2303_private *priv = port->private;
+       unsigned int arg;
+
+       if (copy_from_user(&arg, value, sizeof(int)))
+               return -EFAULT;
+
+       switch (cmd) {
+               case TIOCMBIS:
+                       if (arg & TIOCM_RTS)
+                               priv->line_control |= CONTROL_RTS;
+                       if (arg & TIOCM_DTR)
+                               priv->line_control |= CONTROL_DTR;
+                       break;
+
+               case TIOCMBIC:
+                       if (arg & TIOCM_RTS)
+                               priv->line_control &= ~CONTROL_RTS;
+                       if (arg & TIOCM_DTR)
+                               priv->line_control &= ~CONTROL_DTR;
+                       break;
+
+               case TIOCMSET:
+                       /* turn off RTS and DTR and then only turn
+                          on what was asked to */
+                       priv->line_control &= ~(CONTROL_RTS | CONTROL_DTR);
+                       priv->line_control |= ((arg & TIOCM_RTS) ? CONTROL_RTS : 0);
+                       priv->line_control |= ((arg & TIOCM_DTR) ? CONTROL_DTR : 0);
+                       break;
+       }
+
+       return set_control_lines (port->serial->dev, priv->line_control);
+}
+
+static int get_modem_info (struct usb_serial_port *port, unsigned int *value)
+{
+       struct pl2303_private *priv = port->private;
+       unsigned int mcr = priv->line_control;
+       unsigned int result;
+
+       result = ((mcr & CONTROL_DTR)           ? TIOCM_DTR : 0)
+                 | ((mcr & CONTROL_RTS)        ? TIOCM_RTS : 0);
+
+       dbg (__FUNCTION__ " - result = %x", result);
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
 
 static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned 
int cmd, unsigned long arg)
 {
-       dbg ("pl2303_sio ioctl 0x%04x", cmd);
+       dbg (__FUNCTION__" (%d) cmd = 0x%04x", port->number, cmd);
 
-       /* Based on code from acm.c and others */
        switch (cmd) {
                
                case TIOCMGET:
-                       dbg ("TIOCMGET");
-
+                       dbg (__FUNCTION__" (%d) TIOCMGET", port->number);
+                       return get_modem_info (port, (unsigned int *)arg);
 
-                       return put_user (0, (unsigned long *) arg);
-                       break;
                case TIOCMBIS:
                case TIOCMBIC:
                case TIOCMSET:
-                       return 0;
+                       dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET",  
+port->number);
+                       return set_modem_info(port, cmd, (unsigned int *) arg);
 
                default:
-                       /* This is not an error - turns out the higher layers will do 
-                        *  some ioctls itself (see comment above)
-                        */
-                       dbg ("pl2303_sio ioctl arg not supported - it was 0x%04x", 
cmd);
-                       return(-ENOIOCTLCMD);
+                       dbg (__FUNCTION__" not supported = 0x%04x", cmd);
                        break;
        }
 
-       return 0;
+       return -ENOIOCTLCMD;
 }
 
 
@@ -502,8 +583,10 @@
 
        /* stop everything on all ports */
        for (i = 0; i < serial->num_ports; ++i)
-               while (serial->port[i].open_count > 0)
+               while (serial->port[i].open_count > 0) {
                        pl2303_close (&serial->port[i], NULL);
+                       kfree (serial->port[i].private);
+               }
 }
 
 
diff --minimal -Nru a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
--- a/drivers/usb/serial/pl2303.h       Sat Oct  6 22:20:45 2001
+++ b/drivers/usb/serial/pl2303.h       Sat Oct  6 22:20:45 2001
@@ -9,7 +9,10 @@
  */
 #define PL2303_VENDOR_ID       0x067b
 #define PL2303_PRODUCT_ID      0x2303
+#define PL2303_PRODUCT_ID_RSAQ2        0x04bb
 
 #define ATEN_VENDOR_ID         0x0557
 #define ATEN_PRODUCT_ID                0x2008
 
+#define IODATA_VENDOR_ID       0x04bb
+#define IODATA_PRODUCT_ID      0x0a03

Reply via email to