diag: Add support for mutiple HSIC instances
On a future target, applications processor will talk to
two MDMs simultaneously. This change will enable multiple
HSIC connections towards this configuration.
Change-Id: I2138b1d458936eddb8276a12e92916a4893d922b
Signed-off-by: Ravi Aravamudhan <aravamud@codeaurora.org>
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 53d2c93..376812c 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,6 +30,9 @@
#define DRIVER_DESC "USB host diag bridge driver"
#define DRIVER_VERSION "1.0"
+#define MAX_DIAG_BRIDGE_DEVS 2
+#define AUTOSUSP_DELAY_WITH_USB 1000
+
struct diag_bridge {
struct usb_device *udev;
struct usb_interface *ifc;
@@ -49,12 +51,18 @@
unsigned pending_reads;
unsigned pending_writes;
};
-struct diag_bridge *__dev;
+struct diag_bridge *__dev[MAX_DIAG_BRIDGE_DEVS];
-int diag_bridge_open(struct diag_bridge_ops *ops)
+int diag_bridge_open(int id, struct diag_bridge_ops *ops)
{
- struct diag_bridge *dev = __dev;
+ struct diag_bridge *dev;
+ if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
+ pr_err("Invalid device ID");
+ return -ENODEV;
+ }
+
+ dev = __dev[id];
if (!dev) {
pr_err("dev is null");
return -ENODEV;
@@ -77,16 +85,23 @@
static void diag_bridge_delete(struct kref *kref)
{
struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
+ int id = dev->pdev->id;
usb_put_dev(dev->udev);
- __dev = 0;
+ __dev[id] = 0;
kfree(dev);
}
-void diag_bridge_close(void)
+void diag_bridge_close(int id)
{
- struct diag_bridge *dev = __dev;
+ struct diag_bridge *dev;
+ if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
+ pr_err("Invalid device ID");
+ return;
+ }
+
+ dev = __dev[id];
if (!dev) {
pr_err("dev is null");
return;
@@ -128,15 +143,21 @@
kref_put(&dev->kref, diag_bridge_delete);
}
-int diag_bridge_read(char *data, int size)
+int diag_bridge_read(int id, char *data, int size)
{
struct urb *urb = NULL;
unsigned int pipe;
- struct diag_bridge *dev = __dev;
+ struct diag_bridge *dev;
int ret;
+ if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
+ pr_err("Invalid device ID");
+ return -ENODEV;
+ }
+
pr_debug("reading %d bytes", size);
+ dev = __dev[id];
if (!dev) {
pr_err("device is disconnected");
return -ENODEV;
@@ -230,15 +251,21 @@
kref_put(&dev->kref, diag_bridge_delete);
}
-int diag_bridge_write(char *data, int size)
+int diag_bridge_write(int id, char *data, int size)
{
struct urb *urb = NULL;
unsigned int pipe;
- struct diag_bridge *dev = __dev;
+ struct diag_bridge *dev;
int ret;
+ if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
+ pr_err("Invalid device ID");
+ return -ENODEV;
+ }
+
pr_debug("writing %d bytes", size);
+ dev = __dev[id];
if (!dev) {
pr_err("device is disconnected");
return -ENODEV;
@@ -315,28 +342,30 @@
static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
- struct diag_bridge *dev = __dev;
char *buf;
- int ret;
-
- if (!dev)
- return -ENODEV;
+ int i, ret = 0;
buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = scnprintf(buf, DEBUG_BUF_SIZE,
- "epin:%d, epout:%d\n"
- "bytes to host: %lu\n"
- "bytes to mdm: %lu\n"
- "pending reads: %u\n"
- "pending writes: %u\n"
- "last error: %d\n",
- dev->in_epAddr, dev->out_epAddr,
- dev->bytes_to_host, dev->bytes_to_mdm,
- dev->pending_reads, dev->pending_writes,
- dev->err);
+ for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
+ struct diag_bridge *dev = __dev[i];
+ if (!dev)
+ continue;
+
+ ret += scnprintf(buf, DEBUG_BUF_SIZE,
+ "epin:%d, epout:%d\n"
+ "bytes to host: %lu\n"
+ "bytes to mdm: %lu\n"
+ "pending reads: %u\n"
+ "pending writes: %u\n"
+ "last error: %d\n",
+ dev->in_epAddr, dev->out_epAddr,
+ dev->bytes_to_host, dev->bytes_to_mdm,
+ dev->pending_reads, dev->pending_writes,
+ dev->err);
+ }
ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
kfree(buf);
@@ -346,11 +375,14 @@
static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct diag_bridge *dev = __dev;
+ int i;
- if (dev) {
- dev->bytes_to_host = dev->bytes_to_mdm = 0;
- dev->pending_reads = dev->pending_writes = 0;
+ for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
+ struct diag_bridge *dev = __dev[i];
+ if (dev) {
+ dev->bytes_to_host = dev->bytes_to_mdm = 0;
+ dev->pending_reads = dev->pending_writes = 0;
+ }
}
return count;
@@ -394,8 +426,7 @@
struct diag_bridge *dev;
struct usb_host_interface *ifc_desc;
struct usb_endpoint_descriptor *ep_desc;
- int i;
- int ret = -ENOMEM;
+ int i, devid, ret = -ENOMEM;
__u8 ifc_num;
pr_debug("id:%lu", id->driver_info);
@@ -406,18 +437,30 @@
if (ifc_num != id->driver_info)
return -ENODEV;
+ /* This needs to figure out ID based on PID and/or host bus type */
+ devid = 0;
+
+ if (devid < 0 || devid >= MAX_DIAG_BRIDGE_DEVS)
+ return -ENODEV;
+
+ /* already probed? */
+ if (__dev[devid]) {
+ pr_err("Diag device already probed");
+ return -ENODEV;
+ }
+
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
pr_err("unable to allocate dev");
return -ENOMEM;
}
- dev->pdev = platform_device_alloc("diag_bridge", -1);
+ dev->pdev = platform_device_alloc("diag_bridge", devid);
if (!dev->pdev) {
pr_err("unable to allocate platform device");
kfree(dev);
return -ENOMEM;
}
- __dev = dev;
+ __dev[devid] = dev;
dev->udev = usb_get_dev(interface_to_usbdev(ifc));
dev->ifc = ifc;