Commit 734d37c6 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

USB: serial gadget: simplify endpoint handling

Switch serial gadget away from a *very* old idiom:  just remember
the endpoints we'll be using, instead of looking them up by name
each time.  This is a net code and data (globals) shrink.

Also fix a small memory leak in the rmmod path, by working the
same as the disconnect code.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: Al Borchers <alborchers@steinerpoint.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2c2d28a0
...@@ -198,10 +198,6 @@ static unsigned int gs_buf_get(struct gs_buf *gb, char *buf, ...@@ -198,10 +198,6 @@ static unsigned int gs_buf_get(struct gs_buf *gb, char *buf,
static struct gs_dev *gs_device; static struct gs_dev *gs_device;
static const char *EP_IN_NAME;
static const char *EP_OUT_NAME;
static const char *EP_NOTIFY_NAME;
static struct mutex gs_open_close_lock[GS_NUM_PORTS]; static struct mutex gs_open_close_lock[GS_NUM_PORTS];
...@@ -1217,13 +1213,8 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) ...@@ -1217,13 +1213,8 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
gs_free_req(gadget->ep0, dev->dev_ctrl_req); gs_free_req(gadget->ep0, dev->dev_ctrl_req);
dev->dev_ctrl_req = NULL; dev->dev_ctrl_req = NULL;
} }
gs_reset_config(dev);
gs_free_ports(dev); gs_free_ports(dev);
if (dev->dev_notify_ep)
usb_ep_disable(dev->dev_notify_ep);
if (dev->dev_in_ep)
usb_ep_disable(dev->dev_in_ep);
if (dev->dev_out_ep)
usb_ep_disable(dev->dev_out_ep);
kfree(dev); kfree(dev);
set_gadget_data(gadget, NULL); set_gadget_data(gadget, NULL);
} }
...@@ -1264,19 +1255,23 @@ static int __init gs_bind(struct usb_gadget *gadget) ...@@ -1264,19 +1255,23 @@ static int __init gs_bind(struct usb_gadget *gadget)
__constant_cpu_to_le16(GS_VERSION_NUM|0x0099); __constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
} }
dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
usb_ep_autoconfig_reset(gadget); usb_ep_autoconfig_reset(gadget);
ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
if (!ep) if (!ep)
goto autoconf_fail; goto autoconf_fail;
EP_IN_NAME = ep->name; dev->dev_in_ep = ep;
ep->driver_data = ep; /* claim the endpoint */ ep->driver_data = dev; /* claim the endpoint */
ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
if (!ep) if (!ep)
goto autoconf_fail; goto autoconf_fail;
EP_OUT_NAME = ep->name; dev->dev_out_ep = ep;
ep->driver_data = ep; /* claim the endpoint */ ep->driver_data = dev; /* claim the endpoint */
if (use_acm) { if (use_acm) {
ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc); ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
...@@ -1286,8 +1281,8 @@ static int __init gs_bind(struct usb_gadget *gadget) ...@@ -1286,8 +1281,8 @@ static int __init gs_bind(struct usb_gadget *gadget)
} }
gs_device_desc.idProduct = __constant_cpu_to_le16( gs_device_desc.idProduct = __constant_cpu_to_le16(
GS_CDC_PRODUCT_ID), GS_CDC_PRODUCT_ID),
EP_NOTIFY_NAME = ep->name; dev->dev_notify_ep = ep;
ep->driver_data = ep; /* claim the endpoint */ ep->driver_data = dev; /* claim the endpoint */
} }
gs_device_desc.bDeviceClass = use_acm gs_device_desc.bDeviceClass = use_acm
...@@ -1317,9 +1312,7 @@ static int __init gs_bind(struct usb_gadget *gadget) ...@@ -1317,9 +1312,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL); gs_device = dev;
if (dev == NULL)
return -ENOMEM;
snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
init_utsname()->sysname, init_utsname()->release, init_utsname()->sysname, init_utsname()->release,
...@@ -1351,6 +1344,7 @@ static int __init gs_bind(struct usb_gadget *gadget) ...@@ -1351,6 +1344,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
return 0; return 0;
autoconf_fail: autoconf_fail:
kfree(dev);
pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name); pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
return -ENODEV; return -ENODEV;
} }
...@@ -1710,7 +1704,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) ...@@ -1710,7 +1704,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
int ret = 0; int ret = 0;
struct usb_gadget *gadget = dev->dev_gadget; struct usb_gadget *gadget = dev->dev_gadget;
struct usb_ep *ep; struct usb_ep *ep;
struct usb_endpoint_descriptor *ep_desc; struct usb_endpoint_descriptor *out, *in, *notify;
struct usb_request *req; struct usb_request *req;
if (dev == NULL) { if (dev == NULL) {
...@@ -1738,71 +1732,53 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) ...@@ -1738,71 +1732,53 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
return -EINVAL; return -EINVAL;
} }
dev->dev_config = config; in = choose_ep_desc(gadget,
&gs_highspeed_in_desc,
gadget_for_each_ep(ep, gadget) { &gs_fullspeed_in_desc);
out = choose_ep_desc(gadget,
if (EP_NOTIFY_NAME &gs_highspeed_out_desc,
&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) { &gs_fullspeed_out_desc);
ep_desc = choose_ep_desc(gadget, notify = dev->dev_notify_ep
? choose_ep_desc(gadget,
&gs_highspeed_notify_desc, &gs_highspeed_notify_desc,
&gs_fullspeed_notify_desc); &gs_fullspeed_notify_desc)
ret = usb_ep_enable(ep,ep_desc); : NULL;
if (ret == 0) {
ep->driver_data = dev;
dev->dev_notify_ep = ep;
dev->dev_notify_ep_desc = ep_desc;
} else {
pr_err("gs_set_config: cannot enable NOTIFY "
"endpoint %s, ret=%d\n",
ep->name, ret);
goto exit_reset_config;
}
}
else if (strcmp(ep->name, EP_IN_NAME) == 0) { ret = usb_ep_enable(dev->dev_in_ep, in);
ep_desc = choose_ep_desc(gadget, if (ret == 0) {
&gs_highspeed_in_desc, dev->dev_in_ep_desc = in;
&gs_fullspeed_in_desc); } else {
ret = usb_ep_enable(ep,ep_desc); pr_debug("%s: cannot enable %s %s, ret=%d\n",
if (ret == 0) { __func__, "IN", dev->dev_in_ep->name, ret);
ep->driver_data = dev; return ret;
dev->dev_in_ep = ep; }
dev->dev_in_ep_desc = ep_desc;
} else {
pr_err("gs_set_config: cannot enable IN "
"endpoint %s, ret=%d\n",
ep->name, ret);
goto exit_reset_config;
}
}
else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
ep_desc = choose_ep_desc(gadget,
&gs_highspeed_out_desc,
&gs_fullspeed_out_desc);
ret = usb_ep_enable(ep,ep_desc);
if (ret == 0) {
ep->driver_data = dev;
dev->dev_out_ep = ep;
dev->dev_out_ep_desc = ep_desc;
} else {
pr_err("gs_set_config: cannot enable OUT "
"endpoint %s, ret=%d\n",
ep->name, ret);
goto exit_reset_config;
}
}
ret = usb_ep_enable(dev->dev_out_ep, out);
if (ret == 0) {
dev->dev_out_ep_desc = out;
} else {
pr_debug("%s: cannot enable %s %s, ret=%d\n",
__func__, "OUT", dev->dev_out_ep->name, ret);
fail0:
usb_ep_disable(dev->dev_in_ep);
return ret;
} }
if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL if (notify) {
|| (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) { ret = usb_ep_enable(dev->dev_notify_ep, notify);
pr_err("gs_set_config: cannot find endpoints\n"); if (ret == 0) {
ret = -ENODEV; dev->dev_notify_ep_desc = notify;
goto exit_reset_config; } else {
pr_debug("%s: cannot enable %s %s, ret=%d\n",
__func__, "NOTIFY",
dev->dev_notify_ep->name, ret);
usb_ep_disable(dev->dev_out_ep);
goto fail0;
}
} }
dev->dev_config = config;
/* allocate and queue read requests */ /* allocate and queue read requests */
ep = dev->dev_out_ep; ep = dev->dev_out_ep;
for (i=0; i<read_q_size && ret == 0; i++) { for (i=0; i<read_q_size && ret == 0; i++) {
...@@ -1886,18 +1862,10 @@ static void gs_reset_config(struct gs_dev *dev) ...@@ -1886,18 +1862,10 @@ static void gs_reset_config(struct gs_dev *dev)
/* disable endpoints, forcing completion of pending i/o; */ /* disable endpoints, forcing completion of pending i/o; */
/* completion handlers free their requests in this case */ /* completion handlers free their requests in this case */
if (dev->dev_notify_ep) { if (dev->dev_notify_ep)
usb_ep_disable(dev->dev_notify_ep); usb_ep_disable(dev->dev_notify_ep);
dev->dev_notify_ep = NULL; usb_ep_disable(dev->dev_in_ep);
} usb_ep_disable(dev->dev_out_ep);
if (dev->dev_in_ep) {
usb_ep_disable(dev->dev_in_ep);
dev->dev_in_ep = NULL;
}
if (dev->dev_out_ep) {
usb_ep_disable(dev->dev_out_ep);
dev->dev_out_ep = NULL;
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment