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: Alexey Orishko <alexey.orishko@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
eb722d7a2e
commit
19694ac88d
|
@ -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 {
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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 @@ advance:
|
||||||
|
|
||||||
/* 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 @@ advance:
|
||||||
|
|
||||||
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 @@ advance:
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue