Skip to content

Commit

Permalink
USB: Patch for rtl8150 to fix unplug problems
Browse files Browse the repository at this point in the history
The RTL8150 driver currently crashes the kernel if the USB lead is unplugged
while the device is active.  The attached patch adds error handling to
tell the network layer that the device has gone away when the device is
unplugged.  With this patch, the device can be plugged and unplugged
to one's hearts' content, without crashing anything.

Oh, I've also added rudimentary suspend and resume methods.

Signed-off-by: Peter Chubb <peter@gelato.unsw.edu.au>
Acked-by: Petko Manolov <petkan@nucleusys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Peter Chubb authored and Greg Kroah-Hartman committed Aug 2, 2006
1 parent 6ad576b commit 23219c1
Showing 1 changed file with 71 additions and 12 deletions.
83 changes: 71 additions & 12 deletions drivers/usb/net/rtl8150.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ static inline struct sk_buff *pull_skb(rtl8150_t *);
static void rtl8150_disconnect(struct usb_interface *intf);
static int rtl8150_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message);
static int rtl8150_resume(struct usb_interface *intf);

static const char driver_name [] = "rtl8150";

Expand All @@ -183,6 +185,8 @@ static struct usb_driver rtl8150_driver = {
.probe = rtl8150_probe,
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
.suspend = rtl8150_suspend,
.resume = rtl8150_resume
};

/*
Expand Down Expand Up @@ -238,9 +242,11 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
usb_fill_control_urb(dev->ctrl_urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
&dev->rx_creg, size, ctrl_callback, dev);
if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
if (ret == -ENODEV)
netif_device_detach(dev->netdev);
err("control request submission failed: %d", ret);
else
} else
set_bit(RX_REG_SET, &dev->flags);

return ret;
Expand Down Expand Up @@ -416,6 +422,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
struct sk_buff *skb;
struct net_device *netdev;
u16 rx_stat;
int status;

dev = urb->context;
if (!dev)
Expand Down Expand Up @@ -465,7 +472,10 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
goon:
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
if (status == -ENODEV)
netif_device_detach(dev->netdev);
else if (status) {
set_bit(RX_URB_FAIL, &dev->flags);
goto resched;
} else {
Expand All @@ -481,6 +491,7 @@ static void rx_fixup(unsigned long data)
{
rtl8150_t *dev;
struct sk_buff *skb;
int status;

dev = (rtl8150_t *)data;

Expand All @@ -499,10 +510,13 @@ static void rx_fixup(unsigned long data)
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
try_again:
if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
if (status == -ENODEV) {
netif_device_detach(dev->netdev);
} else if (status) {
set_bit(RX_URB_FAIL, &dev->flags);
goto tlsched;
} else {
} else {
clear_bit(RX_URB_FAIL, &dev->flags);
}

Expand Down Expand Up @@ -574,12 +588,43 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)

resubmit:
status = usb_submit_urb (urb, SLAB_ATOMIC);
if (status)
if (status == -ENODEV)
netif_device_detach(dev->netdev);
else if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
dev->udev->bus->bus_name,
dev->udev->devpath, status);
}

static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
{
rtl8150_t *dev = usb_get_intfdata(intf);

netif_device_detach(dev->netdev);

if (netif_running(dev->netdev)) {
usb_kill_urb(dev->rx_urb);
usb_kill_urb(dev->intr_urb);
}
return 0;
}

static int rtl8150_resume(struct usb_interface *intf)
{
rtl8150_t *dev = usb_get_intfdata(intf);

netif_device_attach(dev->netdev);
if (netif_running(dev->netdev)) {
dev->rx_urb->status = 0;
dev->rx_urb->actual_length = 0;
read_bulk_callback(dev->rx_urb, NULL);

dev->intr_urb->status = 0;
dev->intr_urb->actual_length = 0;
intr_callback(dev->intr_urb, NULL);
}
return 0;
}

/*
**
Expand Down Expand Up @@ -690,9 +735,14 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
skb->data, count, write_bulk_callback, dev);
if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
warn("failed tx_urb %d\n", res);
dev->stats.tx_errors++;
netif_start_queue(netdev);
/* Can we get/handle EPIPE here? */
if (res == -ENODEV)
netif_device_detach(dev->netdev);
else {
warn("failed tx_urb %d\n", res);
dev->stats.tx_errors++;
netif_start_queue(netdev);
}
} else {
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
Expand Down Expand Up @@ -729,16 +779,25 @@ static int rtl8150_open(struct net_device *netdev)

usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
if (res == -ENODEV)
netif_device_detach(dev->netdev);
warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
return res;
}
usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
dev->intr_buff, INTBUFSIZE, intr_callback,
dev, dev->intr_interval);
if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
if (res == -ENODEV)
netif_device_detach(dev->netdev);
warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
netif_start_queue(netdev);
usb_kill_urb(dev->rx_urb);
return res;
}
enable_net_traffic(dev);
set_carrier(netdev);
netif_start_queue(netdev);

return res;
}
Expand Down

0 comments on commit 23219c1

Please sign in to comment.