Somewhere around 2.6.18, reading or writing the sysfs attributes for the ftdi_sio driver started causing seg faults; the wrong dev structure was being accessed.

This patch fixes the problem, and fixes a conceptual error in the original implementation which assumed that there was only one port (and one set of attributes) per usb device. However, multi-port devices each have their own set of registers (or at least the ftdi protocol permits this). This patch creates a set of attributes for each *port*, not merely each usb device, and the sysfs attributes will now appear one directory deeper in /sys, as attributes of the usb_serial_port, rather than the parent usb device. (In other words, the attributes will appear in the ttyUSBxx directory).

Tested on 2.6.20-1 and 2.6.19-1, this patch is against 2.6.20-1.

Signed-off-by: Edwin Olson <[EMAIL PROTECTED]>

---

--- linux-2.6.20.1/drivers/usb/serial/ftdi_sio.c        2007-02-20 
01:34:32.000000000 -0500
+++ linux-2.6.20.1-eolson/drivers/usb/serial/ftdi_sio.c 2007-03-01 
19:55:46.000000000 -0500
@@ -520,9 +520,11 @@
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
+static int  ftdi_device_probe           (struct usb_interface *interface,  
const struct usb_device_id *id);
+
 static struct usb_driver ftdi_driver = {
        .name =         "ftdi_sio",
-       .probe =        usb_serial_probe,
+       .probe =        ftdi_device_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table_combined,
        .no_dynamic_id =        1,
@@ -585,7 +587,7 @@
  ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP )
 
 /* function prototypes for a FTDI serial converter */
-static int  ftdi_sio_probe     (struct usb_serial *serial, const struct 
usb_device_id *id);
+static int  ftdi_sio_probe             (struct usb_serial *serial, const 
struct usb_device_id *id);
 static int  ftdi_sio_attach            (struct usb_serial *serial);
 static void ftdi_shutdown              (struct usb_serial *serial);
 static int  ftdi_open                  (struct usb_serial_port *port, struct 
file *filp);
@@ -1023,12 +1025,10 @@
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev;
+       struct usb_device *udev = port->serial->dev;
        unsigned short latency = 0;
        int rv = 0;
 
-       udev = to_usb_device(dev);
-
        dbg("%s",__FUNCTION__);
 
        rv = usb_control_msg(udev,
@@ -1051,13 +1051,12 @@
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev;
+       struct usb_device *udev = port->serial->dev;
+
        char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
 
-       udev = to_usb_device(dev);
-
        dbg("%s: setting latency timer = %i", __FUNCTION__, v);
 
        rv = usb_control_msg(udev,
@@ -1082,13 +1081,12 @@
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev;
+       struct usb_device *udev = port->serial->dev;
+
        char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
 
-       udev = to_usb_device(dev);
-
        dbg("%s: setting event char = %i", __FUNCTION__, v);
 
        rv = usb_control_msg(udev,
@@ -1109,17 +1107,14 @@
 static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, 
store_latency_timer);
 static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
 
-static int create_sysfs_attrs(struct usb_serial *serial)
+static int create_sysfs_attrs(struct usb_serial_port *port)
 {
-       struct ftdi_private *priv;
-       struct usb_device *udev;
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *udev = to_usb_device(&port->dev);
        int retval = 0;
 
        dbg("%s",__FUNCTION__);
 
-       priv = usb_get_serial_port_data(serial->port[0]);
-       udev = serial->dev;
-
        /* XXX I've no idea if the original SIO supports the event_char
         * sysfs parameter, so I'm playing it safe.  */
        if (priv->chip_type != SIO) {
@@ -1134,16 +1129,13 @@
        return retval;
 }
 
-static void remove_sysfs_attrs(struct usb_serial *serial)
+static void remove_sysfs_attrs(struct usb_serial_port *port)
 {
-       struct ftdi_private *priv;
-       struct usb_device *udev;
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *udev = to_usb_device(&port->dev);
 
        dbg("%s",__FUNCTION__);
 
-       priv = usb_get_serial_port_data(serial->port[0]);
-       udev = serial->dev;
-
        /* XXX see create_sysfs_attrs */
        if (priv->chip_type != SIO) {
                device_remove_file(&udev->dev, &dev_attr_event_char);
@@ -1154,6 +1146,22 @@
 
 }
 
+static int ftdi_device_probe(struct usb_interface *interface,
+                            const struct usb_device_id *id)
+{
+       int rv = usb_serial_probe(interface, id);
+       struct usb_serial *serial = usb_get_intfdata(interface);
+       int i;
+
+       if (!rv) {
+               for (i = 0; i < serial->num_ports; i++) {
+                       create_sysfs_attrs(serial->port[i]);
+               }
+       }
+
+       return rv;
+}
+
 /*
  * ***************************************************************************
  * FTDI driver specific functions
@@ -1174,7 +1182,6 @@
        struct usb_serial_port *port = serial->port[0];
        struct ftdi_private *priv;
        struct ftdi_sio_quirk *quirk;
-       int retval;
 
        dbg("%s",__FUNCTION__);
 
@@ -1217,10 +1224,6 @@
        usb_set_serial_port_data(serial->port[0], priv);
 
        ftdi_determine_type (serial->port[0]);
-       retval = create_sysfs_attrs(serial);
-       if (retval)
-               dev_err(&serial->dev->dev, "Error creating sysfs files, "
-                       "continuing\n");
 
        /* Check for device requiring special set up. */
        quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
@@ -1277,10 +1280,12 @@
 
        struct usb_serial_port *port = serial->port[0];
        struct ftdi_private *priv = usb_get_serial_port_data(port);
+       int i;
 
        dbg("%s", __FUNCTION__);
 
-       remove_sysfs_attrs(serial);
+       for (i = 0; i < serial->num_ports; i++)
+               remove_sysfs_attrs(serial->port[i]);
 
        /* all open ports are closed at this point
          *    (by usbserial.c:__serial_close, which calls ftdi_close)
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to