]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/usb/serial/ftdi_sio.c
[PATCH] USB Serial: move name to driver structure
[mirror_ubuntu-artful-kernel.git] / drivers / usb / serial / ftdi_sio.c
index 0b03ddab53d9e9e325dfaaed918630f7e9b194e9..77d54ac39a0e9a873d510f8bbdfd60e9604874b8 100644 (file)
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
 static int debug;
+static __u16 vendor = FTDI_VID;
+static __u16 product;
 
 /* struct ftdi_sio_quirk is used by devices requiring special attention. */
 struct ftdi_sio_quirk {
@@ -407,6 +409,35 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) },
+       /*
+        * These will probably use user-space drivers.  Uncomment them if
+        * you need them or use the user-specified vendor/product module
+        * parameters (see ftdi_sio.h for the numbers).  Make a fuss if
+        * you think the driver should recognize any of them by default.
+        */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
+       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
        { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
        { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
        { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -418,6 +449,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
        { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
        { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
+       { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
@@ -427,9 +459,24 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
+       { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
        { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
-       { }                                             /* Terminating entry */
+       { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
+       { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
+       { },                                    /* Optional parameter entry */
+       { }                                     /* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
@@ -515,10 +562,12 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud);
 static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
 static __u32 ftdi_232bm_baud_to_divisor (int baud);
 
-static struct usb_serial_device_type ftdi_sio_device = {
-       .owner =                THIS_MODULE,
-       .name =                 "FTDI USB Serial Device",
-       .short_name =           "ftdi_sio",
+static struct usb_serial_driver ftdi_sio_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "ftdi_sio",
+       },
+       .description =          "FTDI USB Serial Device",
        .id_table =             id_table_combined,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
@@ -545,6 +594,7 @@ static struct usb_serial_device_type ftdi_sio_device = {
 
 
 #define WDR_TIMEOUT 5000 /* default urb timeout */
+#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
 
 /* High and low are for DTR, RTS etc etc */
 #define HIGH 1
@@ -593,62 +643,59 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud)
         return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
 }
 
-static int set_rts(struct usb_serial_port *port, int high_or_low)
+#define set_mctrl(port, set)           update_mctrl((port), (set), 0)
+#define clear_mctrl(port, clear)       update_mctrl((port), 0, (clear))
+
+static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        char *buf;
-       unsigned ftdi_high_or_low;
+       unsigned urb_value;
        int rv;
-       
-       buf = kmalloc(1, GFP_NOIO);
-       if (!buf)
-               return -ENOMEM;
-       
-       if (high_or_low) {
-               ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
-               priv->last_dtr_rts |= TIOCM_RTS;
-       } else {
-               ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
-               priv->last_dtr_rts &= ~TIOCM_RTS;
-       }
-       rv = usb_control_msg(port->serial->dev,
-                              usb_sndctrlpipe(port->serial->dev, 0),
-                              FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                              FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                              ftdi_high_or_low, priv->interface, 
-                              buf, 0, WDR_TIMEOUT);
-
-       kfree(buf);
-       return rv;
-}
 
+       if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+               dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__);
+               return 0;       /* no change */
+       }
 
-static int set_dtr(struct usb_serial_port *port, int high_or_low)
-{
-       struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char *buf;
-       unsigned ftdi_high_or_low;
-       int rv;
-       
        buf = kmalloc(1, GFP_NOIO);
-       if (!buf)
+       if (!buf) {
                return -ENOMEM;
-
-       if (high_or_low) {
-               ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
-               priv->last_dtr_rts |= TIOCM_DTR;
-       } else {
-               ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
-               priv->last_dtr_rts &= ~TIOCM_DTR;
        }
+
+       clear &= ~set;  /* 'set' takes precedence over 'clear' */
+       urb_value = 0;
+       if (clear & TIOCM_DTR)
+               urb_value |= FTDI_SIO_SET_DTR_LOW;
+       if (clear & TIOCM_RTS)
+               urb_value |= FTDI_SIO_SET_RTS_LOW;
+       if (set & TIOCM_DTR)
+               urb_value |= FTDI_SIO_SET_DTR_HIGH;
+       if (set & TIOCM_RTS)
+               urb_value |= FTDI_SIO_SET_RTS_HIGH;
        rv = usb_control_msg(port->serial->dev,
                               usb_sndctrlpipe(port->serial->dev, 0),
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                              ftdi_high_or_low, priv->interface, 
+                              urb_value, priv->interface,
                               buf, 0, WDR_TIMEOUT);
 
        kfree(buf);
+       if (rv < 0) {
+               err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+                               __FUNCTION__,
+                               (set & TIOCM_DTR) ? "HIGH" :
+                               (clear & TIOCM_DTR) ? "LOW" : "unchanged",
+                               (set & TIOCM_RTS) ? "HIGH" :
+                               (clear & TIOCM_RTS) ? "LOW" : "unchanged");
+       } else {
+               dbg("%s - DTR %s, RTS %s", __FUNCTION__,
+                               (set & TIOCM_DTR) ? "HIGH" :
+                               (clear & TIOCM_DTR) ? "LOW" : "unchanged",
+                               (set & TIOCM_RTS) ? "HIGH" :
+                               (clear & TIOCM_RTS) ? "LOW" : "unchanged");
+               priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
+       }
        return rv;
 }
 
@@ -681,7 +728,7 @@ static int change_speed(struct usb_serial_port *port)
                            FTDI_SIO_SET_BAUDRATE_REQUEST,
                            FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
                            urb_value, urb_index,
-                           buf, 0, 100);
+                           buf, 0, WDR_SHORT_TIMEOUT);
 
        kfree(buf);
        return rv;
@@ -873,7 +920,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
        unsigned interfaces;
 
        /* Assume it is not the original SIO device for now. */
-       priv->baud_base = 48000000 / 16;
+       priv->baud_base = 48000000 / 2;
        priv->write_offset = 0;
 
        version = le16_to_cpu(udev->descriptor.bcdDevice);
@@ -1219,12 +1266,7 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
        /* FIXME: Flow control might be enabled, so it should be checked -
           we have no control of defaults! */
        /* Turn on RTS and DTR since we are not flow controlling by default */
-       if (set_dtr(port, HIGH) < 0) {
-               err("%s Error from DTR HIGH urb", __FUNCTION__);
-       }
-       if (set_rts(port, HIGH) < 0){
-               err("%s Error from RTS HIGH urb", __FUNCTION__);
-       }
+       set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 
        /* Not throttled */
        spin_lock_irqsave(&priv->rx_lock, flags);
@@ -1274,14 +1316,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
                        err("error from flowcontrol urb");
                }           
 
-               /* drop DTR */
-               if (set_dtr(port, LOW) < 0){
-                       err("Error from DTR LOW urb");
-               }
-               /* drop RTS */
-               if (set_rts(port, LOW) < 0) {
-                       err("Error from RTS LOW urb");
-               }
+               /* drop RTS and DTR */
+               clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        } /* Note change no line if hupcl is off */
 
        /* cancel any scheduled reading */
@@ -1797,7 +1833,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
                            FTDI_SIO_SET_DATA_REQUEST, 
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , priv->interface,
-                           buf, 0, 100) < 0) {
+                           buf, 0, WDR_SHORT_TIMEOUT) < 0) {
                err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
        }          
 
@@ -1812,25 +1848,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
                        err("%s error from disable flowcontrol urb", __FUNCTION__);
                }           
                /* Drop RTS and DTR */
-               if (set_dtr(port, LOW) < 0){
-                       err("%s Error from DTR LOW urb", __FUNCTION__);
-               }
-               if (set_rts(port, LOW) < 0){
-                       err("%s Error from RTS LOW urb", __FUNCTION__);
-               }       
-               
+               clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        } else {
                /* set the baudrate determined before */
                if (change_speed(port)) {
-                       err("%s urb failed to set baurdrate", __FUNCTION__);
+                       err("%s urb failed to set baudrate", __FUNCTION__);
                }
-               /* Ensure  RTS and DTR are raised */
-               else if (set_dtr(port, HIGH) < 0){
-                       err("%s Error from DTR HIGH urb", __FUNCTION__);
+               /* Ensure RTS and DTR are raised when baudrate changed from 0 */
+               if ((old_termios->c_cflag & CBAUD) == B0) {
+                       set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
                }
-               else if (set_rts(port, HIGH) < 0){
-                       err("%s Error from RTS HIGH urb", __FUNCTION__);
-               }       
        }
 
        /* Set flow control */
@@ -1942,35 +1969,8 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
 
 static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
 {
-       int ret;
-       
        dbg("%s TIOCMSET", __FUNCTION__);
-       if (set & TIOCM_DTR){
-               if ((ret = set_dtr(port, HIGH)) < 0) {
-                       err("Urb to set DTR failed");
-                       return(ret);
-               }
-       }
-       if (set & TIOCM_RTS) {
-               if ((ret = set_rts(port, HIGH)) < 0){
-                       err("Urb to set RTS failed");
-                       return(ret);
-               }
-       }
-       
-       if (clear & TIOCM_DTR){
-               if ((ret = set_dtr(port, LOW)) < 0){
-                       err("Urb to unset DTR failed");
-                       return(ret);
-               }
-       }       
-       if (clear & TIOCM_RTS) {
-               if ((ret = set_rts(port, LOW)) < 0){
-                       err("Urb to unset RTS failed");
-                       return(ret);
-               }
-       }
-       return(0);
+       return update_mctrl(port, set, clear);
 }
 
 
@@ -2078,6 +2078,15 @@ static int __init ftdi_init (void)
        int retval;
 
        dbg("%s", __FUNCTION__);
+       if (vendor > 0 && product > 0) {
+               /* Add user specified VID/PID to reserved element of table. */
+               int i;
+               for (i = 0; id_table_combined[i].idVendor; i++)
+                       ;
+               id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+               id_table_combined[i].idVendor = vendor;
+               id_table_combined[i].idProduct = product;
+       }
        retval = usb_serial_register(&ftdi_sio_device);
        if (retval)
                goto failed_sio_register;
@@ -2114,4 +2123,9 @@ MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(vendor, ushort, 0);
+MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
+               __MODULE_STRING(FTDI_VID)")");
+module_param(product, ushort, 0);
+MODULE_PARM_DESC(vendor, "User specified product ID");