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