Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[powerpc.git] / drivers / isdn / gigaset / usb-gigaset.c
index a977dd5..6e05d9d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * USB driver for Gigaset 307x directly or using M105 Data.
  *
- * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>
+ * Copyright (c) 2001 by Stefan Eilers
  *                   and Hansjoerg Lipp <hjlipp@web.de>.
  *
  * This driver was derived from the USB skeleton driver by
@@ -25,7 +25,7 @@
 #include <linux/moduleparam.h>
 
 /* Version Information */
-#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers"
 #define DRIVER_DESC "USB Driver for Gigaset 307x using M105"
 
 /* Module parameters */
@@ -41,7 +41,6 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
 #define GIGASET_MINORS     1
 #define GIGASET_MINOR      8
 #define GIGASET_MODULENAME "usb_gigaset"
-#define GIGASET_DEVFSNAME  "gig/usb/"
 #define GIGASET_DEVNAME    "ttyGU"
 
 #define IF_WRITEBUF 2000 //FIXME  // WAKEUP_CHARS: 256
@@ -365,25 +364,20 @@ static void gigaset_modem_fill(unsigned long data)
  */
 static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
 {
+       struct inbuf_t *inbuf = urb->context;
+       struct cardstate *cs = inbuf->cs;
        int resubmit = 0;
        int r;
-       struct cardstate *cs;
        unsigned numbytes;
        unsigned char *src;
-       struct inbuf_t *inbuf;
-
-       IFNULLRET(urb);
-       inbuf = (struct inbuf_t *) urb->context;
-       IFNULLRET(inbuf);
-       cs = inbuf->cs;
-       IFNULLRET(cs);
-
-       if (!atomic_read(&cs->connected)) {
-               err("%s: disconnected", __func__);
-               return;
-       }
+       unsigned long flags;
 
        if (!urb->status) {
+               if (!cs->connected) {
+                       err("%s: disconnected", __func__); /* should never happen */
+                       return;
+               }
+
                numbytes = urb->actual_length;
 
                if (numbytes) {
@@ -405,12 +399,19 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
                /* The urb might have been killed. */
                gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
                        __func__, urb->status);
-               if (urb->status != -ENOENT) /* not killed */
+               if (urb->status != -ENOENT) { /* not killed */
+                       if (!cs->connected) {
+                               err("%s: disconnected", __func__); /* should never happen */
+                               return;
+                       }
                        resubmit = 1;
+               }
        }
 
        if (resubmit) {
-               r = usb_submit_urb(urb, SLAB_ATOMIC);
+               spin_lock_irqsave(&cs->lock, flags);
+               r = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
+               spin_unlock_irqrestore(&cs->lock, flags);
                if (r)
                        dev_err(cs->dev, "error %d when resubmitting urb.\n",
                                -r);
@@ -421,23 +422,23 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
 /* This callback routine is called when data was transmitted to the device. */
 static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
 {
-       struct cardstate *cs = (struct cardstate *) urb->context;
+       struct cardstate *cs = urb->context;
+       unsigned long flags;
 
-       IFNULLRET(cs);
-#ifdef CONFIG_GIGASET_DEBUG
-       if (!atomic_read(&cs->connected)) {
-               err("%s: not connected", __func__);
-               return;
-       }
-#endif
        if (urb->status)
                dev_err(cs->dev, "bulk transfer failed (status %d)\n",
                        -urb->status);
                /* That's all we can do. Communication problems
                   are handled by timeouts or network protocols. */
 
-       atomic_set(&cs->hw.usb->busy, 0);
-       tasklet_schedule(&cs->write_tasklet);
+       spin_lock_irqsave(&cs->lock, flags);
+       if (!cs->connected) {
+               err("%s: not connected", __func__);
+       } else {
+               atomic_set(&cs->hw.usb->busy, 0);
+               tasklet_schedule(&cs->write_tasklet);
+       }
+       spin_unlock_irqrestore(&cs->lock, flags);
 }
 
 static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
@@ -472,6 +473,8 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
                }
                if (cb) {
                        count = min(cb->len, ucs->bulk_out_size);
+                       gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
+
                        usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
                                          usb_sndbulkpipe(ucs->udev,
                                             ucs->bulk_out_endpointAddr & 0x0f),
@@ -481,14 +484,15 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
                        cb->offset += count;
                        cb->len -= count;
                        atomic_set(&ucs->busy, 1);
-                       gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
 
-                       status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+                       spin_lock_irqsave(&cs->lock, flags);
+                       status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC) : -ENODEV;
+                       spin_unlock_irqrestore(&cs->lock, flags);
+
                        if (status) {
                                atomic_set(&ucs->busy, 0);
-                               dev_err(cs->dev,
-                                       "could not submit urb (error %d)\n",
-                                       -status);
+                               err("could not submit urb (error %d)\n",
+                                   -status);
                                cb->len = 0; /* skip urb => remove cb+wakeup
                                                in next loop cycle */
                        }
@@ -507,12 +511,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
 
        gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
-                          "CMD Transmit", len, buf, 0);
-
-       if (!atomic_read(&cs->connected)) {
-               err("%s: not connected", __func__);
-               return -ENODEV;
-       }
+                          "CMD Transmit", len, buf);
 
        if (len <= 0)
                return 0;
@@ -540,7 +539,10 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        cs->lastcmdbuf = cb;
        spin_unlock_irqrestore(&cs->cmdlock, flags);
 
-       tasklet_schedule(&cs->write_tasklet);
+       spin_lock_irqsave(&cs->lock, flags);
+       if (cs->connected)
+               tasklet_schedule(&cs->write_tasklet);
+       spin_unlock_irqrestore(&cs->lock, flags);
        return len;
 }
 
@@ -566,7 +568,7 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
 #ifdef CONFIG_GIGASET_UNDOCREQ
        struct usb_device *udev = cs->hw.usb->udev;
 
-       gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf, 0);
+       gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf);
        memcpy(cs->hw.usb->bchars, buf, 6);
        return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41,
                               0, 0, &buf, 6, 2000);
@@ -632,20 +634,14 @@ static int gigaset_initcshw(struct cardstate *cs)
 /* Send data from current skb to the device. */
 static int write_modem(struct cardstate *cs)
 {
-       int ret;
+       int ret = 0;
        int count;
        struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
        struct usb_cardstate *ucs = cs->hw.usb;
-
-       IFNULLRETVAL(bcs->tx_skb, -EINVAL);
+       unsigned long flags;
 
        gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
 
-       ret = -ENODEV;
-       IFNULLGOTO(ucs->bulk_out_buffer, error);
-       IFNULLGOTO(ucs->bulk_out_urb, error);
-       ret = 0;
-
        if (!bcs->tx_skb->len) {
                dev_kfree_skb_any(bcs->tx_skb);
                bcs->tx_skb = NULL;
@@ -658,20 +654,27 @@ static int write_modem(struct cardstate *cs)
        count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
        memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count);
        skb_pull(bcs->tx_skb, count);
-
-       usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
-                         usb_sndbulkpipe(ucs->udev,
-                                         ucs->bulk_out_endpointAddr & 0x0f),
-                         ucs->bulk_out_buffer, count,
-                         gigaset_write_bulk_callback, cs);
        atomic_set(&ucs->busy, 1);
        gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
 
-       ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+       spin_lock_irqsave(&cs->lock, flags);
+       if (cs->connected) {
+               usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
+                                 usb_sndbulkpipe(ucs->udev,
+                                                 ucs->bulk_out_endpointAddr & 0x0f),
+                                 ucs->bulk_out_buffer, count,
+                                 gigaset_write_bulk_callback, cs);
+               ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+       } else {
+               ret = -ENODEV;
+       }
+       spin_unlock_irqrestore(&cs->lock, flags);
+
        if (ret) {
-               dev_err(cs->dev, "could not submit urb (error %d)\n", -ret);
+               err("could not submit urb (error %d)\n", -ret);
                atomic_set(&ucs->busy, 0);
        }
+
        if (!bcs->tx_skb->len) {
                /* skb sent completely */
                gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0?
@@ -683,11 +686,6 @@ static int write_modem(struct cardstate *cs)
        }
 
        return ret;
-error:
-       dev_kfree_skb_any(bcs->tx_skb);
-       bcs->tx_skb = NULL;
-       return ret;
-
 }
 
 static int gigaset_probe(struct usb_interface *interface,
@@ -711,8 +709,8 @@ static int gigaset_probe(struct usb_interface *interface,
        retval = -ENODEV; //FIXME
 
        /* See if the device offered us matches what we can accept */
-       if ((le16_to_cpu(udev->descriptor.idVendor  != USB_M105_VENDOR_ID)) ||
-           (le16_to_cpu(udev->descriptor.idProduct != USB_M105_PRODUCT_ID)))
+       if ((le16_to_cpu(udev->descriptor.idVendor)  != USB_M105_VENDOR_ID) ||
+           (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID))
                return -ENODEV;
 
        /* this starts to become ascii art... */
@@ -835,9 +833,6 @@ error:
        return retval;
 }
 
-/**
- *     skel_disconnect
- */
 static void gigaset_disconnect(struct usb_interface *interface)
 {
        struct cardstate *cs;
@@ -900,8 +895,7 @@ static int __init usb_gigaset_init(void)
        /* allocate memory for our driver state and intialize it */
        if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
                                       GIGASET_MODULENAME, GIGASET_DEVNAME,
-                                      GIGASET_DEVFSNAME, &ops,
-                                      THIS_MODULE)) == NULL)
+                                      &ops, THIS_MODULE)) == NULL)
                goto error;
 
        /* allocate memory for our device state and intialize it */