Commit 19694ac8 authored by Alexey Orishko's avatar Alexey Orishko Committed by David S. Miller

CDC NCM: release interfaces fix in unbind()

Changes:
- claim slave/data interface during bind() and release
 interfaces in unbind() unconditionally
- in case of error during bind(), release claimed data
 interface in the same function
- remove obsolited "*_claimed" entries from driver context
Signed-off-by: default avatarAlexey Orishko <alexey.orishko@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent eb722d7a
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
#include <linux/usb/usbnet.h> #include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h> #include <linux/usb/cdc.h>
#define DRIVER_VERSION "06-May-2011" #define DRIVER_VERSION "24-May-2011"
/* CDC NCM subclass 3.2.1 */ /* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
...@@ -134,8 +134,6 @@ struct cdc_ncm_ctx { ...@@ -134,8 +134,6 @@ struct cdc_ncm_ctx {
u16 tx_ndp_modulus; u16 tx_ndp_modulus;
u16 tx_seq; u16 tx_seq;
u16 connected; u16 connected;
u8 data_claimed;
u8 control_claimed;
}; };
static void cdc_ncm_tx_timeout(unsigned long arg); static void cdc_ncm_tx_timeout(unsigned long arg);
...@@ -460,17 +458,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) ...@@ -460,17 +458,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
del_timer_sync(&ctx->tx_timer); del_timer_sync(&ctx->tx_timer);
if (ctx->data_claimed) {
usb_set_intfdata(ctx->data, NULL);
usb_driver_release_interface(driver_of(ctx->intf), ctx->data);
}
if (ctx->control_claimed) {
usb_set_intfdata(ctx->control, NULL);
usb_driver_release_interface(driver_of(ctx->intf),
ctx->control);
}
if (ctx->tx_rem_skb != NULL) { if (ctx->tx_rem_skb != NULL) {
dev_kfree_skb_any(ctx->tx_rem_skb); dev_kfree_skb_any(ctx->tx_rem_skb);
ctx->tx_rem_skb = NULL; ctx->tx_rem_skb = NULL;
...@@ -495,7 +482,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -495,7 +482,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx == NULL) if (ctx == NULL)
goto error; return -ENODEV;
memset(ctx, 0, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx));
...@@ -568,46 +555,36 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -568,46 +555,36 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
/* check if we got everything */ /* check if we got everything */
if ((ctx->control == NULL) || (ctx->data == NULL) || if ((ctx->control == NULL) || (ctx->data == NULL) ||
(ctx->ether_desc == NULL)) (ctx->ether_desc == NULL) || (ctx->control != intf))
goto error; goto error;
/* claim interfaces, if any */ /* claim interfaces, if any */
if (ctx->data != intf) { temp = usb_driver_claim_interface(driver, ctx->data, dev);
temp = usb_driver_claim_interface(driver, ctx->data, dev); if (temp)
if (temp) goto error;
goto error;
ctx->data_claimed = 1;
}
if (ctx->control != intf) {
temp = usb_driver_claim_interface(driver, ctx->control, dev);
if (temp)
goto error;
ctx->control_claimed = 1;
}
iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
/* reset data interface */ /* reset data interface */
temp = usb_set_interface(dev->udev, iface_no, 0); temp = usb_set_interface(dev->udev, iface_no, 0);
if (temp) if (temp)
goto error; goto error2;
/* initialize data interface */ /* initialize data interface */
if (cdc_ncm_setup(ctx)) if (cdc_ncm_setup(ctx))
goto error; goto error2;
/* configure data interface */ /* configure data interface */
temp = usb_set_interface(dev->udev, iface_no, 1); temp = usb_set_interface(dev->udev, iface_no, 1);
if (temp) if (temp)
goto error; goto error2;
cdc_ncm_find_endpoints(ctx, ctx->data); cdc_ncm_find_endpoints(ctx, ctx->data);
cdc_ncm_find_endpoints(ctx, ctx->control); cdc_ncm_find_endpoints(ctx, ctx->control);
if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) || if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) ||
(ctx->status_ep == NULL)) (ctx->status_ep == NULL))
goto error; goto error2;
dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
...@@ -617,7 +594,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -617,7 +594,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress); temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
if (temp) if (temp)
goto error; goto error2;
dev_info(&dev->udev->dev, "MAC-Address: " dev_info(&dev->udev->dev, "MAC-Address: "
"0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
...@@ -642,38 +619,38 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -642,38 +619,38 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
ctx->tx_speed = ctx->rx_speed = 0; ctx->tx_speed = ctx->rx_speed = 0;
return 0; return 0;
error2:
usb_set_intfdata(ctx->control, NULL);
usb_set_intfdata(ctx->data, NULL);
usb_driver_release_interface(driver, ctx->data);
error: error:
cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]); cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
dev->data[0] = 0; dev->data[0] = 0;
dev_info(&dev->udev->dev, "Descriptor failure\n"); dev_info(&dev->udev->dev, "bind() failure\n");
return -ENODEV; return -ENODEV;
} }
static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
{ {
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
struct usb_driver *driver; struct usb_driver *driver = driver_of(intf);
if (ctx == NULL) if (ctx == NULL)
return; /* no setup */ return; /* no setup */
driver = driver_of(intf); /* disconnect master --> disconnect slave */
if (intf == ctx->control && ctx->data) {
usb_set_intfdata(ctx->data, NULL); usb_set_intfdata(ctx->data, NULL);
usb_set_intfdata(ctx->control, NULL);
usb_set_intfdata(ctx->intf, NULL);
/* release interfaces, if any */
if (ctx->data_claimed) {
usb_driver_release_interface(driver, ctx->data); usb_driver_release_interface(driver, ctx->data);
ctx->data_claimed = 0; ctx->data = NULL;
}
if (ctx->control_claimed) { } else if (intf == ctx->data && ctx->control) {
usb_set_intfdata(ctx->control, NULL);
usb_driver_release_interface(driver, ctx->control); usb_driver_release_interface(driver, ctx->control);
ctx->control_claimed = 0; ctx->control = NULL;
} }
usb_set_intfdata(ctx->intf, NULL);
cdc_ncm_free(ctx); cdc_ncm_free(ctx);
} }
......
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