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: Jim Radford <radford@blackbean.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 07884e0..ada4e6c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -597,6 +597,8 @@
 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 @@
 	.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 @@
 {
 	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 @@
 {
 	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 @@
 {
 	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 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 @@
 	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 @@
 	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 @@
  *      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 @@
 		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 */