Commit 12bdbe03 authored by Jim Radford's avatar Jim Radford Committed by Greg Kroah-Hartman

USB: ftdi_sio: use port_probe / port_remove thereby fixing access to the latency_timer

Convert all the port specific code in attach / shutdown to use the new
port_probe / port_register callbacks from device_register /
device_unregister allowing adding the sysfs attributes to be added at
the correct time and to the serial port device itself, instead of to
the unadorned usb device, avoiding a NULL dereference.
Signed-off-by: default avatarJim Radford <radford@blackbean.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d9a7ecac
...@@ -597,6 +597,8 @@ struct ftdi_private { ...@@ -597,6 +597,8 @@ struct ftdi_private {
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 int ftdi_sio_attach (struct usb_serial *serial);
static void ftdi_shutdown (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial);
static int ftdi_sio_port_probe (struct usb_serial_port *port);
static int ftdi_sio_port_remove (struct usb_serial_port *port);
static int ftdi_open (struct usb_serial_port *port, struct file *filp); static int ftdi_open (struct usb_serial_port *port, struct file *filp);
static void ftdi_close (struct usb_serial_port *port, struct file *filp); static void ftdi_close (struct usb_serial_port *port, struct file *filp);
static int ftdi_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int ftdi_write (struct usb_serial_port *port, const unsigned char *buf, int count);
...@@ -631,6 +633,8 @@ static struct usb_serial_driver ftdi_sio_device = { ...@@ -631,6 +633,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.num_bulk_out = 1, .num_bulk_out = 1,
.num_ports = 1, .num_ports = 1,
.probe = ftdi_sio_probe, .probe = ftdi_sio_probe,
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open, .open = ftdi_open,
.close = ftdi_close, .close = ftdi_close,
.throttle = ftdi_throttle, .throttle = ftdi_throttle,
...@@ -1033,11 +1037,10 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a ...@@ -1033,11 +1037,10 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
{ {
struct usb_serial_port *port = to_usb_serial_port(dev); struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port); 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; unsigned short latency = 0;
int rv = 0; int rv = 0;
udev = to_usb_device(dev);
dbg("%s",__FUNCTION__); dbg("%s",__FUNCTION__);
...@@ -1061,13 +1064,11 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute * ...@@ -1061,13 +1064,11 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
{ {
struct usb_serial_port *port = to_usb_serial_port(dev); struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev; struct usb_device *udev = port->serial->dev;
char buf[1]; char buf[1];
int v = simple_strtoul(valbuf, NULL, 10); int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0; int rv = 0;
udev = to_usb_device(dev);
dbg("%s: setting latency timer = %i", __FUNCTION__, v); dbg("%s: setting latency timer = %i", __FUNCTION__, v);
rv = usb_control_msg(udev, rv = usb_control_msg(udev,
...@@ -1092,13 +1093,11 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att ...@@ -1092,13 +1093,11 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
{ {
struct usb_serial_port *port = to_usb_serial_port(dev); struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev; struct usb_device *udev = port->serial->dev;
char buf[1]; char buf[1];
int v = simple_strtoul(valbuf, NULL, 10); int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0; int rv = 0;
udev = to_usb_device(dev);
dbg("%s: setting event char = %i", __FUNCTION__, v); dbg("%s: setting event char = %i", __FUNCTION__, v);
rv = usb_control_msg(udev, rv = usb_control_msg(udev,
...@@ -1119,46 +1118,38 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att ...@@ -1119,46 +1118,38 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer); 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 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 ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev;
int retval = 0; int retval = 0;
dbg("%s",__FUNCTION__); 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 /* XXX I've no idea if the original SIO supports the event_char
* sysfs parameter, so I'm playing it safe. */ * sysfs parameter, so I'm playing it safe. */
if (priv->chip_type != SIO) { if (priv->chip_type != SIO) {
dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]); dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
retval = device_create_file(&udev->dev, &dev_attr_event_char); retval = device_create_file(&port->dev, &dev_attr_event_char);
if ((!retval) && if ((!retval) &&
(priv->chip_type == FT232BM || priv->chip_type == FT2232C)) { (priv->chip_type == FT232BM || priv->chip_type == FT2232C)) {
retval = device_create_file(&udev->dev, retval = device_create_file(&port->dev,
&dev_attr_latency_timer); &dev_attr_latency_timer);
} }
} }
return retval; 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 ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev;
dbg("%s",__FUNCTION__); dbg("%s",__FUNCTION__);
priv = usb_get_serial_port_data(serial->port[0]);
udev = serial->dev;
/* XXX see create_sysfs_attrs */ /* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) { if (priv->chip_type != SIO) {
device_remove_file(&udev->dev, &dev_attr_event_char); device_remove_file(&port->dev, &dev_attr_event_char);
if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) { if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
device_remove_file(&udev->dev, &dev_attr_latency_timer); device_remove_file(&port->dev, &dev_attr_latency_timer);
} }
} }
...@@ -1178,13 +1169,9 @@ static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id ...@@ -1178,13 +1169,9 @@ static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id
return (0); return (0);
} }
/* attach subroutine */ static int ftdi_sio_port_probe(struct usb_serial_port *port)
static int ftdi_sio_attach (struct usb_serial *serial)
{ {
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv; struct ftdi_private *priv;
struct ftdi_sio_quirk *quirk;
int retval;
dbg("%s",__FUNCTION__); dbg("%s",__FUNCTION__);
...@@ -1224,19 +1211,21 @@ static int ftdi_sio_attach (struct usb_serial *serial) ...@@ -1224,19 +1211,21 @@ static int ftdi_sio_attach (struct usb_serial *serial)
kfree(port->bulk_out_buffer); kfree(port->bulk_out_buffer);
port->bulk_out_buffer = NULL; port->bulk_out_buffer = NULL;
usb_set_serial_port_data(serial->port[0], priv); usb_set_serial_port_data(port, priv);
ftdi_determine_type (serial->port[0]); ftdi_determine_type (port);
retval = create_sysfs_attrs(serial); create_sysfs_attrs(port);
if (retval) return 0;
dev_err(&serial->dev->dev, "Error creating sysfs files, " }
"continuing\n");
/* attach subroutine */
static int ftdi_sio_attach (struct usb_serial *serial)
{
/* Check for device requiring special set up. */ /* Check for device requiring special set up. */
quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial); struct ftdi_sio_quirk *quirk = usb_get_serial_data(serial);
if (quirk && quirk->setup) {
if (quirk && quirk->setup)
quirk->setup(serial); quirk->setup(serial);
}
return 0; return 0;
} /* ftdi_sio_attach */ } /* ftdi_sio_attach */
...@@ -1280,17 +1269,18 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) ...@@ -1280,17 +1269,18 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
* calls __serial_close for each open of the port * calls __serial_close for each open of the port
* shutdown is called then (ie ftdi_shutdown) * shutdown is called then (ie ftdi_shutdown)
*/ */
static void ftdi_shutdown (struct usb_serial *serial) static void ftdi_shutdown (struct usb_serial *serial)
{ /* ftdi_shutdown */ {
dbg("%s", __FUNCTION__);
}
struct usb_serial_port *port = serial->port[0]; static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
remove_sysfs_attrs(serial); remove_sysfs_attrs(port);
/* all open ports are closed at this point /* all open ports are closed at this point
* (by usbserial.c:__serial_close, which calls ftdi_close) * (by usbserial.c:__serial_close, which calls ftdi_close)
...@@ -1300,8 +1290,9 @@ static void ftdi_shutdown (struct usb_serial *serial) ...@@ -1300,8 +1290,9 @@ static void ftdi_shutdown (struct usb_serial *serial)
usb_set_serial_port_data(port, NULL); usb_set_serial_port_data(port, NULL);
kfree(priv); kfree(priv);
} }
} /* ftdi_shutdown */
return 0;
}
static int ftdi_open (struct usb_serial_port *port, struct file *filp) static int ftdi_open (struct usb_serial_port *port, struct file *filp)
{ /* ftdi_open */ { /* ftdi_open */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment