{
        struct zd_usb_tx *tx = &usb->tx;
        unsigned long flags;
-       struct list_head *pos, *n;
+
+       atomic_set(&tx->enabled, 0);
+
+       /* kill all submitted tx-urbs */
+       usb_kill_anchored_urbs(&tx->submitted);
 
        spin_lock_irqsave(&tx->lock, flags);
-       list_for_each_safe(pos, n, &tx->free_urb_list) {
-               list_del(pos);
-               usb_free_urb(list_entry(pos, struct urb, urb_list));
-       }
-       tx->enabled = 0;
+       WARN_ON(tx->submitted_urbs != 0);
        tx->submitted_urbs = 0;
+       spin_unlock_irqrestore(&tx->lock, flags);
+
        /* The stopped state is ignored, relying on ieee80211_wake_queues()
         * in a potentionally following zd_usb_enable_tx().
         */
-       spin_unlock_irqrestore(&tx->lock, flags);
 }
 
 /**
        struct zd_usb_tx *tx = &usb->tx;
 
        spin_lock_irqsave(&tx->lock, flags);
-       tx->enabled = 1;
+       atomic_set(&tx->enabled, 1);
        tx->submitted_urbs = 0;
        ieee80211_wake_queues(zd_usb_to_hw(usb));
        tx->stopped = 0;
        spin_unlock_irqrestore(&tx->lock, flags);
 }
 
-/**
- * alloc_tx_urb - provides an tx URB
- * @usb: a &struct zd_usb pointer
- *
- * Allocates a new URB. If possible takes the urb from the free list in
- * usb->tx.
- */
-static struct urb *alloc_tx_urb(struct zd_usb *usb)
-{
-       struct zd_usb_tx *tx = &usb->tx;
-       unsigned long flags;
-       struct list_head *entry;
-       struct urb *urb;
-
-       spin_lock_irqsave(&tx->lock, flags);
-       if (list_empty(&tx->free_urb_list)) {
-               urb = usb_alloc_urb(0, GFP_ATOMIC);
-               goto out;
-       }
-       entry = tx->free_urb_list.next;
-       list_del(entry);
-       urb = list_entry(entry, struct urb, urb_list);
-out:
-       spin_unlock_irqrestore(&tx->lock, flags);
-       return urb;
-}
-
-/**
- * free_tx_urb - frees a used tx URB
- * @usb: a &struct zd_usb pointer
- * @urb: URB to be freed
- *
- * Frees the transmission URB, which means to put it on the free URB
- * list.
- */
-static void free_tx_urb(struct zd_usb *usb, struct urb *urb)
-{
-       struct zd_usb_tx *tx = &usb->tx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tx->lock, flags);
-       if (!tx->enabled) {
-               usb_free_urb(urb);
-               goto out;
-       }
-       list_add(&urb->urb_list, &tx->free_urb_list);
-out:
-       spin_unlock_irqrestore(&tx->lock, flags);
-}
-
 static void tx_dec_submitted_urbs(struct zd_usb *usb)
 {
        struct zd_usb_tx *tx = &usb->tx;
        struct sk_buff *skb;
        struct ieee80211_tx_info *info;
        struct zd_usb *usb;
+       struct zd_usb_tx *tx;
+
+       skb = (struct sk_buff *)urb->context;
+       info = IEEE80211_SKB_CB(skb);
+       /*
+        * grab 'usb' pointer before handing off the skb (since
+        * it might be freed by zd_mac_tx_to_dev or mac80211)
+        */
+       usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb;
+       tx = &usb->tx;
 
        switch (urb->status) {
        case 0:
                goto resubmit;
        }
 free_urb:
-       skb = (struct sk_buff *)urb->context;
-       /*
-        * grab 'usb' pointer before handing off the skb (since
-        * it might be freed by zd_mac_tx_to_dev or mac80211)
-        */
-       info = IEEE80211_SKB_CB(skb);
-       usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb;
        zd_mac_tx_to_dev(skb, urb->status);
-       free_tx_urb(usb, urb);
+       usb_free_urb(urb);
        tx_dec_submitted_urbs(usb);
        return;
 resubmit:
+       usb_anchor_urb(urb, &tx->submitted);
        r = usb_submit_urb(urb, GFP_ATOMIC);
        if (r) {
+               usb_unanchor_urb(urb);
                dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r);
                goto free_urb;
        }
        int r;
        struct usb_device *udev = zd_usb_to_usbdev(usb);
        struct urb *urb;
+       struct zd_usb_tx *tx = &usb->tx;
 
-       urb = alloc_tx_urb(usb);
+       if (!atomic_read(&tx->enabled)) {
+               r = -ENOENT;
+               goto out;
+       }
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
                r = -ENOMEM;
                goto out;
        usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
                          skb->data, skb->len, tx_urb_complete, skb);
 
+       usb_anchor_urb(urb, &tx->submitted);
        r = usb_submit_urb(urb, GFP_ATOMIC);
-       if (r)
+       if (r) {
+               usb_unanchor_urb(urb);
                goto error;
+       }
        tx_inc_submitted_urbs(usb);
        return 0;
 error:
-       free_tx_urb(usb, urb);
+       usb_free_urb(urb);
 out:
        return r;
 }
 {
        struct zd_usb_tx *tx = &usb->tx;
        spin_lock_init(&tx->lock);
-       tx->enabled = 0;
+       atomic_set(&tx->enabled, 0);
        tx->stopped = 0;
-       INIT_LIST_HEAD(&tx->free_urb_list);
+       init_usb_anchor(&tx->submitted);
        tx->submitted_urbs = 0;
 }
 
        ieee80211_unregister_hw(hw);
 
        /* Just in case something has gone wrong! */
+       zd_usb_disable_tx(usb);
        zd_usb_disable_rx(usb);
        zd_usb_disable_int(usb);