usb: gadget: Support multiple HSIC transport instances for dun and rmnet
Instead of using integer-based IDs to couple bridge instances to the
corresponding gadget ports, assign transport name strings (passed by
userspace) describing the port instance, and match strings to identify
the correct instance when bridge_open() called. This allows multiple
dun and rmnet ports to be assigned without having dependecy of
one-to-one mapping between gadget port instance and bridge driver
instance.
Change-Id: Ia87bd6e9c72d5e98f47dbc2a1cf0b71b48daa1a8
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index f783f09..82a7e35 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -29,9 +29,18 @@
#define FLOW_CTRL_DISABLE 300
#define FLOW_CTRL_SUPPORT 1
-static const char *data_bridge_names[] = {
- "dun_data_hsic0",
- "rmnet_data_hsic0"
+#define BRIDGE_DATA_IDX 0
+#define BRIDGE_CTRL_IDX 1
+
+/*for xport : HSIC*/
+static const char * const serial_hsic_bridge_names[] = {
+ "serial_hsic_data",
+ "serial_hsic_ctrl",
+};
+
+static const char * const rmnet_hsic_bridge_names[] = {
+ "rmnet_hsic_data",
+ "rmnet_hsic_ctrl",
};
static struct workqueue_struct *bridge_wq;
@@ -62,6 +71,7 @@
struct usb_interface *intf;
struct usb_device *udev;
int id;
+ char *name;
unsigned int bulk_in;
unsigned int bulk_out;
@@ -110,6 +120,20 @@
static int submit_rx_urb(struct data_bridge *dev, struct urb *urb,
gfp_t flags);
+static int get_data_bridge_chid(char *xport_name)
+{
+ struct data_bridge *dev;
+ int i;
+
+ for (i = 0; i < MAX_BRIDGE_DEVICES; i++) {
+ dev = __dev[i];
+ if (!strncmp(dev->name, xport_name, BRIDGE_NAME_MAX_LEN))
+ return i;
+ }
+
+ return -ENODEV;
+}
+
static inline bool rx_halted(struct data_bridge *dev)
{
return test_bit(RX_HALT, &dev->flags);
@@ -322,21 +346,23 @@
int data_bridge_open(struct bridge *brdg)
{
struct data_bridge *dev;
+ int ch_id;
if (!brdg) {
err("bridge is null\n");
return -EINVAL;
}
- if (brdg->ch_id >= MAX_BRIDGE_DEVICES)
- return -EINVAL;
-
- dev = __dev[brdg->ch_id];
- if (!dev) {
- err("dev is null\n");
- return -ENODEV;
+ ch_id = get_data_bridge_chid(brdg->name);
+ if (ch_id < 0 || ch_id >= MAX_BRIDGE_DEVICES) {
+ err("%s: %s dev not found\n", __func__, brdg->name);
+ return ch_id;
}
+ brdg->ch_id = ch_id;
+
+ dev = __dev[ch_id];
+
dev_dbg(&dev->intf->dev, "%s: dev:%p\n", __func__, dev);
dev->brdg = brdg;
@@ -657,7 +683,7 @@
static int data_bridge_probe(struct usb_interface *iface,
struct usb_host_endpoint *bulk_in,
- struct usb_host_endpoint *bulk_out, int id)
+ struct usb_host_endpoint *bulk_out, char *name, int id)
{
struct data_bridge *dev;
int retval;
@@ -668,7 +694,7 @@
return -ENODEV;
}
- dev->pdev = platform_device_alloc(data_bridge_names[id], id);
+ dev->pdev = platform_device_alloc(name, -1);
if (!dev->pdev) {
err("%s: unable to allocate platform device\n", __func__);
kfree(dev);
@@ -677,6 +703,7 @@
dev->flags = 0;
dev->id = id;
+ dev->name = name;
dev->udev = interface_to_usbdev(iface);
dev->intf = iface;
@@ -939,9 +966,7 @@
int i;
int status = 0;
int numends;
- unsigned int iface_num;
-
- iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+ char **bname = (char **)id->driver_info;
if (iface->num_altsetting != 1) {
err("%s invalid num_altsetting %u\n",
@@ -949,9 +974,6 @@
return -EINVAL;
}
- if (!test_bit(iface_num, &id->driver_info))
- return -ENODEV;
-
udev = interface_to_usbdev(iface);
usb_get_dev(udev);
@@ -979,13 +1001,15 @@
goto out;
}
- status = data_bridge_probe(iface, bulk_in, bulk_out, ch_id);
+ status = data_bridge_probe(iface, bulk_in, bulk_out,
+ bname[BRIDGE_DATA_IDX], ch_id);
if (status < 0) {
dev_err(&iface->dev, "data_bridge_probe failed %d\n", status);
goto out;
}
- status = ctrl_bridge_probe(iface, int_in, ch_id);
+ status = ctrl_bridge_probe(iface, int_in, bname[BRIDGE_CTRL_IDX],
+ ch_id);
if (status < 0) {
dev_err(&iface->dev, "ctrl_bridge_probe failed %d\n", status);
goto error;
@@ -1024,28 +1048,37 @@
usb_put_dev(dev->udev);
}
-/*bit position represents interface number*/
-#define PID9001_IFACE_MASK 0xC
-#define PID9034_IFACE_MASK 0xC
-#define PID9048_IFACE_MASK 0x18
-#define PID904C_IFACE_MASK 0x28
-#define PID9075_IFACE_MASK 0x28
-
+/*driver info stores data/ctrl bridge name used to match bridge xport name*/
static const struct usb_device_id bridge_ids[] = {
- { USB_DEVICE(0x5c6, 0x9001),
- .driver_info = PID9001_IFACE_MASK,
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9001, 2),
+ .driver_info = (unsigned long)serial_hsic_bridge_names,
},
- { USB_DEVICE(0x5c6, 0x9034),
- .driver_info = PID9034_IFACE_MASK,
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9001, 3),
+ .driver_info = (unsigned long)rmnet_hsic_bridge_names,
},
- { USB_DEVICE(0x5c6, 0x9048),
- .driver_info = PID9048_IFACE_MASK,
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9034, 2),
+ .driver_info = (unsigned long)serial_hsic_bridge_names,
},
- { USB_DEVICE(0x5c6, 0x904c),
- .driver_info = PID904C_IFACE_MASK,
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9034, 3),
+ .driver_info = (unsigned long)rmnet_hsic_bridge_names,
},
- { USB_DEVICE(0x5c6, 0x9075),
- .driver_info = PID9075_IFACE_MASK,
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 3),
+ .driver_info = (unsigned long)serial_hsic_bridge_names,
+ },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 4),
+ .driver_info = (unsigned long)rmnet_hsic_bridge_names,
+ },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x904c, 3),
+ .driver_info = (unsigned long)serial_hsic_bridge_names,
+ },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x904c, 5),
+ .driver_info = (unsigned long)rmnet_hsic_bridge_names,
+ },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9075, 3),
+ .driver_info = (unsigned long)serial_hsic_bridge_names,
+ },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9075, 5),
+ .driver_info = (unsigned long)rmnet_hsic_bridge_names,
},
{ } /* Terminating entry */
@@ -1090,6 +1123,9 @@
dev->wq = bridge_wq;
+ /*transport name will be set during probe*/
+ dev->name = "";
+
init_usb_anchor(&dev->tx_active);
init_usb_anchor(&dev->rx_active);
init_usb_anchor(&dev->delayed);