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);