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 {
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_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 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);
......@@ -631,6 +633,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.num_bulk_out = 1,
.num_ports = 1,
.probe = ftdi_sio_probe,
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
......@@ -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 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__);
......@@ -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 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,
......@@ -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 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,
......@@ -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(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);
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) {
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) &&
(priv->chip_type == FT232BM || priv->chip_type == FT2232C)) {
retval = device_create_file(&udev->dev,
retval = device_create_file(&port->dev,
&dev_attr_latency_timer);
}
}
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);
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);
device_remove_file(&port->dev, &dev_attr_event_char);
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
return (0);
}
/* attach subroutine */
static int ftdi_sio_attach (struct usb_serial *serial)
static int ftdi_sio_port_probe(struct usb_serial_port *port)
{
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv;
struct ftdi_sio_quirk *quirk;
int retval;
dbg("%s",__FUNCTION__);
......@@ -1224,19 +1211,21 @@ static int ftdi_sio_attach (struct usb_serial *serial)
kfree(port->bulk_out_buffer);
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]);
retval = create_sysfs_attrs(serial);
if (retval)
dev_err(&serial->dev->dev, "Error creating sysfs files, "
"continuing\n");
ftdi_determine_type (port);
create_sysfs_attrs(port);
return 0;
}
/* attach subroutine */
static int ftdi_sio_attach (struct usb_serial *serial)
{
/* Check for device requiring special set up. */
quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
if (quirk && quirk->setup) {
struct ftdi_sio_quirk *quirk = usb_get_serial_data(serial);
if (quirk && quirk->setup)
quirk->setup(serial);
}
return 0;
} /* ftdi_sio_attach */
......@@ -1280,17 +1269,18 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
* calls __serial_close for each open of the port
* shutdown is called then (ie ftdi_shutdown)
*/
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);
dbg("%s", __FUNCTION__);
remove_sysfs_attrs(serial);
remove_sysfs_attrs(port);
/* all open ports are closed at this point
* (by usbserial.c:__serial_close, which calls ftdi_close)
......@@ -1300,8 +1290,9 @@ static void ftdi_shutdown (struct usb_serial *serial)
usb_set_serial_port_data(port, NULL);
kfree(priv);
}
} /* ftdi_shutdown */
return 0;
}
static int ftdi_open (struct usb_serial_port *port, struct file *filp)
{ /* 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