Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
[cascardo/linux.git] / drivers / staging / ozwpan / ozpd.c
index d67dff2..ab85a72 100644 (file)
@@ -3,28 +3,26 @@
  * Released under the GNU General Public License Version 2 (GPLv2).
  * -----------------------------------------------------------------------------
  */
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
 #include <linux/netdevice.h>
 #include <linux/errno.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
 #include "ozprotocol.h"
 #include "ozeltbuf.h"
 #include "ozpd.h"
 #include "ozproto.h"
-#include "oztrace.h"
 #include "ozcdev.h"
 #include "ozusbsvc.h"
 #include <asm/unaligned.h>
 #include <linux/uaccess.h>
 #include <net/psnap.h>
-/*------------------------------------------------------------------------------
- */
+
 #define OZ_MAX_TX_POOL_SIZE    6
-/*------------------------------------------------------------------------------
- */
+
 static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
 static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
 static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
@@ -39,10 +37,12 @@ static void oz_def_app_term(void);
 static int oz_def_app_start(struct oz_pd *pd, int resume);
 static void oz_def_app_stop(struct oz_pd *pd, int pause);
 static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt);
-/*------------------------------------------------------------------------------
+
+/*
  * Counts the uncompleted isoc frames submitted to netcard.
  */
 static atomic_t g_submitted_isoc = ATOMIC_INIT(0);
+
 /* Application handler functions.
  */
 static const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
@@ -82,69 +82,75 @@ static const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
        NULL,
        OZ_APPID_SERIAL},
 };
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static int oz_def_app_init(void)
 {
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static void oz_def_app_term(void)
 {
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static int oz_def_app_start(struct oz_pd *pd, int resume)
 {
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static void oz_def_app_stop(struct oz_pd *pd, int pause)
 {
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt)
 {
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 void oz_pd_set_state(struct oz_pd *pd, unsigned state)
 {
        pd->state = state;
-#ifdef WANT_TRACE
        switch (state) {
        case OZ_PD_S_IDLE:
-               oz_trace("PD State: OZ_PD_S_IDLE\n");
+               oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n");
                break;
        case OZ_PD_S_CONNECTED:
-               oz_trace("PD State: OZ_PD_S_CONNECTED\n");
+               oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n");
                break;
        case OZ_PD_S_STOPPED:
-               oz_trace("PD State: OZ_PD_S_STOPPED\n");
+               oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n");
                break;
        case OZ_PD_S_SLEEP:
-               oz_trace("PD State: OZ_PD_S_SLEEP\n");
+               oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_SLEEP\n");
                break;
        }
-#endif /* WANT_TRACE */
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 void oz_pd_get(struct oz_pd *pd)
 {
        atomic_inc(&pd->ref_count);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 void oz_pd_put(struct oz_pd *pd)
@@ -152,12 +158,14 @@ void oz_pd_put(struct oz_pd *pd)
        if (atomic_dec_and_test(&pd->ref_count))
                oz_pd_destroy(pd);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 struct oz_pd *oz_pd_alloc(const u8 *mac_addr)
 {
        struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
+
        if (pd) {
                int i;
                atomic_set(&pd->ref_count, 2);
@@ -177,19 +185,34 @@ struct oz_pd *oz_pd_alloc(const u8 *mac_addr)
                pd->last_sent_frame = &pd->tx_queue;
                spin_lock_init(&pd->stream_lock);
                INIT_LIST_HEAD(&pd->stream_list);
+               tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler,
+                                                       (unsigned long)pd);
+               tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler,
+                                                       (unsigned long)pd);
+               hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+               hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+               pd->heartbeat.function = oz_pd_heartbeat_event;
+               pd->timeout.function = oz_pd_timeout_event;
        }
        return pd;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
-void oz_pd_destroy(struct oz_pd *pd)
+static void oz_pd_free(struct work_struct *work)
 {
        struct list_head *e;
        struct oz_tx_frame *f;
        struct oz_isoc_stream *st;
        struct oz_farewell *fwell;
-       oz_trace("Destroying PD\n");
+       struct oz_pd *pd;
+
+       oz_pd_dbg(pd, ON, "Destroying PD\n");
+       pd = container_of(work, struct oz_pd, workitem);
+       /*Disable timer tasklets*/
+       tasklet_kill(&pd->heartbeat_tasklet);
+       tasklet_kill(&pd->timeout_tasklet);
        /* Delete any streams.
         */
        e = pd->stream_list.next;
@@ -228,20 +251,38 @@ void oz_pd_destroy(struct oz_pd *pd)
                dev_put(pd->net_dev);
        kfree(pd);
 }
-/*------------------------------------------------------------------------------
+
+/*
+ * Context: softirq or Process
+ */
+void oz_pd_destroy(struct oz_pd *pd)
+{
+       if (hrtimer_active(&pd->timeout))
+               hrtimer_cancel(&pd->timeout);
+       if (hrtimer_active(&pd->heartbeat))
+               hrtimer_cancel(&pd->heartbeat);
+
+       INIT_WORK(&pd->workitem, oz_pd_free);
+       if (!schedule_work(&pd->workitem))
+               oz_pd_dbg(pd, ON, "failed to schedule workitem\n");
+}
+
+/*
  * Context: softirq-serialized
  */
 int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
 {
        const struct oz_app_if *ai;
        int rc = 0;
-       oz_trace("oz_services_start(0x%x) resume(%d)\n", apps, resume);
+
+       oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
        for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
                if (apps & (1<<ai->app_id)) {
                        if (ai->start(pd, resume)) {
                                rc = -1;
-                               oz_trace("Unabled to start service %d\n",
-                                       ai->app_id);
+                               oz_pd_dbg(pd, ON,
+                                         "Unable to start service %d\n",
+                                         ai->app_id);
                                break;
                        }
                        oz_polling_lock_bh();
@@ -253,13 +294,15 @@ int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
        }
        return rc;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
 {
        const struct oz_app_if *ai;
-       oz_trace("oz_stop_services(0x%x) pause(%d)\n", apps, pause);
+
+       oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
        for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
                if (apps & (1<<ai->app_id)) {
                        oz_polling_lock_bh();
@@ -274,34 +317,38 @@ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
                }
        }
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 void oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
 {
        const struct oz_app_if *ai;
        int more = 0;
+
        for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
                if (ai->heartbeat && (apps & (1<<ai->app_id))) {
                        if (ai->heartbeat(pd))
                                more = 1;
                }
        }
-       if (more)
-               oz_pd_request_heartbeat(pd);
+       if ((!more) && (hrtimer_active(&pd->heartbeat)))
+               hrtimer_cancel(&pd->heartbeat);
        if (pd->mode & OZ_F_ISOC_ANYTIME) {
                int count = 8;
                while (count-- && (oz_send_isoc_frame(pd) >= 0))
                        ;
        }
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 void oz_pd_stop(struct oz_pd *pd)
 {
-       u16 stop_apps = 0;
-       oz_trace("oz_pd_stop() State = 0x%x\n", pd->state);
+       u16 stop_apps;
+
+       oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
        oz_pd_indicate_farewells(pd);
        oz_polling_lock_bh();
        stop_apps = pd->total_apps;
@@ -314,46 +361,46 @@ void oz_pd_stop(struct oz_pd *pd)
        /* Remove from PD list.*/
        list_del(&pd->link);
        oz_polling_unlock_bh();
-       oz_trace("pd ref count = %d\n", atomic_read(&pd->ref_count));
-       oz_timer_delete(pd, 0);
+       oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
        oz_pd_put(pd);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_pd_sleep(struct oz_pd *pd)
 {
        int do_stop = 0;
-       u16 stop_apps = 0;
+       u16 stop_apps;
+
        oz_polling_lock_bh();
        if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
                oz_polling_unlock_bh();
                return 0;
        }
-       if (pd->keep_alive_j && pd->session_id) {
+       if (pd->keep_alive && pd->session_id)
                oz_pd_set_state(pd, OZ_PD_S_SLEEP);
-               pd->pulse_time_j = jiffies + pd->keep_alive_j;
-               oz_trace("Sleep Now %lu until %lu\n",
-                       jiffies, pd->pulse_time_j);
-       } else {
+       else
                do_stop = 1;
-       }
+
        stop_apps = pd->total_apps;
        oz_polling_unlock_bh();
        if (do_stop) {
                oz_pd_stop(pd);
        } else {
                oz_services_stop(pd, stop_apps, 1);
-               oz_timer_add(pd, OZ_TIMER_STOP, jiffies + pd->keep_alive_j, 1);
+               oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive);
        }
        return do_stop;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
 {
        struct oz_tx_frame *f = NULL;
+
        spin_lock_bh(&pd->tx_frame_lock);
        if (pd->tx_pool) {
                f = container_of(pd->tx_pool, struct oz_tx_frame, link);
@@ -370,7 +417,8 @@ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
        }
        return f;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -384,10 +432,11 @@ static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
        } else {
                kfree(f);
        }
-       oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
-                                               pd->nb_queued_isoc_frames);
+       oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
+              pd->nb_queued_isoc_frames);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -402,28 +451,34 @@ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
        spin_unlock_bh(&pd->tx_frame_lock);
        kfree(f);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static void oz_set_more_bit(struct sk_buff *skb)
 {
        struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+
        oz_hdr->control |= OZ_F_MORE_DATA;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
 {
        struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+
        oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_prepare_frame(struct oz_pd *pd, int empty)
 {
        struct oz_tx_frame *f;
+
        if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
                return -1;
        if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
@@ -448,7 +503,8 @@ int oz_prepare_frame(struct oz_pd *pd, int empty)
        spin_unlock(&pd->tx_frame_lock);
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -458,6 +514,7 @@ static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
        struct oz_hdr *oz_hdr;
        struct oz_elt *elt;
        struct list_head *e;
+
        /* Allocate skb with enough space for the lower layers as well
         * as the space we need.
         */
@@ -492,13 +549,15 @@ fail:
        kfree_skb(skb);
        return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
 {
        struct list_head *e;
        struct oz_elt_info *ei;
+
        e = f->elt_list.next;
        while (e != &f->elt_list) {
                ei = container_of(e, struct oz_elt_info, link);
@@ -514,7 +573,8 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
        if (pd->elt_buff.free_elts > pd->elt_buff.max_free_elts)
                oz_trim_elt_pool(&pd->elt_buff);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
@@ -522,6 +582,7 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
        struct sk_buff *skb;
        struct oz_tx_frame *f;
        struct list_head *e;
+
        spin_lock(&pd->tx_frame_lock);
        e = pd->last_sent_frame->next;
        if (e == &pd->tx_queue) {
@@ -540,18 +601,16 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
                if ((int)atomic_read(&g_submitted_isoc) <
                                                        OZ_MAX_SUBMITTED_ISOC) {
                        if (dev_queue_xmit(skb) < 0) {
-                               oz_trace2(OZ_TRACE_TX_FRAMES,
-                                               "Dropping ISOC Frame\n");
+                               oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
                                return -1;
                        }
                        atomic_inc(&g_submitted_isoc);
-                       oz_trace2(OZ_TRACE_TX_FRAMES,
-                                       "Sending ISOC Frame, nb_isoc= %d\n",
-                                               pd->nb_queued_isoc_frames);
+                       oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
+                              pd->nb_queued_isoc_frames);
                        return 0;
                } else {
                        kfree_skb(skb);
-                       oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Frame>\n");
+                       oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
                        return -1;
                }
        }
@@ -559,17 +618,18 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
        pd->last_sent_frame = e;
        skb = oz_build_frame(pd, f);
        spin_unlock(&pd->tx_frame_lock);
+       if (!skb)
+               return -1;
        if (more_data)
                oz_set_more_bit(skb);
-       oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
-       if (skb) {
-               if (dev_queue_xmit(skb) < 0)
-                       return -1;
+       oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
+       if (dev_queue_xmit(skb) < 0)
+               return -1;
 
-       }
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 void oz_send_queued_frames(struct oz_pd *pd, int backlog)
@@ -607,7 +667,8 @@ void oz_send_queued_frames(struct oz_pd *pd, int backlog)
 out:   oz_prepare_frame(pd, 1);
        oz_send_next_queued_frame(pd, 0);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static int oz_send_isoc_frame(struct oz_pd *pd)
@@ -619,6 +680,7 @@ static int oz_send_isoc_frame(struct oz_pd *pd)
        struct list_head *e;
        struct list_head list;
        int total_size = sizeof(struct oz_hdr);
+
        INIT_LIST_HEAD(&list);
 
        oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
@@ -627,7 +689,7 @@ static int oz_send_isoc_frame(struct oz_pd *pd)
                return 0;
        skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
        if (skb == NULL) {
-               oz_trace("Cannot alloc skb\n");
+               oz_dbg(ON, "Cannot alloc skb\n");
                oz_elt_info_free_chain(&pd->elt_buff, &list);
                return -1;
        }
@@ -655,7 +717,8 @@ static int oz_send_isoc_frame(struct oz_pd *pd)
        oz_elt_info_free_chain(&pd->elt_buff, &list);
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
@@ -675,8 +738,8 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
                diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
                if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
                        break;
-               oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
-                                                pkt_num, pd->nb_queued_frames);
+               oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
+                      pkt_num, pd->nb_queued_frames);
                if (first == NULL)
                        first = e;
                last = e;
@@ -696,7 +759,8 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
                oz_retire_frame(pd, f);
        }
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Precondition: stream_lock must be held.
  * Context: softirq
  */
@@ -704,6 +768,7 @@ static struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
 {
        struct list_head *e;
        struct oz_isoc_stream *st;
+
        list_for_each(e, &pd->stream_list) {
                st = container_of(e, struct oz_isoc_stream, link);
                if (st->ep_num == ep_num)
@@ -711,7 +776,8 @@ static struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
        }
        return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
@@ -730,7 +796,8 @@ int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
        kfree(st);
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 static void oz_isoc_stream_free(struct oz_isoc_stream *st)
@@ -738,12 +805,14 @@ static void oz_isoc_stream_free(struct oz_isoc_stream *st)
        kfree_skb(st->skb);
        kfree(st);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
 {
        struct oz_isoc_stream *st;
+
        spin_lock_bh(&pd->stream_lock);
        st = pd_stream_find(pd, ep_num);
        if (st)
@@ -753,14 +822,16 @@ int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
                oz_isoc_stream_free(st);
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: any
  */
 static void oz_isoc_destructor(struct sk_buff *skb)
 {
        atomic_dec(&g_submitted_isoc);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
@@ -771,6 +842,7 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
        struct sk_buff *skb = NULL;
        struct oz_hdr *oz_hdr = NULL;
        int size = 0;
+
        spin_lock_bh(&pd->stream_lock);
        st = pd_stream_find(pd, ep_num);
        if (st) {
@@ -835,10 +907,20 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
                        struct oz_tx_frame *isoc_unit = NULL;
                        int nb = pd->nb_queued_isoc_frames;
                        if (nb >= pd->isoc_latency) {
-                               oz_trace2(OZ_TRACE_TX_FRAMES,
-                                               "Dropping ISOC Unit nb= %d\n",
-                                                                       nb);
-                               goto out;
+                               struct list_head *e;
+                               struct oz_tx_frame *f;
+                               oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
+                                      nb);
+                               spin_lock(&pd->tx_frame_lock);
+                               list_for_each(e, &pd->tx_queue) {
+                                       f = container_of(e, struct oz_tx_frame,
+                                                                       link);
+                                       if (f->skb != NULL) {
+                                               oz_tx_isoc_free(pd, f);
+                                               break;
+                                       }
+                               }
+                               spin_unlock(&pd->tx_frame_lock);
                        }
                        isoc_unit = oz_tx_frame_alloc(pd);
                        if (isoc_unit == NULL)
@@ -849,9 +931,9 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
                        list_add_tail(&isoc_unit->link, &pd->tx_queue);
                        pd->nb_queued_isoc_frames++;
                        spin_unlock_bh(&pd->tx_frame_lock);
-                       oz_trace2(OZ_TRACE_TX_FRAMES,
-                       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
-                       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
+                       oz_dbg(TX_FRAMES,
+                              "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
+                              pd->nb_queued_isoc_frames, pd->nb_queued_frames);
                        return 0;
                }
 
@@ -870,45 +952,53 @@ out:      kfree_skb(skb);
        }
        return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 void oz_apps_init(void)
 {
        int i;
+
        for (i = 0; i < OZ_APPID_MAX; i++)
                if (g_app_if[i].init)
                        g_app_if[i].init();
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 void oz_apps_term(void)
 {
        int i;
+
        /* Terminate all the apps. */
        for (i = 0; i < OZ_APPID_MAX; i++)
                if (g_app_if[i].term)
                        g_app_if[i].term();
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
 {
        const struct oz_app_if *ai;
+
        if (app_id == 0 || app_id > OZ_APPID_MAX)
                return;
        ai = &g_app_if[app_id-1];
        ai->rx(pd, elt);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 void oz_pd_indicate_farewells(struct oz_pd *pd)
 {
        struct oz_farewell *f;
        const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
+
        while (1) {
                oz_polling_lock_bh();
                if (list_empty(&pd->farewell_list)) {