Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+35 −44
Original line number Original line Diff line number Diff line
@@ -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 = {
	.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
{
{
	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 *
{
{
	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
{
{
	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
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
	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)
	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)
 *      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)
		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 */