From: Stephen H. <she...@os...> - 2004-02-20 01:04:32
|
Please give this driver some more work before I push the update to Dave. Changes: * viro's disconnect feedback * async unlink of receive requests to avoid waiting for each one individually. * in fir, copy small receive packets * in fir, use get_unaligned(le32_to_cpu(..)) rather than explicit shifts * in fir, don't turnaround prematurely just because of a error (like crc) * separate sir and fir polling intervals * slightly better reset, change speed logic * transmit path formats wrapped data into a skbuff which allows wrapping in parallel with usb transfer, and avoids allocating a fixed size buffer. * some code cleanup of the txwait path * use do_gettimeofday() rather than CURRENT_TIME for better resolution Tested with two different vendor dongles and against nsc-ircc. diff -Nru a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c --- a/drivers/net/irda/stir4200.c Thu Feb 19 16:29:02 2004 +++ b/drivers/net/irda/stir4200.c Thu Feb 19 16:29:02 2004 @@ -49,12 +49,15 @@ #include <linux/suspend.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/crc32.h> #include <net/irda/irda.h> #include <net/irda/irlap.h> #include <net/irda/irda_device.h> #include <net/irda/wrapper.h> #include <net/irda/crc.h> -#include <linux/crc32.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> + MODULE_AUTHOR("Stephen Hemminger <she...@os...>"); MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200"); @@ -72,14 +75,19 @@ module_param(tx_power, int, 0); MODULE_PARM_DESC(tx_power, "Set Transmitter power (0-3, 0 is highest power)"); -static int rx_interval = 5; /* milliseconds */ -module_param(rx_interval, int, 0); -MODULE_PARM_DESC(rx_interval, "Receive polling interval (ms)"); +static int fir_interval = 1; /* milliseconds */ +module_param(fir_interval, int, 0); +MODULE_PARM_DESC(fir_interval, "Fast IR polling interval (ms)"); + +static int sir_interval = 5; /* milliseconds */ +module_param(sir_interval, int, 0); +MODULE_PARM_DESC(sir_interval, "Slow IR polling interval (ms)"); #define STIR_IRDA_HEADER 4 #define CTRL_TIMEOUT 100 /* milliseconds */ #define TRANSMIT_TIMEOUT 200 /* milliseconds */ #define STIR_FIFO_SIZE 4096 +#define STIR_RX_SIZE STIR_FIFO_SIZE #define NUM_RX_URBS 2 enum FirChars { @@ -167,18 +175,12 @@ TEST_TSTOSC = 0x0F, }; -enum StirState { - STIR_STATE_RECEIVING=0, - STIR_STATE_TXREADY, -}; - struct stir_cb { struct usb_device *usbdev; /* init: probe_irda */ struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ struct net_device_stats stats; /* network statistics */ struct qos_info qos; - unsigned long state; unsigned speed; /* Current speed */ wait_queue_head_t thr_wait; /* transmit thread wakeup */ @@ -186,14 +188,14 @@ pid_t thr_pid; unsigned int tx_bulkpipe; - void *tx_data; /* wrapped data out */ - unsigned tx_len; - unsigned tx_newspeed; - unsigned tx_mtt; + struct sk_buff *tx_pending; /* wrapped data out */ unsigned int rx_intpipe; iobuff_t rx_buff; /* receive unwrap state machine */ - struct timespec rx_time; + struct timeval rx_time; + struct completion rx_stop_complete; + int rx_receiving; + atomic_t rx_pending; struct urb *rx_urbs[NUM_RX_URBS]; void *rx_data[NUM_RX_URBS]; @@ -209,7 +211,6 @@ MODULE_DEVICE_TABLE(usb, dongles); -static int fifo_txwait(struct stir_cb *stir, unsigned space); static void stir_usb_receive(struct urb *urb, struct pt_regs *regs); /* Send control message to set dongle register */ @@ -310,12 +311,13 @@ return wraplen + STIR_IRDA_HEADER; } -static unsigned wrap_sir_skb(struct sk_buff *skb, __u8 *buf) +static unsigned wrap_sir_skb(struct sk_buff *skb, __u8 *buf, + unsigned space) { __u16 wraplen; - wraplen = async_wrap_skb(skb, buf + STIR_IRDA_HEADER, - STIR_FIFO_SIZE - STIR_IRDA_HEADER); + wraplen = async_wrap_skb(skb, buf + STIR_IRDA_HEADER, + space - STIR_IRDA_HEADER); buf[0] = 0x55; buf[1] = 0xAA; buf[2] = wraplen & 0xff; @@ -329,60 +331,63 @@ * and pass up to irlap * setup for next receive */ -static void fir_eof(struct stir_cb *stir) +static int fir_eof(struct stir_cb *stir) { iobuff_t *rx_buff = &stir->rx_buff; int len = rx_buff->len - 4; + struct sk_buff *skb; __u32 fcs; - struct sk_buff *nskb; if (unlikely(len <= 0)) { pr_debug("%s: short frame len %d\n", stir->netdev->name, len); - - ++stir->stats.rx_errors; ++stir->stats.rx_length_errors; - return; + goto err_out; } - fcs = rx_buff->data[len] | - rx_buff->data[len+1] << 8 | - rx_buff->data[len+2] << 16 | - rx_buff->data[len+3] << 24; - - if (unlikely(fcs != ~(crc32_le(~0, rx_buff->data, len)))) { + fcs = le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len))); + if (fcs != ~(crc32_le(~0, rx_buff->data, len))) { pr_debug("%s: crc error\n", stir->netdev->name); - irda_device_set_media_busy(stir->netdev, TRUE); - stir->stats.rx_errors++; stir->stats.rx_crc_errors++; - return; + goto err_out; } - /* If can't get new buffer, just drop and reuse */ - nskb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (unlikely(!nskb)) - ++stir->stats.rx_dropped; - else { - struct sk_buff *oskb = rx_buff->skb; + /* if frame is short then just copy it */ + if (len < IRDA_RX_COPY_THRESHOLD) { + skb = dev_alloc_skb(len + 1); + if (unlikely(!skb)) + goto nomem; + skb_reserve(skb, 1); + memcpy(skb->data, rx_buff->data, len); + } else { + struct sk_buff *nskb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (unlikely(!nskb)) + goto nomem; + + skb = rx_buff->skb; skb_reserve(nskb, 1); + rx_buff->skb = nskb; + rx_buff->head = nskb->data; + } - /* Set correct length in socket buffer */ - skb_put(oskb, len); + skb_put(skb, len); - oskb->mac.raw = oskb->data; - oskb->protocol = htons(ETH_P_IRDA); - oskb->dev = stir->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + skb->dev = stir->netdev; - netif_rx(oskb); + netif_rx(skb); - stir->stats.rx_packets++; - stir->stats.rx_bytes += len; - rx_buff->skb = nskb; - rx_buff->head = nskb->data; - } + stir->stats.rx_packets++; + stir->stats.rx_bytes += len; rx_buff->data = rx_buff->head; rx_buff->len = 0; + return 0; + nomem: + ++stir->stats.rx_dropped; + err_out: + return 1; } /* Unwrap FIR stuffed data and bump it to IrLAP */ @@ -439,7 +444,8 @@ case FIR_EOF: rx_buff->state = OUTSIDE_FRAME; rx_buff->in_frame = FALSE; - fir_eof(stir); + if (fir_eof(stir)) + goto error_recovery; continue; } break; @@ -461,7 +467,6 @@ error_recovery: ++stir->stats.rx_errors; - irda_device_set_media_busy(stir->netdev, TRUE); rx_buff->state = OUTSIDE_FRAME; rx_buff->in_frame = FALSE; } @@ -519,7 +524,6 @@ int i, err; __u8 mode; - pr_debug("%s: change speed %d\n", stir->netdev->name, speed); for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) { if (speed == stir_modes[i].speed) goto found; @@ -532,12 +536,15 @@ pr_debug("%s: speed change from %d to %d\n", stir->netdev->name, stir->speed, speed); - /* Make sure any previous Tx is really finished. This happens - * when we answer an incomming request ; the ua:rsp and the - * speed change are bundled together, so we need to wait until - * the packet we just submitted has been sent. Jean II */ - if (fifo_txwait(stir, 0)) - return -EIO; + /* Reset modulator */ + err = write_reg(stir, REG_CTRL1, CTRL1_SRESET); + if (err) + goto out; + + /* Undocumented magic to tweak the DPLL */ + err = write_reg(stir, REG_DPLL, 0x15); + if (err) + goto out; /* Set clock */ err = write_reg(stir, REG_PDCLK, stir_modes[i].pdclk); @@ -564,33 +571,13 @@ goto out; err = write_reg(stir, REG_CTRL1, (tx_power & 3) << 1); - - out: - stir->speed = speed; - return err; -} - -static int stir_reset(struct stir_cb *stir) -{ - int err; - - /* reset state */ - stir->rx_buff.in_frame = FALSE; - stir->rx_buff.state = OUTSIDE_FRAME; - stir->speed = -1; - - /* Undocumented magic to tweak the DPLL */ - err = write_reg(stir, REG_DPLL, 0x15); if (err) goto out; /* Reset sensitivity */ err = write_reg(stir, REG_CTRL2, (rx_sensitivity & 7) << 5); - if (err) - goto out; - - err = change_speed(stir, 9600); out: + stir->speed = speed; return err; } @@ -600,50 +587,69 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev) { struct stir_cb *stir = netdev->priv; + struct sk_buff *nskb; + unsigned maxlen; netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ SKB_LINEAR_ASSERT(skb); - if (unlikely(skb->len) == 0) /* speed change only */ - stir->tx_len = 0; - else if (isfir(stir->speed)) - stir->tx_len = wrap_fir_skb(skb, stir->tx_data); - else - stir->tx_len = wrap_sir_skb(skb, stir->tx_data); - - stir->stats.tx_packets++; - stir->stats.tx_bytes += skb->len; + /* need enough space for worst case */ + maxlen = STIR_IRDA_HEADER + irda_get_xbofs(skb) + + 2 * skb->len + 10; - stir->tx_mtt = irda_get_mtt(skb); - stir->tx_newspeed = irda_get_next_speed(skb); + nskb = dev_alloc_skb(maxlen); + if (!nskb) { + stir->stats.tx_errors++; + return 0; + } + + /* copy cb containing speed and mtt info */ + memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); + + /* speed change only */ + if (skb->len > 0) { + unsigned wraplen; - if (!test_and_set_bit(STIR_STATE_TXREADY, &stir->state)) - wake_up(&stir->thr_wait); + if (isfir(stir->speed)) + wraplen = wrap_fir_skb(skb, nskb->data); + else + wraplen = wrap_sir_skb(skb, nskb->data, maxlen); + + skb_put(nskb, wraplen); + stir->stats.tx_packets++; + stir->stats.tx_bytes += skb->len; + } dev_kfree_skb(skb); + + skb = xchg(&stir->tx_pending, nskb); + + BUG_ON(skb != NULL); /* stop/wakeup logic error */ + wake_up(&stir->thr_wait); + return 0; } /* * Wait for the transmit FIFO to have space for next data + * + * If space < 0 then wait till FIFO completely drains. + * FYI: can take up to 13 seconds at 2400baud. */ -static int fifo_txwait(struct stir_cb *stir, unsigned space) +static int fifo_txwait(struct stir_cb *stir, int space) { int err; - unsigned count; __u8 regs[3]; - unsigned long timeout = jiffies + HZ/10; - for(;;) { - /* Read FIFO status and count */ - err = read_reg(stir, REG_FIFOCTL, regs, 3); - if (unlikely(err != 3)) { - WARNING("%s: FIFO register read error: %d\n", - stir->netdev->name, err); - return err; - } + /* Read FIFO status and count */ + while ((err = read_reg(stir, REG_FIFOCTL, regs, 3)) == 3) { + unsigned count; + + count = (unsigned)(regs[2] & 0x1f) << 8 | regs[1]; + pr_debug("%s: fifo status 0x%x count %u\n", + stir->netdev->name, regs[0], count); /* is fifo receiving already, or empty */ if (!(regs[0] & FIFOCTL_DIR) @@ -658,40 +664,32 @@ || !netif_device_present(stir->netdev)) return -ESHUTDOWN; - count = (unsigned)(regs[2] & 0x1f) << 8 | regs[1]; - - pr_debug("%s: fifo status 0x%x count %u\n", - stir->netdev->name, regs[0], count); - /* only waiting for some space */ - if (space && STIR_FIFO_SIZE - 4 > space + count) + if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count) return 0; - if (time_after(jiffies, timeout)) { - WARNING("%s: transmit fifo timeout status=0x%x count=%d\n", - stir->netdev->name, regs[0], count); - ++stir->stats.tx_errors; - irda_device_set_media_busy(stir->netdev, TRUE); - return -ETIMEDOUT; - } - /* estimate transfer time for remaining chars */ - wait_ms((count * 8000) / stir->speed); + wait_ms( (count * 8000) / stir->speed); } + + WARNING("%s: FIFO register read error: %d\n", + stir->netdev->name, err); + return err; } /* Wait for turnaround delay before starting transmit. */ -static void turnaround_delay(long us, const struct timespec *last) +static void turnaround_delay(const struct stir_cb *stir, long us) { long ticks; - struct timespec now = CURRENT_TIME; + struct timeval now; if (us <= 0) return; - us -= (now.tv_sec - last->tv_sec) * USEC_PER_SEC; - us -= (now.tv_nsec - last->tv_nsec) / NSEC_PER_USEC; + do_gettimeofday(&now); + us -= (now.tv_sec - stir->rx_time.tv_sec) * USEC_PER_SEC; + us -= now.tv_usec - stir->rx_time.tv_usec; if (us < 10) return; @@ -711,31 +709,28 @@ { int i; - if (test_and_set_bit(STIR_STATE_RECEIVING, &stir->state)) - return; - - if (fifo_txwait(stir, 0)) - return; - + /* reset state */ + stir->rx_buff.in_frame = FALSE; + stir->rx_buff.state = OUTSIDE_FRAME; + stir->rx_receiving = 1; + wmb(); for (i = 0; i < NUM_RX_URBS; i++) { struct urb *urb = stir->rx_urbs[i]; + urb->status = 0; usb_fill_int_urb(urb, stir->usbdev, stir->rx_intpipe, - stir->rx_data[i], STIR_FIFO_SIZE, - stir_usb_receive, stir, rx_interval); + stir->rx_data[i], STIR_RX_SIZE, + stir_usb_receive, stir, + isfir(stir->speed) ? fir_interval + : sir_interval); + urb->transfer_flags = URB_ASYNC_UNLINK; - if (usb_submit_urb(urb, GFP_KERNEL)) - urb->status = -EINVAL; + if (0 == usb_submit_urb(urb, GFP_KERNEL)) + atomic_inc(&stir->rx_pending); } - if (i == 0) { - /* if nothing got queued, then just retry next time */ - if (net_ratelimit()) - WARNING("%s: no receive buffers avaiable\n", - stir->netdev->name); - - clear_bit(STIR_STATE_RECEIVING, &stir->state); - } + if (atomic_read(&stir->rx_pending) == 0) + stir->rx_receiving = 0; } /* Stop all pending receive Urb's */ @@ -743,34 +738,34 @@ { int i; - for (i = 0; i < NUM_RX_URBS; i++) { - struct urb *urb = stir->rx_urbs[i]; - usb_unlink_urb(urb); - } + stir->rx_receiving = 0; + wmb(); + for (i = 0; i < NUM_RX_URBS; i++) + usb_unlink_urb(stir->rx_urbs[i]); + + wait_for_completion(&stir->rx_stop_complete); } -/* Send wrapped data (in tx_data) to device */ -static void stir_send(struct stir_cb *stir) +/* Send wrapped data */ +static void stir_send(struct stir_cb *stir, struct sk_buff *skb) { int rc; - if (test_and_clear_bit(STIR_STATE_RECEIVING, &stir->state)) { + if (stir->rx_receiving) { receive_stop(stir); - - turnaround_delay(stir->tx_mtt, &stir->rx_time); + turnaround_delay(stir, irda_get_mtt(skb)); if (stir->rx_buff.in_frame) ++stir->stats.collisions; } - else if (fifo_txwait(stir, stir->tx_len)) + else if (fifo_txwait(stir, skb->len)) return; /* shutdown or major errors */ stir->netdev->trans_start = jiffies; - pr_debug("%s: send %d\n", stir->netdev->name, stir->tx_len); - rc = usb_bulk_msg(stir->usbdev, - stir->tx_bulkpipe, - stir->tx_data, stir->tx_len, + pr_debug("%s: send len=%d\n", stir->netdev->name, skb->len); + rc = usb_bulk_msg(stir->usbdev, stir->tx_bulkpipe, + skb->data, skb->len, NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT)); if (unlikely(rc)) { @@ -796,44 +791,59 @@ && netif_device_present(dev) && !signal_pending(current)) { - /* make swsusp happy with our thread */ + struct sk_buff *skb; + + /* if suspending, then power off and wait */ if (current->flags & PF_FREEZE) { - receive_stop(stir); + if (stir->rx_receiving) + receive_stop(stir); + else + fifo_txwait(stir, -1); write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD); refrigerator(PF_IOTHREAD); - stir_reset(stir); + if (change_speed(stir, stir->speed)) + break; } /* if something to send? */ - if (test_and_clear_bit(STIR_STATE_TXREADY, &stir->state)) { - unsigned new_speed = stir->tx_newspeed; - - /* Note that we may both send a packet and - * change speed in some cases. Jean II */ - - if (stir->tx_len != 0) - stir_send(stir); + skb = xchg(&stir->tx_pending, NULL); + if (skb) { + unsigned new_speed = irda_get_next_speed(skb); + + netif_wake_queue(dev); + if (skb->len != 0) + stir_send(stir, skb); + + dev_kfree_skb(skb); + if (stir->speed != new_speed) { + if (fifo_txwait(stir, -1)) + break; + if (change_speed(stir, new_speed)) { + WARNING("%s: speed change hardware error\n", + dev->name); + } + } + } else { + if (!stir->rx_receiving + && irda_device_txqueue_empty(dev)) { + /* Wait otherwise chip gets confused. */ + if (fifo_txwait(stir, -1)) + break; - if (stir->speed != new_speed) - change_speed(stir, new_speed); + receive_start(stir); + } - netif_wake_queue(stir->netdev); - continue; + set_task_state(current, TASK_INTERRUPTIBLE); + add_wait_queue(&stir->thr_wait, &wait); + if (stir->tx_pending) + __set_task_state(current, TASK_RUNNING); + else + schedule_timeout(HZ/10); + remove_wait_queue(&stir->thr_wait, &wait); } - - if (irda_device_txqueue_empty(dev)) - receive_start(stir); - - set_task_state(current, TASK_INTERRUPTIBLE); - add_wait_queue(&stir->thr_wait, &wait); - if (test_bit(STIR_STATE_TXREADY, &stir->state)) - __set_task_state(current, TASK_RUNNING); - else - schedule_timeout(HZ/10); - remove_wait_queue(&stir->thr_wait, &wait); } complete_and_exit (&stir->thr_exited, 0); @@ -848,53 +858,27 @@ static void stir_usb_receive(struct urb *urb, struct pt_regs *regs) { struct stir_cb *stir = urb->context; - int err; - - if (!netif_running(stir->netdev)) - return; - switch (urb->status) { - case 0: + if (netif_running(stir->netdev) && urb->status == 0) { if(urb->actual_length > 0) { pr_debug("%s: receive %d\n", stir->netdev->name, urb->actual_length); unwrap_chars(stir, urb->transfer_buffer, urb->actual_length); - + stir->netdev->last_rx = jiffies; - stir->rx_time = CURRENT_TIME; + do_gettimeofday(&stir->rx_time); } - break; - case -ECONNRESET: /* killed but pending */ - case -ENOENT: /* killed but not in use */ - case -ESHUTDOWN: - /* These are normal errors when URB is cancelled */ - stir->rx_buff.in_frame = FALSE; - stir->rx_buff.state = OUTSIDE_FRAME; - return; + /* Normal case, resubmit same urb to pick up more data */ + if (stir->rx_receiving && 0 == usb_submit_urb(urb, GFP_ATOMIC)) + return; - default: - WARNING("%s: received status %d\n", stir->netdev->name, - urb->status); - stir->stats.rx_errors++; - urb->status = 0; } - /* kernel thread is stopping receiver don't resubmit */ - if (!test_bit(STIR_STATE_RECEIVING, &stir->state)) - return; - - /* resubmit existing urb */ - err = usb_submit_urb(urb, GFP_ATOMIC); - - /* in case of error, the kernel thread will restart us */ - if (err) { - WARNING("%s: usb receive submit error: %d\n", - stir->netdev->name, err); - urb->status = -ENOENT; - wake_up(&stir->thr_wait); - } + /* don't resubmit, and wakeup receive_stop */ + if (atomic_dec_and_test(&stir->rx_pending)) + complete(&stir->rx_stop_complete); } @@ -909,45 +893,42 @@ int i, err; char hwname[16]; - err = stir_reset(stir); + err = change_speed(stir, 9600); if (err) goto err_out1; err = -ENOMEM; - - /* Note: Max SIR frame possible is 4273 */ - stir->tx_data = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL); - if (!stir->tx_data) { - ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__); - goto err_out1; - } - /* Initialize for SIR/FIR to copy data directly into skb. */ + stir->rx_receiving = 0; + atomic_set(&stir->rx_pending, 0); + init_completion(&stir->rx_stop_complete); stir->rx_buff.truesize = IRDA_SKB_MAX_MTU; stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); if (!stir->rx_buff.skb) { ERROR("%s(), dev_alloc_skb() failed for rxbuf!\n", __FUNCTION__); - goto err_out2; + goto err_out1; } skb_reserve(stir->rx_buff.skb, 1); stir->rx_buff.head = stir->rx_buff.skb->data; - stir->rx_time = CURRENT_TIME; + do_gettimeofday(&stir->rx_time); /* Allocate N receive buffer's and urbs */ for (i = 0; i < NUM_RX_URBS; i++) { - stir->rx_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!stir->rx_urbs[i]){ + struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!urb) { ERROR("%s(), usb_alloc_urb failed\n", __FUNCTION__); goto err_out3; } - stir->rx_data[i] = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL); + stir->rx_data[i] = kmalloc(STIR_RX_SIZE, GFP_KERNEL); if (!stir->rx_data) { - usb_free_urb(stir->rx_urbs[i]); + usb_free_urb(urb); ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__); goto err_out3; } + stir->rx_urbs[i] = urb; } /* @@ -984,8 +965,6 @@ kfree(stir->rx_data[i]); } kfree_skb(stir->rx_buff.skb); - err_out2: - kfree(stir->tx_data); err_out1: return err; } @@ -1001,19 +980,22 @@ struct stir_cb *stir = netdev->priv; int i; + pr_debug("%s: net close\n", stir->netdev->name); + /* Stop transmit processing */ netif_stop_queue(netdev); /* Kill transmit thread */ kill_proc(stir->thr_pid, SIGTERM, 1); wait_for_completion(&stir->thr_exited); - kfree(stir->tx_data); - - clear_bit(STIR_STATE_RECEIVING, &stir->state); - receive_stop(stir); + /* Mop up receive urb's */ for (i = 0; i < NUM_RX_URBS; i++) { - usb_free_urb(stir->rx_urbs[i]); + struct urb *urb = stir->rx_urbs[i]; + urb->transfer_flags &= ~URB_ASYNC_UNLINK; + usb_unlink_urb(urb); + usb_free_urb(urb); + stir->rx_urbs[i] = NULL; kfree(stir->rx_data[i]); } kfree_skb(stir->rx_buff.skb); @@ -1057,7 +1039,7 @@ case SIOCGRECEIVING: /* Only approximately true */ - irq->ifr_receiving = test_bit(STIR_STATE_RECEIVING, &stir->state); + irq->ifr_receiving = stir->rx_receiving; break; default: @@ -1170,8 +1152,8 @@ stir->qos.min_turn_time.bits &= qos_mtt_bits; irda_qos_bits_to_value(&stir->qos); - init_completion (&stir->thr_exited); - init_waitqueue_head (&stir->thr_wait); + init_completion(&stir->thr_exited); + init_waitqueue_head(&stir->thr_wait); /* Override the network functions we need to use */ net->hard_start_xmit = stir_hard_xmit; @@ -1180,10 +1162,6 @@ net->get_stats = stir_net_get_stats; net->do_ioctl = stir_net_ioctl; - ret = stir_reset(stir); - if (ret) - goto err_out2; - ret = register_netdev(net); if (ret != 0) goto err_out2; @@ -1206,23 +1184,14 @@ static void stir_disconnect(struct usb_interface *intf) { struct stir_cb *stir = usb_get_intfdata(intf); - struct net_device *net; - usb_set_intfdata(intf, NULL); if (!stir) return; - /* Stop transmitter */ - net = stir->netdev; - netif_device_detach(net); + unregister_netdev(stir->netdev); + free_netdev(stir->netdev); - /* Remove netdevice */ - unregister_netdev(net); - - /* No longer attached to USB bus */ - stir->usbdev = NULL; - - free_netdev(net); + usb_set_intfdata(intf, NULL); } |