# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.493 -> 1.494 # drivers/usb/net/kaweth.c 1.17 -> 1.18 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/04/16 oliver@oenone.homelinux.org 1.494 # [PATCH] kaweth usb driver updates # # USB kaweth driver updates # # - fixed race between close and disconnect # - disconnect bug # - add link state reporting # - fix an urb reference counting bug # - fix probe oopsability on oom # - groundwork for atomic pool depletion # - cosmetic changes # -------------------------------------------- # diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c --- a/drivers/usb/net/kaweth.c Tue Apr 16 11:35:35 2002 +++ b/drivers/usb/net/kaweth.c Tue Apr 16 11:35:35 2002 @@ -100,8 +100,14 @@ #define KAWETH_SOFS_TO_WAIT 0x05 +#define INTBUFFERSIZE 4 -MODULE_AUTHOR("Michael Zappe , Stephane Alnet and Brad Hards "); +#define STATE_OFFSET 0 +#define STATE_MASK 0x40 +#define STATE_SHIFT 5 + + +MODULE_AUTHOR("Michael Zappe , Stephane Alnet , Brad Hards and Oliver Neukum "); MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); MODULE_LICENSE("GPL"); @@ -203,6 +209,8 @@ __u32 status; int end; int removed; + int suspend_lowmem; + int linkstate; struct usb_device *dev; struct net_device *net; @@ -210,10 +218,12 @@ struct urb *rx_urb; struct urb *tx_urb; + struct urb *irq_urb; __u8 firmware_buf[KAWETH_FIRMWARE_BUF_SIZE]; __u8 tx_buf[KAWETH_BUF_SIZE]; __u8 rx_buf[KAWETH_BUF_SIZE]; + __u8 intbuffer[INTBUFFERSIZE]; __u16 packet_filter_bitmap; struct kaweth_ethernet_configuration configuration; @@ -448,17 +458,40 @@ } static void kaweth_usb_receive(struct urb *); +static void kaweth_resubmit_rx_urb(struct kaweth_device *, int); + +/**************************************************************** + int_callback +*****************************************************************/ +static void int_callback(struct urb *u) +{ + struct kaweth_device *kaweth = u->context; + int act_state; + + /* we abuse the interrupt urb for rebsubmitting under low memory saving a timer */ + if (kaweth->suspend_lowmem) + kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); + + /* we check the link state to report changes */ + if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { + if (!act_state) + netif_carrier_on(kaweth->net); + else + netif_carrier_off(kaweth->net); + + kaweth->linkstate = act_state; + } + +} /**************************************************************** * kaweth_resubmit_rx_urb ****************************************************************/ -static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, +static void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, int mem_flags) { int result; - memset(kaweth->rx_urb, 0, sizeof(*kaweth->rx_urb)); - FILL_BULK_URB(kaweth->rx_urb, kaweth->dev, usb_rcvbulkpipe(kaweth->dev, 1), @@ -468,7 +501,11 @@ kaweth); if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { + if (result == -ENOMEM) + kaweth->suspend_lowmem = 1; kaweth_err("resubmitting rx_urb %d failed", result); + } else { + kaweth->suspend_lowmem = 0; } } @@ -489,10 +526,6 @@ struct sk_buff *skb; - if(kaweth->status & KAWETH_STATUS_CLOSING) { - return; - } - if(unlikely(urb->status == -ECONNRESET || urb->status == -ECONNABORTED)) /* we are killed - set a flag and wake the disconnect handler */ { @@ -501,6 +534,9 @@ return; } + if (kaweth->status & KAWETH_STATUS_CLOSING) + return; + if(urb->status && urb->status != -EREMOTEIO && count != 1) { kaweth_err("%s RX status: %d count: %d packet_len: %d", net->name, @@ -557,6 +593,18 @@ kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); + FILL_INT_URB( + kaweth->irq_urb, + kaweth->dev, + usb_rcvintpipe(kaweth->dev, 3), + kaweth->intbuffer, + INTBUFFERSIZE, + int_callback, + kaweth, + HZ/4); + + usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); + netif_start_queue(net); kaweth_async_set_rx_mode(kaweth); @@ -574,6 +622,7 @@ kaweth->status |= KAWETH_STATUS_CLOSING; + usb_unlink_urb(kaweth->irq_urb); usb_unlink_urb(kaweth->rx_urb); kaweth->status &= ~KAWETH_STATUS_CLOSING; @@ -632,8 +681,6 @@ memcpy(kaweth->tx_buf + 2, skb->data, skb->len); - memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb)); - FILL_BULK_URB(kaweth->tx_urb, kaweth->dev, usb_sndbulkpipe(kaweth->dev, 2), @@ -896,7 +943,14 @@ kaweth_dbg("Initializing net device."); kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kaweth->tx_urb) + goto err_no_urb; kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kaweth->rx_urb) + goto err_only_tx; + kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kaweth->irq_urb) + goto err_tx_and_rx; kaweth->net = init_etherdev(0, 0); if (!kaweth->net) { @@ -929,6 +983,14 @@ kaweth_dbg("Kaweth probe returning."); return kaweth; + +err_tx_and_rx: + usb_free_urb(kaweth->rx_urb); +err_only_tx: + usb_free_urb(kaweth->tx_urb); +err_no_urb: + kfree(kaweth); + return NULL; } /**************************************************************** @@ -946,6 +1008,7 @@ } kaweth->removed = 1; + usb_unlink_urb(kaweth->irq_urb); usb_unlink_urb(kaweth->rx_urb); /* we need to wait for the urb to be cancelled, if it is active */ @@ -1088,6 +1151,7 @@ module_init(kaweth_init); module_exit(kaweth_exit); +