usb: ks_bridge: Add support for multiple instance of driver

ks bridver needs to get loaded for two mdm9x15 device enumeration
to support flashless boot and efs sync.

Change-Id: I4316fe74a311a26042e60787cb0b27fcd2df3cb9
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index cb47b72..e5062fb 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -33,6 +33,24 @@
 #define DRIVER_DESC	"USB host ks bridge driver"
 #define DRIVER_VERSION	"1.0"
 
+enum bus_id {
+	BUS_HSIC,
+	BUS_USB,
+	BUS_UNDEF,
+};
+
+#define BUSNAME_LEN	20
+
+static enum bus_id str_to_busid(const char *name)
+{
+	if (!strncasecmp("msm_hsic_host", name, BUSNAME_LEN))
+		return BUS_HSIC;
+	if (!strncasecmp("msm_ehci_host.0", name, BUSNAME_LEN))
+		return BUS_USB;
+
+	return BUS_UNDEF;
+}
+
 struct data_pkt {
 	int			n_read;
 	char			*buf;
@@ -44,9 +62,9 @@
 #define FILE_OPENED		BIT(0)
 #define USB_DEV_CONNECTED	BIT(1)
 #define NO_RX_REQS		10
-#define NO_BRIDGE_INSTANCES	2
-#define BOOT_BRIDGE_INDEX	0
-#define EFS_BRIDGE_INDEX	1
+#define NO_BRIDGE_INSTANCES	4
+#define EFS_HSIC_BRIDGE_INDEX	2
+#define EFS_USB_BRIDGE_INDEX	3
 #define MAX_DATA_PKT_SIZE	16384
 
 struct ks_bridge {
@@ -58,7 +76,7 @@
 	struct list_head	to_mdm_list;
 	struct list_head	to_ks_list;
 	wait_queue_head_t	ks_wait_q;
-	struct miscdevice	*fs_dev;
+	struct miscdevice	fs_dev;
 
 	/* usb specific */
 	struct usb_device	*udev;
@@ -174,7 +192,8 @@
 
 		ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
 		if (ret) {
-			pr_err("copy_to_user failed err:%d\n", ret);
+			dev_err(ksb->fs_dev.this_device,
+					"copy_to_user failed err:%d\n", ret);
 			ksb_free_data_pkt(pkt);
 			return ret;
 		}
@@ -201,7 +220,8 @@
 
 	dbg_log_event(ksb, "KS_READ", copied, 0);
 
-	pr_debug("count:%d space:%d copied:%d", count, space, copied);
+	dev_dbg(ksb->fs_dev.this_device, "count:%d space:%d copied:%d", count,
+			space, copied);
 
 	return copied;
 }
@@ -212,13 +232,14 @@
 	struct ks_bridge *ksb = pkt->ctxt;
 
 	dbg_log_event(ksb, "C TX_URB", urb->status, 0);
-	pr_debug("status:%d", urb->status);
+	dev_dbg(&ksb->udev->dev, "status:%d", urb->status);
 
 	if (ksb->ifc)
 		usb_autopm_put_interface_async(ksb->ifc);
 
 	if (urb->status < 0)
-		pr_err_ratelimited("urb failed with err:%d", urb->status);
+		pr_err_ratelimited("%s: urb failed with err:%d",
+				ksb->fs_dev.name, urb->status);
 
 	ksb_free_data_pkt(pkt);
 }
@@ -241,14 +262,16 @@
 
 		urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (!urb) {
-			pr_err_ratelimited("unable to allocate urb");
+			pr_err_ratelimited("%s: unable to allocate urb",
+					ksb->fs_dev.name);
 			ksb_free_data_pkt(pkt);
 			return;
 		}
 
 		ret = usb_autopm_get_interface(ksb->ifc);
 		if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
-			pr_err_ratelimited("autopm_get failed:%d", ret);
+			pr_err_ratelimited("%s: autopm_get failed:%d",
+					ksb->fs_dev.name, ret);
 			usb_free_urb(urb);
 			ksb_free_data_pkt(pkt);
 			return;
@@ -261,7 +284,7 @@
 
 		ret = usb_submit_urb(urb, GFP_KERNEL);
 		if (ret) {
-			pr_err("out urb submission failed");
+			dev_err(&ksb->udev->dev, "out urb submission failed");
 			usb_unanchor_urb(urb);
 			usb_free_urb(urb);
 			ksb_free_data_pkt(pkt);
@@ -290,13 +313,15 @@
 
 	pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
 	if (IS_ERR(pkt)) {
-		pr_err("unable to allocate data packet");
+		dev_err(ksb->fs_dev.this_device,
+				"unable to allocate data packet");
 		return PTR_ERR(pkt);
 	}
 
 	ret = copy_from_user(pkt->buf, buf, count);
 	if (ret) {
-		pr_err("copy_from_user failed: err:%d", ret);
+		dev_err(ksb->fs_dev.this_device,
+				"copy_from_user failed: err:%d", ret);
 		ksb_free_data_pkt(pkt);
 		return ret;
 	}
@@ -310,39 +335,19 @@
 	return count;
 }
 
-static int efs_fs_open(struct inode *ip, struct file *fp)
-{
-	struct ks_bridge *ksb = __ksb[EFS_BRIDGE_INDEX];
-
-	pr_debug(":%s", ksb->name);
-	dbg_log_event(ksb, "EFS-FS-OPEN", 0, 0);
-
-	if (!ksb) {
-		pr_err("ksb is being removed");
-		return -ENODEV;
-	}
-
-	fp->private_data = ksb;
-	set_bit(FILE_OPENED, &ksb->flags);
-
-	if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
-		queue_work(ksb->wq, &ksb->start_rx_work);
-
-	return 0;
-}
-
 static int ksb_fs_open(struct inode *ip, struct file *fp)
 {
-	struct ks_bridge *ksb = __ksb[BOOT_BRIDGE_INDEX];
+	struct miscdevice *mdev = fp->private_data;
+	struct ks_bridge *ksb = container_of(mdev, struct ks_bridge, fs_dev);
 
-	pr_debug(":%s", ksb->name);
-	dbg_log_event(ksb, "KS-FS-OPEN", 0, 0);
-
-	if (!ksb) {
-		pr_err("ksb is being removed");
+	if (IS_ERR(ksb)) {
+		pr_err("ksb device not found");
 		return -ENODEV;
 	}
 
+	dev_dbg(ksb->fs_dev.this_device, ":%s", ksb->fs_dev.name);
+	dbg_log_event(ksb, "FS-OPEN", 0, 0);
+
 	fp->private_data = ksb;
 	set_bit(FILE_OPENED, &ksb->flags);
 
@@ -356,7 +361,7 @@
 {
 	struct ks_bridge	*ksb = fp->private_data;
 
-	pr_debug(":%s", ksb->name);
+	dev_dbg(ksb->fs_dev.this_device, ":%s", ksb->fs_dev.name);
 	dbg_log_event(ksb, "FS-RELEASE", 0, 0);
 
 	clear_bit(FILE_OPENED, &ksb->flags);
@@ -373,33 +378,47 @@
 	.release = ksb_fs_release,
 };
 
-static struct miscdevice ksb_fboot_dev = {
-	.minor = MISC_DYNAMIC_MINOR,
-	.name = "ks_bridge",
-	.fops = &ksb_fops,
+static struct miscdevice ksb_fboot_dev[] = {
+	{
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "ks_hsic_bridge",
+		.fops = &ksb_fops,
+	},
+	{
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "ks_usb_bridge",
+		.fops = &ksb_fops,
+	},
 };
 
 static const struct file_operations efs_fops = {
 	.owner = THIS_MODULE,
 	.read = ksb_fs_read,
 	.write = ksb_fs_write,
-	.open = efs_fs_open,
+	.open = ksb_fs_open,
 	.release = ksb_fs_release,
 };
 
-static struct miscdevice ksb_efs_dev = {
+static struct miscdevice ksb_efs_hsic_dev = {
 	.minor = MISC_DYNAMIC_MINOR,
-	.name = "efs_bridge",
+	.name = "efs_hsic_bridge",
 	.fops = &efs_fops,
 };
 
+static struct miscdevice ksb_efs_usb_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "efs_usb_bridge",
+	.fops = &efs_fops,
+};
 static const struct usb_device_id ksb_usb_ids[] = {
 	{ USB_DEVICE(0x5c6, 0x9008),
 	.driver_info = (unsigned long)&ksb_fboot_dev, },
 	{ USB_DEVICE(0x5c6, 0x9048),
-	.driver_info = (unsigned long)&ksb_efs_dev, },
+	.driver_info = (unsigned long)&ksb_efs_hsic_dev, },
 	{ USB_DEVICE(0x5c6, 0x904C),
-	.driver_info = (unsigned long)&ksb_efs_dev, },
+	.driver_info = (unsigned long)&ksb_efs_hsic_dev, },
+	{ USB_DEVICE(0x5c6, 0x9079),
+	.driver_info = (unsigned long)&ksb_efs_usb_dev, },
 
 	{} /* terminating entry */
 };
@@ -414,7 +433,7 @@
 
 	urb = usb_alloc_urb(0, flags);
 	if (!urb) {
-		pr_err("unable to allocate urb");
+		dev_err(&ksb->udev->dev, "unable to allocate urb");
 		ksb_free_data_pkt(pkt);
 		return;
 	}
@@ -428,7 +447,7 @@
 
 	ret = usb_submit_urb(urb, flags);
 	if (ret) {
-		pr_err("in urb submission failed");
+		dev_err(&ksb->udev->dev, "in urb submission failed");
 		usb_unanchor_urb(urb);
 		usb_free_urb(urb);
 		ksb_free_data_pkt(pkt);
@@ -444,7 +463,8 @@
 
 	dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
 
-	pr_debug("status:%d actual:%d", urb->status, urb->actual_length);
+	dev_dbg(&ksb->udev->dev, "status:%d actual:%d", urb->status,
+			urb->actual_length);
 
 	/*non zero len of data received while unlinking urb*/
 	if (urb->status == -ENOENT && urb->actual_length > 0)
@@ -453,8 +473,8 @@
 	if (urb->status < 0) {
 		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
 				&& urb->status != -EPROTO)
-			pr_err_ratelimited("urb failed with err:%d",
-					urb->status);
+			pr_err_ratelimited("%s: urb failed with err:%d",
+					ksb->fs_dev.name, urb->status);
 		ksb_free_data_pkt(pkt);
 		return;
 	}
@@ -495,13 +515,13 @@
 	for (i = 0; i < NO_RX_REQS; i++) {
 		pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
 		if (IS_ERR(pkt)) {
-			pr_err("unable to allocate data pkt");
+			dev_err(&ksb->udev->dev, "unable to allocate data pkt");
 			break;
 		}
 
 		urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (!urb) {
-			pr_err("unable to allocate urb");
+			dev_err(&ksb->udev->dev, "unable to allocate urb");
 			ksb_free_data_pkt(pkt);
 			break;
 		}
@@ -515,7 +535,7 @@
 
 		ret = usb_submit_urb(urb, GFP_KERNEL);
 		if (ret) {
-			pr_err("in urb submission failed");
+			dev_err(&ksb->udev->dev, "in urb submission failed");
 			usb_unanchor_urb(urb);
 			usb_free_urb(urb);
 			ksb_free_data_pkt(pkt);
@@ -536,20 +556,39 @@
 	struct usb_endpoint_descriptor	*ep_desc;
 	int				i;
 	struct ks_bridge		*ksb;
+	struct miscdevice		*mdev, *fbdev;
+	struct usb_device		*udev;
+	unsigned int			bus_id;
 
 	ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
 
+	udev = interface_to_usbdev(ifc);
+	fbdev = mdev = (struct miscdevice *)id->driver_info;
+
+	bus_id = str_to_busid(udev->bus->bus_name);
+	if (bus_id == BUS_UNDEF) {
+		dev_err(&udev->dev, "unknown usb bus %s, probe failed\n",
+				udev->bus->bus_name);
+		return -ENODEV;
+	}
+
 	switch (id->idProduct) {
 	case 0x9008:
 		if (ifc_num != 0)
 			return -ENODEV;
-		ksb = __ksb[BOOT_BRIDGE_INDEX];
+		ksb = __ksb[bus_id];
+		mdev = &fbdev[bus_id];
 		break;
 	case 0x9048:
 	case 0x904C:
 		if (ifc_num != 2)
 			return -ENODEV;
-		ksb = __ksb[EFS_BRIDGE_INDEX];
+		ksb = __ksb[EFS_HSIC_BRIDGE_INDEX];
+		break;
+	case 0x9079:
+		if (ifc_num != 2)
+			return -ENODEV;
+		ksb = __ksb[EFS_USB_BRIDGE_INDEX];
 		break;
 	default:
 		return -ENODEV;
@@ -575,7 +614,8 @@
 	}
 
 	if (!(ksb->in_epAddr && ksb->out_epAddr)) {
-		pr_err("could not find bulk in and bulk out endpoints");
+		dev_err(&udev->dev,
+			"could not find bulk in and bulk out endpoints");
 		usb_put_dev(ksb->udev);
 		ksb->ifc = NULL;
 		return -ENODEV;
@@ -589,13 +629,13 @@
 
 	dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
 
-	ksb->fs_dev = (struct miscdevice *)id->driver_info;
-	misc_register(ksb->fs_dev);
+	ksb->fs_dev = *mdev;
+	misc_register(&ksb->fs_dev);
 
 	ifc->needs_remote_wakeup = 1;
 	usb_enable_autosuspend(ksb->udev);
 
-	pr_debug("usb dev connected");
+	dev_dbg(&udev->dev, "usb dev connected");
 
 	return 0;
 }
@@ -635,7 +675,7 @@
 	wake_up(&ksb->ks_wait_q);
 	cancel_work_sync(&ksb->to_mdm_work);
 
-	misc_deregister(ksb->fs_dev);
+	misc_deregister(&ksb->fs_dev);
 
 	usb_kill_anchored_urbs(&ksb->submitted);
 	spin_lock_irqsave(&ksb->lock, flags);