Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-drm-fsl-dcu.git] / drivers / isdn / gigaset / bas-gigaset.c
index 63b629b1cdb2be0c1e79ac5d7d56f100914a5c11..63e51dd6debe2a9b279ebb1281852a606f9d3301 100644 (file)
@@ -257,10 +257,10 @@ static inline void dump_urb(enum debuglevel level, const char *tag,
                        urb->transfer_flags);
                gig_dbg(level,
                        "  transfer_buffer=0x%08lx[%d], actual_length=%d, "
-                       "bandwidth=%d, setup_packet=0x%08lx,",
+                       "setup_packet=0x%08lx,",
                        (unsigned long) urb->transfer_buffer,
                        urb->transfer_buffer_length, urb->actual_length,
-                       urb->bandwidth, (unsigned long) urb->setup_packet);
+                       (unsigned long) urb->setup_packet);
                gig_dbg(level,
                        "  start_frame=%d, number_of_packets=%d, interval=%d, "
                        "error_count=%d,",
@@ -1853,20 +1853,24 @@ static int gigaset_write_cmd(struct cardstate *cs,
 {
        struct cmdbuf_t *cb;
        unsigned long flags;
-       int status;
+       int rc;
 
        gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
-       if (len <= 0)
-               return 0;                       /* nothing to do */
+       if (len <= 0) {
+               /* nothing to do */
+               rc = 0;
+               goto notqueued;
+       }
 
        if (len > IF_WRITEBUF)
                len = IF_WRITEBUF;
        if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
                dev_err(cs->dev, "%s: out of memory\n", __func__);
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto notqueued;
        }
 
        memcpy(cb->buf, buf, len);
@@ -1891,11 +1895,21 @@ static int gigaset_write_cmd(struct cardstate *cs,
        if (unlikely(!cs->connected)) {
                spin_unlock_irqrestore(&cs->lock, flags);
                gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
+               /* flush command queue */
+               spin_lock_irqsave(&cs->cmdlock, flags);
+               while (cs->cmdbuf != NULL)
+                       complete_cb(cs);
+               spin_unlock_irqrestore(&cs->cmdlock, flags);
                return -ENODEV;
        }
-       status = start_cbsend(cs);
+       rc = start_cbsend(cs);
        spin_unlock_irqrestore(&cs->lock, flags);
-       return status < 0 ? status : len;
+       return rc < 0 ? rc : len;
+
+notqueued:                     /* request handled without queuing */
+       if (wake_tasklet)
+               tasklet_schedule(wake_tasklet);
+       return rc;
 }
 
 /* gigaset_write_room
@@ -1964,20 +1978,15 @@ static int gigaset_freebcshw(struct bc_state *bcs)
 
        /* kill URBs and tasklets before freeing - better safe than sorry */
        atomic_set(&ubc->running, 0);
-       for (i = 0; i < BAS_OUTURBS; ++i)
-               if (ubc->isoouturbs[i].urb) {
-                       gig_dbg(DEBUG_INIT, "%s: killing iso out URB %d",
-                               __func__, i);
-                       usb_kill_urb(ubc->isoouturbs[i].urb);
-                       usb_free_urb(ubc->isoouturbs[i].urb);
-               }
-       for (i = 0; i < BAS_INURBS; ++i)
-               if (ubc->isoinurbs[i]) {
-                       gig_dbg(DEBUG_INIT, "%s: killing iso in URB %d",
-                               __func__, i);
-                       usb_kill_urb(ubc->isoinurbs[i]);
-                       usb_free_urb(ubc->isoinurbs[i]);
-               }
+       gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__);
+       for (i = 0; i < BAS_OUTURBS; ++i) {
+               usb_kill_urb(ubc->isoouturbs[i].urb);
+               usb_free_urb(ubc->isoouturbs[i].urb);
+       }
+       for (i = 0; i < BAS_INURBS; ++i) {
+               usb_kill_urb(ubc->isoinurbs[i]);
+               usb_free_urb(ubc->isoinurbs[i]);
+       }
        tasklet_kill(&ubc->sent_tasklet);
        tasklet_kill(&ubc->rcvd_tasklet);
        kfree(ubc->isooutbuf);
@@ -2099,55 +2108,32 @@ static void freeurbs(struct cardstate *cs)
        struct bas_bc_state *ubc;
        int i, j;
 
+       gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__);
        for (j = 0; j < 2; ++j) {
                ubc = cs->bcs[j].hw.bas;
-               for (i = 0; i < BAS_OUTURBS; ++i)
-                       if (ubc->isoouturbs[i].urb) {
-                               usb_kill_urb(ubc->isoouturbs[i].urb);
-                               gig_dbg(DEBUG_INIT,
-                                       "%s: isoc output URB %d/%d unlinked",
-                                       __func__, j, i);
-                               usb_free_urb(ubc->isoouturbs[i].urb);
-                               ubc->isoouturbs[i].urb = NULL;
-                       }
-               for (i = 0; i < BAS_INURBS; ++i)
-                       if (ubc->isoinurbs[i]) {
-                               usb_kill_urb(ubc->isoinurbs[i]);
-                               gig_dbg(DEBUG_INIT,
-                                       "%s: isoc input URB %d/%d unlinked",
-                                       __func__, j, i);
-                               usb_free_urb(ubc->isoinurbs[i]);
-                               ubc->isoinurbs[i] = NULL;
-                       }
-       }
-       if (ucs->urb_int_in) {
-               usb_kill_urb(ucs->urb_int_in);
-               gig_dbg(DEBUG_INIT, "%s: interrupt input URB unlinked",
-                       __func__);
-               usb_free_urb(ucs->urb_int_in);
-               ucs->urb_int_in = NULL;
-       }
-       if (ucs->urb_cmd_out) {
-               usb_kill_urb(ucs->urb_cmd_out);
-               gig_dbg(DEBUG_INIT, "%s: command output URB unlinked",
-                       __func__);
-               usb_free_urb(ucs->urb_cmd_out);
-               ucs->urb_cmd_out = NULL;
-       }
-       if (ucs->urb_cmd_in) {
-               usb_kill_urb(ucs->urb_cmd_in);
-               gig_dbg(DEBUG_INIT, "%s: command input URB unlinked",
-                       __func__);
-               usb_free_urb(ucs->urb_cmd_in);
-               ucs->urb_cmd_in = NULL;
-       }
-       if (ucs->urb_ctrl) {
-               usb_kill_urb(ucs->urb_ctrl);
-               gig_dbg(DEBUG_INIT, "%s: control output URB unlinked",
-                       __func__);
-               usb_free_urb(ucs->urb_ctrl);
-               ucs->urb_ctrl = NULL;
+               for (i = 0; i < BAS_OUTURBS; ++i) {
+                       usb_kill_urb(ubc->isoouturbs[i].urb);
+                       usb_free_urb(ubc->isoouturbs[i].urb);
+                       ubc->isoouturbs[i].urb = NULL;
+               }
+               for (i = 0; i < BAS_INURBS; ++i) {
+                       usb_kill_urb(ubc->isoinurbs[i]);
+                       usb_free_urb(ubc->isoinurbs[i]);
+                       ubc->isoinurbs[i] = NULL;
+               }
        }
+       usb_kill_urb(ucs->urb_int_in);
+       usb_free_urb(ucs->urb_int_in);
+       ucs->urb_int_in = NULL;
+       usb_kill_urb(ucs->urb_cmd_out);
+       usb_free_urb(ucs->urb_cmd_out);
+       ucs->urb_cmd_out = NULL;
+       usb_kill_urb(ucs->urb_cmd_in);
+       usb_free_urb(ucs->urb_cmd_in);
+       ucs->urb_cmd_in = NULL;
+       usb_kill_urb(ucs->urb_ctrl);
+       usb_free_urb(ucs->urb_ctrl);
+       ucs->urb_ctrl = NULL;
 }
 
 /* gigaset_probe