aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/usb/sipc_hsic.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/net/usb/sipc_hsic.c b/drivers/net/usb/sipc_hsic.c
index 1809480cd5dd..e32acb07f1c0 100644
--- a/drivers/net/usb/sipc_hsic.c
+++ b/drivers/net/usb/sipc_hsic.c
@@ -32,6 +32,9 @@ struct sipc_usb_ep {
struct sipc_link_callback *cb;
struct usb_device *udev;
struct usb_interface *data_intf;
+
+ spinlock_t rx_lock; /* Protects disconnects */
+ bool disconnected;
};
#define linkops_to_ep(ops) container_of(ops, struct sipc_usb_ep, link_ops)
@@ -73,8 +76,16 @@ static void sipc_rx_complete(struct urb *urb)
static int sipc_start_rx(struct sipc_usb_ep *ep)
{
struct urb *urb;
+ unsigned long flags;
int ret;
+ spin_lock_irqsave(&ep->rx_lock, flags);
+
+ if (ep->disconnected) {
+ spin_unlock_irqrestore(&ep->rx_lock, flags);
+ return -ENODEV;
+ }
+
urb = ep->in_urb;
urb->transfer_flags = 0;
usb_fill_bulk_urb(urb, ep->udev,
@@ -83,6 +94,8 @@ static int sipc_start_rx(struct sipc_usb_ep *ep)
ep);
ret = usb_submit_urb(urb, GFP_ATOMIC);
+ spin_unlock_irqrestore(&ep->rx_lock, flags);
+
if (ret)
dev_err(&ep->udev->dev, "Failed to submit rx urb: %d\n", ret);
@@ -259,6 +272,8 @@ static int sipc_probe(struct usb_interface *intf,
}
}
+ spin_lock_init(&ep->rx_lock);
+
sipc_start_rx(ep);
return 0;
@@ -273,6 +288,8 @@ static void sipc_disconnect(struct usb_interface *intf)
struct sipc_usb_ep *ep = usb_get_intfdata(intf);
int fmt;
+ ep->disconnected = true;
+
fmt = usb_to_sipc_format(ep->ep);
if (fmt < 0)
goto invalid_format;