[PATCH 2.6.20.1] fix ftdi_sio sysfs attributes (latency_timer, event_char)

Edwin Olson <[email protected]>
Newsgroups gmane.linux.usb.devel,gmane.spam.detected
Message-ID <[email protected]>
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]>

---

-------------------------------------------------------------------------
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
patch (text/plain, 4.9 KB)
--- 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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.