From cc9bd53eb1bf50e265a8f8741a624bf67851f5c0 Mon Sep 17 00:00:00 2001
From: Johan Hovold <johan@hovoldconsulting.com>
Date: Thu, 30 Jul 2015 20:30:38 +0200
Subject: [PATCH] greybus: usb: fix hcd allocation, deregistration and
 deallocation

Fix allocation, deregistration and deallocation of USB HCD, and update
the hcd_priv helper functions.

The HCD private data was not allocated correctly, something which would
lead to a crash when accessed in hcd_start. The HCD was neither
reregistered or deallocated on connection tear down.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
---
 drivers/staging/greybus/usb.c | 46 ++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/staging/greybus/usb.c b/drivers/staging/greybus/usb.c
index 2a146d77ecdac..1ba731e6bfadf 100644
--- a/drivers/staging/greybus/usb.c
+++ b/drivers/staging/greybus/usb.c
@@ -40,12 +40,19 @@ struct gb_usb_hub_control_response {
 struct gb_usb_device {
 	struct gb_connection *connection;
 
-	struct usb_hcd *hcd;
 	u8 version_major;
 	u8 version_minor;
 };
 
-#define to_gb_usb_device(d) ((struct gb_usb_device*) d->hcd_priv)
+static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
+{
+	return (struct gb_usb_device *)hcd->hcd_priv;
+}
+
+static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
+{
+	return container_of((void *)dev, struct usb_hcd, hcd_priv);
+}
 
 /* Define get_version() routine */
 define_get_version(gb_usb_device, USB);
@@ -143,45 +150,44 @@ static int gb_usb_connection_init(struct gb_connection *connection)
 {
 	struct device *dev = &connection->dev;
 	struct gb_usb_device *gb_usb_dev;
+	struct usb_hcd *hcd;
 
 	int retval;
 
-	gb_usb_dev = kzalloc(sizeof(*gb_usb_dev), GFP_KERNEL);
-	if (!gb_usb_dev)
+	hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
+	if (!hcd)
 		return -ENOMEM;
 
+	gb_usb_dev = to_gb_usb_device(hcd);
 	gb_usb_dev->connection = connection;
 	connection->private = gb_usb_dev;
 
 	/* Check for compatible protocol version */
 	retval = get_version(gb_usb_dev);
 	if (retval)
-		goto error_create_hcd;
-
-	gb_usb_dev->hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
-	if (!gb_usb_dev->hcd) {
-		retval = -ENODEV;
-		goto error_create_hcd;
-	}
+		goto err_put_hcd;
 
-	gb_usb_dev->hcd->has_tt = 1;
-	gb_usb_dev->hcd->hcd_priv[0] = (unsigned long) gb_usb_dev;
+	hcd->has_tt = 1;
 
-	retval = usb_add_hcd(gb_usb_dev->hcd, 0, 0);
+	retval = usb_add_hcd(hcd, 0, 0);
 	if (retval)
-		goto error_add_hcd;
+		goto err_put_hcd;
 
 	return 0;
-error_add_hcd:
-	usb_put_hcd(gb_usb_dev->hcd);
-error_create_hcd:
-	kfree(gb_usb_dev);
+
+err_put_hcd:
+	usb_put_hcd(hcd);
+
 	return retval;
 }
 
 static void gb_usb_connection_exit(struct gb_connection *connection)
 {
-	// FIXME - tear everything down!
+	struct gb_usb_device *gb_usb_dev = connection->private;
+	struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
 }
 
 static struct gb_protocol usb_protocol = {
-- 
2.30.2