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>
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index f944c1c..5b83cb4 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -506,6 +506,9 @@
#define MAX_XPORT_STR_LEN 50
static char rmnet_transports[MAX_XPORT_STR_LEN];
+/*rmnet transport name string - "rmnet_hsic[,rmnet_hsusb]" */
+static char rmnet_xport_names[MAX_XPORT_STR_LEN];
+
static void rmnet_function_cleanup(struct android_usb_function *f)
{
frmnet_cleanup();
@@ -518,18 +521,28 @@
int err = 0;
char *ctrl_name;
char *data_name;
+ char *tname = NULL;
char buf[MAX_XPORT_STR_LEN], *b;
+ char xport_name_buf[MAX_XPORT_STR_LEN], *tb;
static int rmnet_initialized, ports;
if (!rmnet_initialized) {
rmnet_initialized = 1;
strlcpy(buf, rmnet_transports, sizeof(buf));
b = strim(buf);
+
+ strlcpy(xport_name_buf, rmnet_xport_names,
+ sizeof(xport_name_buf));
+ tb = strim(xport_name_buf);
+
while (b) {
ctrl_name = strsep(&b, ",");
data_name = strsep(&b, ",");
if (ctrl_name && data_name) {
- err = frmnet_init_port(ctrl_name, data_name);
+ if (tb)
+ tname = strsep(&tb, ",");
+ err = frmnet_init_port(ctrl_name, data_name,
+ tname);
if (err) {
pr_err("rmnet: Cannot open ctrl port:"
"'%s' data port:'%s'\n",
@@ -573,12 +586,34 @@
return size;
}
+static ssize_t rmnet_xport_names_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", rmnet_xport_names);
+}
+
+static ssize_t rmnet_xport_names_store(
+ struct device *device, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ strlcpy(rmnet_xport_names, buff, sizeof(rmnet_xport_names));
+
+ return size;
+}
+
static struct device_attribute dev_attr_rmnet_transports =
__ATTR(transports, S_IRUGO | S_IWUSR,
rmnet_transports_show,
rmnet_transports_store);
+
+static struct device_attribute dev_attr_rmnet_xport_names =
+ __ATTR(transport_names, S_IRUGO | S_IWUSR,
+ rmnet_xport_names_show,
+ rmnet_xport_names_store);
+
static struct device_attribute *rmnet_function_attributes[] = {
&dev_attr_rmnet_transports,
+ &dev_attr_rmnet_xport_names,
NULL };
static struct android_usb_function rmnet_function = {
@@ -811,9 +846,33 @@
return size;
}
+/*enabled FSERIAL transport names - "serial_hsic[,serial_hsusb]"*/
+static char serial_xport_names[32];
+static ssize_t serial_xport_names_store(
+ struct device *device, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ strlcpy(serial_xport_names, buff, sizeof(serial_xport_names));
+
+ return size;
+}
+
+static ssize_t serial_xport_names_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", serial_xport_names);
+}
+
static DEVICE_ATTR(transports, S_IWUSR, NULL, serial_transports_store);
-static struct device_attribute *serial_function_attributes[] =
- { &dev_attr_transports, NULL };
+static struct device_attribute dev_attr_serial_xport_names =
+ __ATTR(transport_names, S_IRUGO | S_IWUSR,
+ serial_xport_names_show,
+ serial_xport_names_store);
+
+static struct device_attribute *serial_function_attributes[] = {
+ &dev_attr_transports,
+ &dev_attr_serial_xport_names,
+ NULL };
static void serial_function_cleanup(struct android_usb_function *f)
{
@@ -823,8 +882,8 @@
static int serial_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
- char *name;
- char buf[32], *b;
+ char *name, *xport_name = NULL;
+ char buf[32], *b, xport_name_buf[32], *tb;
int err = -1, i;
static int serial_initialized = 0, ports = 0;
@@ -835,11 +894,16 @@
strlcpy(buf, serial_transports, sizeof(buf));
b = strim(buf);
+ strlcpy(xport_name_buf, serial_xport_names, sizeof(xport_name_buf));
+ tb = strim(xport_name_buf);
+
while (b) {
name = strsep(&b, ",");
if (name) {
- err = gserial_init_port(ports, name);
+ if (tb)
+ xport_name = strsep(&tb, ",");
+ err = gserial_init_port(ports, name, xport_name);
if (err) {
pr_err("serial: Cannot open port '%s'", name);
goto out;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 1d0b6d4..759a64f 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -1082,7 +1082,8 @@
no_data_hsuart_ports = 0;
}
-static int frmnet_init_port(const char *ctrl_name, const char *data_name)
+static int frmnet_init_port(const char *ctrl_name, const char *data_name,
+ const char *port_name)
{
struct f_rmnet *dev;
struct rmnet_ports *rmnet_port;
@@ -1120,6 +1121,7 @@
no_ctrl_smd_ports++;
break;
case USB_GADGET_XPORT_HSIC:
+ ghsic_ctrl_set_port_name(port_name, ctrl_name);
rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
no_ctrl_hsic_ports++;
break;
@@ -1146,6 +1148,7 @@
no_data_bam2bam_ports++;
break;
case USB_GADGET_XPORT_HSIC:
+ ghsic_data_set_port_name(port_name, data_name);
rmnet_port->data_xport_num = no_data_hsic_ports;
no_data_hsic_ports++;
break;
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 2461960..3f1f03b 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -951,9 +951,11 @@
/**
* gserial_init_port - bind a gserial_port to its transport
*/
-static int gserial_init_port(int port_num, const char *name)
+static int gserial_init_port(int port_num, const char *name,
+ const char *port_name)
{
enum transport_type transport;
+ int ret = 0;
if (port_num >= GSERIAL_NO_PORTS)
return -ENODEV;
@@ -979,6 +981,9 @@
no_smd_ports++;
break;
case USB_GADGET_XPORT_HSIC:
+ ghsic_ctrl_set_port_name(port_name, name);
+ ghsic_data_set_port_name(port_name, name);
+
/*client port number will be updated in gport_setup*/
no_hsic_sports++;
break;
@@ -994,5 +999,5 @@
nr_ports++;
- return 0;
+ return ret;
}
diff --git a/drivers/usb/gadget/u_ctrl_hsic.c b/drivers/usb/gadget/u_ctrl_hsic.c
index fdfab96..84b1cd3 100644
--- a/drivers/usb/gadget/u_ctrl_hsic.c
+++ b/drivers/usb/gadget/u_ctrl_hsic.c
@@ -36,12 +36,6 @@
static unsigned int no_ctrl_ports;
-static const char *ctrl_bridge_names[] = {
- "dun_ctrl_hsic0",
- "rmnet_ctrl_hsic0"
-};
-
-#define CTRL_BRIDGE_NAME_MAX_LEN 20
#define READ_BUF_LEN 1024
#define CH_OPENED 0
@@ -83,6 +77,7 @@
static struct {
struct gctrl_port *port;
struct platform_driver pdrv;
+ char port_name[BRIDGE_NAME_MAX_LEN];
} gctrl_ports[NUM_PORTS];
static int ghsic_ctrl_receive(void *dev, void *buf, size_t actual)
@@ -336,19 +331,35 @@
gser->send_modem_ctrl_bits(gser, ctrl_bits);
}
+static int ghsic_ctrl_get_port_id(const char *pdev_name)
+{
+ struct gctrl_port *port;
+ int i;
+
+ for (i = 0; i < no_ctrl_ports; i++) {
+ port = gctrl_ports[i].port;
+ if (!strncmp(port->brdg.name, pdev_name, BRIDGE_NAME_MAX_LEN))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
static int ghsic_ctrl_probe(struct platform_device *pdev)
{
struct gctrl_port *port;
unsigned long flags;
+ int id;
pr_debug("%s: name:%s\n", __func__, pdev->name);
- if (pdev->id >= no_ctrl_ports) {
- pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ id = ghsic_ctrl_get_port_id(pdev->name);
+ if (id < 0 || id >= no_ctrl_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, id);
return -EINVAL;
}
- port = gctrl_ports[pdev->id].port;
+ port = gctrl_ports[id].port;
set_bit(CH_READY, &port->bridge_sts);
/* if usb is online, start read */
@@ -366,15 +377,17 @@
struct gserial *gser = NULL;
struct grmnet *gr = NULL;
unsigned long flags;
+ int id;
pr_debug("%s: name:%s\n", __func__, pdev->name);
- if (pdev->id >= no_ctrl_ports) {
- pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ id = ghsic_ctrl_get_port_id(pdev->name);
+ if (id < 0 || id >= no_ctrl_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, id);
return -EINVAL;
}
- port = gctrl_ports[pdev->id].port;
+ port = gctrl_ports[id].port;
spin_lock_irqsave(&port->port_lock, flags);
if (!port->port_usb) {
@@ -421,15 +434,17 @@
{
struct gctrl_port *port;
struct platform_driver *pdrv;
+ char *name;
port = kzalloc(sizeof(struct gctrl_port), GFP_KERNEL);
if (!port)
return -ENOMEM;
- port->wq = create_singlethread_workqueue(ctrl_bridge_names[portno]);
+ name = gctrl_ports[portno].port_name;
+
+ port->wq = create_singlethread_workqueue(name);
if (!port->wq) {
- pr_err("%s: Unable to create workqueue:%s\n",
- __func__, ctrl_bridge_names[portno]);
+ pr_err("%s: Unable to create workqueue:%s\n", __func__, name);
return -ENOMEM;
}
@@ -441,7 +456,7 @@
INIT_WORK(&port->connect_w, ghsic_ctrl_connect_w);
INIT_WORK(&port->disconnect_w, gctrl_disconnect_w);
- port->brdg.ch_id = portno;
+ port->brdg.name = name;
port->brdg.ctx = port;
port->brdg.ops.send_pkt = ghsic_ctrl_receive;
if (port->gtype == USB_GADGET_SERIAL)
@@ -451,7 +466,7 @@
pdrv = &gctrl_ports[portno].pdrv;
pdrv->probe = ghsic_ctrl_probe;
pdrv->remove = ghsic_ctrl_remove;
- pdrv->driver.name = ctrl_bridge_names[portno];
+ pdrv->driver.name = name;
pdrv->driver.owner = THIS_MODULE;
platform_driver_register(pdrv);
@@ -461,6 +476,31 @@
return 0;
}
+/*portname will be used to find the bridge channel index*/
+void ghsic_ctrl_set_port_name(const char *name, const char *xport_type)
+{
+ static unsigned int port_num;
+
+ if (port_num >= NUM_PORTS) {
+ pr_err("%s: setting xport name for invalid port num %d\n",
+ __func__, port_num);
+ return;
+ }
+
+ /*if no xport name is passed set it to xport type e.g. hsic*/
+ if (!name)
+ strlcpy(gctrl_ports[port_num].port_name, xport_type,
+ BRIDGE_NAME_MAX_LEN);
+ else
+ strlcpy(gctrl_ports[port_num].port_name, name,
+ BRIDGE_NAME_MAX_LEN);
+
+ /*append _ctrl to get ctrl bridge name e.g. serial_hsic_ctrl*/
+ strlcat(gctrl_ports[port_num].port_name, "_ctrl", BRIDGE_NAME_MAX_LEN);
+
+ port_num++;
+}
+
int ghsic_ctrl_setup(unsigned int num_ports, enum gadget_type gtype)
{
int first_port_id = no_ctrl_ports;
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 44c36db..2f65dce 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -25,13 +25,6 @@
static unsigned int no_data_ports;
-static const char *data_bridge_names[] = {
- "dun_data_hsic0",
- "rmnet_data_hsic0"
-};
-
-#define DATA_BRIDGE_NAME_MAX_LEN 20
-
#define GHSIC_DATA_RMNET_RX_Q_SIZE 50
#define GHSIC_DATA_RMNET_TX_Q_SIZE 300
#define GHSIC_DATA_SERIAL_RX_Q_SIZE 10
@@ -130,6 +123,7 @@
static struct {
struct gdata_port *port;
struct platform_driver pdrv;
+ char port_name[BRIDGE_NAME_MAX_LEN];
} gdata_ports[NUM_PORTS];
static unsigned int get_timestamp(void);
@@ -585,19 +579,35 @@
spin_unlock_irqrestore(&port->rx_lock, flags);
}
+static int ghsic_data_get_port_id(const char *pdev_name)
+{
+ struct gdata_port *port;
+ int i;
+
+ for (i = 0; i < no_data_ports; i++) {
+ port = gdata_ports[i].port;
+ if (!strncmp(port->brdg.name, pdev_name, BRIDGE_NAME_MAX_LEN))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
static int ghsic_data_probe(struct platform_device *pdev)
{
struct gdata_port *port;
+ int id;
- pr_debug("%s: name:%s no_data_ports= %d\n",
- __func__, pdev->name, no_data_ports);
+ pr_debug("%s: name:%s no_data_ports= %d\n", __func__, pdev->name,
+ no_data_ports);
- if (pdev->id >= no_data_ports) {
- pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ id = ghsic_data_get_port_id(pdev->name);
+ if (id < 0 || id >= no_data_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, id);
return -EINVAL;
}
- port = gdata_ports[pdev->id].port;
+ port = gdata_ports[id].port;
set_bit(CH_READY, &port->bridge_sts);
/* if usb is online, try opening bridge */
@@ -613,15 +623,17 @@
struct gdata_port *port;
struct usb_ep *ep_in;
struct usb_ep *ep_out;
+ int id;
pr_debug("%s: name:%s\n", __func__, pdev->name);
- if (pdev->id >= no_data_ports) {
- pr_err("%s: invalid port: %d\n", __func__, pdev->id);
+ id = ghsic_data_get_port_id(pdev->name);
+ if (id < 0 || id >= no_data_ports) {
+ pr_err("%s: invalid port: %d\n", __func__, id);
return -EINVAL;
}
- port = gdata_ports[pdev->id].port;
+ port = gdata_ports[id].port;
ep_in = port->in;
if (ep_in)
@@ -657,15 +669,17 @@
{
struct gdata_port *port;
struct platform_driver *pdrv;
+ char *name;
port = kzalloc(sizeof(struct gdata_port), GFP_KERNEL);
if (!port)
return -ENOMEM;
- port->wq = create_singlethread_workqueue(data_bridge_names[port_num]);
+ name = gdata_ports[port_num].port_name;
+
+ port->wq = create_singlethread_workqueue(name);
if (!port->wq) {
- pr_err("%s: Unable to create workqueue:%s\n",
- __func__, data_bridge_names[port_num]);
+ pr_err("%s: Unable to create workqueue:%s\n", __func__, name);
kfree(port);
return -ENOMEM;
}
@@ -687,7 +701,7 @@
skb_queue_head_init(&port->rx_skb_q);
port->gtype = gtype;
- port->brdg.ch_id = port_num;
+ port->brdg.name = name;
port->brdg.ctx = port;
port->brdg.ops.send_pkt = ghsic_data_receive;
port->brdg.ops.unthrottle_tx = ghsic_data_unthrottle_tx;
@@ -696,7 +710,7 @@
pdrv = &gdata_ports[port_num].pdrv;
pdrv->probe = ghsic_data_probe;
pdrv->remove = ghsic_data_remove;
- pdrv->driver.name = data_bridge_names[port_num];
+ pdrv->driver.name = name;
pdrv->driver.owner = THIS_MODULE;
platform_driver_register(pdrv);
@@ -841,7 +855,7 @@
}
#if defined(CONFIG_DEBUG_FS)
-#define DEBUG_BUF_SIZE 1024
+#define DEBUG_DATA_BUF_SIZE 4096
static unsigned int record_timestamp;
module_param(record_timestamp, uint, S_IRUGO | S_IWUSR);
@@ -912,7 +926,7 @@
if (!record_timestamp)
return 0;
- buf = kzalloc(sizeof(char) * 4 * DEBUG_BUF_SIZE, GFP_KERNEL);
+ buf = kzalloc(sizeof(char) * DEBUG_DATA_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -922,7 +936,7 @@
for (dbg_inc(&i); i != dbg_data.idx; dbg_inc(&i)) {
if (!strnlen(dbg_data.buf[i], DBG_DATA_MSG))
continue;
- j += scnprintf(buf + j, (4 * DEBUG_BUF_SIZE) - j,
+ j += scnprintf(buf + j, DEBUG_DATA_BUF_SIZE - j,
"%s\n", dbg_data.buf[i]);
}
@@ -950,7 +964,7 @@
int i;
int temp = 0;
- buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ buf = kzalloc(sizeof(char) * DEBUG_DATA_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -961,7 +975,7 @@
pdrv = &gdata_ports[i].pdrv;
spin_lock_irqsave(&port->rx_lock, flags);
- temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+ temp += scnprintf(buf + temp, DEBUG_DATA_BUF_SIZE - temp,
"\nName: %s\n"
"#PORT:%d port#: %p\n"
"data_ch_open: %d\n"
@@ -986,7 +1000,7 @@
spin_unlock_irqrestore(&port->rx_lock, flags);
spin_lock_irqsave(&port->tx_lock, flags);
- temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+ temp += scnprintf(buf + temp, DEBUG_DATA_BUF_SIZE - temp,
"\n******DL INFO******\n\n"
"dpkts_to_usbhost: %lu\n"
"tx_buf_len: %u\n"
@@ -1089,6 +1103,31 @@
#endif
+/*portname will be used to find the bridge channel index*/
+void ghsic_data_set_port_name(const char *name, const char *xport_type)
+{
+ static unsigned int port_num;
+
+ if (port_num >= NUM_PORTS) {
+ pr_err("%s: setting xport name for invalid port num %d\n",
+ __func__, port_num);
+ return;
+ }
+
+ /*if no xport name is passed set it to xport type e.g. hsic*/
+ if (!name)
+ strlcpy(gdata_ports[port_num].port_name, xport_type,
+ BRIDGE_NAME_MAX_LEN);
+ else
+ strlcpy(gdata_ports[port_num].port_name, name,
+ BRIDGE_NAME_MAX_LEN);
+
+ /*append _data to get data bridge name: e.g. serial_hsic_data*/
+ strlcat(gdata_ports[port_num].port_name, "_data", BRIDGE_NAME_MAX_LEN);
+
+ port_num++;
+}
+
int ghsic_data_setup(unsigned num_ports, enum gadget_type gtype)
{
int first_port_id = no_data_ports;