]> err.no Git - linux-2.6/blobdiff - drivers/isdn/gigaset/usb-gigaset.c
Merge commit 'origin/master'
[linux-2.6] / drivers / isdn / gigaset / usb-gigaset.c
index d81c0e3f770249d1683d14b9d3c2a485ba9a2542..77d20ab0cd4d422b31226c9093a08eedb22ad937 100644 (file)
@@ -109,8 +109,12 @@ static int gigaset_probe(struct usb_interface *interface,
                         const struct usb_device_id *id);
 static void gigaset_disconnect(struct usb_interface *interface);
 
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+static int gigaset_pre_reset(struct usb_interface *intf);
+
 static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver gigaset_usb_driver = {
@@ -118,12 +122,17 @@ static struct usb_driver gigaset_usb_driver = {
        .probe =        gigaset_probe,
        .disconnect =   gigaset_disconnect,
        .id_table =     gigaset_table,
+       .suspend =      gigaset_suspend,
+       .resume =       gigaset_resume,
+       .reset_resume = gigaset_resume,
+       .pre_reset =    gigaset_pre_reset,
+       .post_reset =   gigaset_resume,
 };
 
 struct usb_cardstate {
        struct usb_device       *udev;          /* usb device pointer */
        struct usb_interface    *interface;     /* interface for this device */
-       atomic_t                busy;           /* bulk output in progress */
+       int                     busy;           /* bulk output in progress */
 
        /* Output buffer */
        unsigned char           *bulk_out_buffer;
@@ -315,7 +324,7 @@ static void gigaset_modem_fill(unsigned long data)
 
        gig_dbg(DEBUG_OUTPUT, "modem_fill");
 
-       if (atomic_read(&cs->hw.usb->busy)) {
+       if (cs->hw.usb->busy) {
                gig_dbg(DEBUG_OUTPUT, "modem_fill: busy");
                return;
        }
@@ -420,7 +429,7 @@ static void gigaset_write_bulk_callback(struct urb *urb)
                break;
        case -ENOENT:           /* killed */
                gig_dbg(DEBUG_ANY, "%s: killed", __func__);
-               atomic_set(&cs->hw.usb->busy, 0);
+               cs->hw.usb->busy = 0;
                return;
        default:
                dev_err(cs->dev, "bulk transfer failed (status %d)\n",
@@ -433,7 +442,7 @@ static void gigaset_write_bulk_callback(struct urb *urb)
        if (!cs->connected) {
                err("%s: not connected", __func__);
        } else {
-               atomic_set(&cs->hw.usb->busy, 0);
+               cs->hw.usb->busy = 0;
                tasklet_schedule(&cs->write_tasklet);
        }
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -481,14 +490,14 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
 
                        cb->offset += count;
                        cb->len -= count;
-                       atomic_set(&ucs->busy, 1);
+                       ucs->busy = 1;
 
                        spin_lock_irqsave(&cs->lock, flags);
                        status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV;
                        spin_unlock_irqrestore(&cs->lock, flags);
 
                        if (status) {
-                               atomic_set(&ucs->busy, 0);
+                               ucs->busy = 0;
                                err("could not submit urb (error %d)\n",
                                    -status);
                                cb->len = 0; /* skip urb => remove cb+wakeup
@@ -507,7 +516,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        struct cmdbuf_t *cb;
        unsigned long flags;
 
-       gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+       gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
@@ -644,7 +653,7 @@ static int write_modem(struct cardstate *cs)
        count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
        skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
        skb_pull(bcs->tx_skb, count);
-       atomic_set(&ucs->busy, 1);
+       ucs->busy = 1;
        gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
 
        spin_lock_irqsave(&cs->lock, flags);
@@ -662,7 +671,7 @@ static int write_modem(struct cardstate *cs)
 
        if (ret) {
                err("could not submit urb (error %d)\n", -ret);
-               atomic_set(&ucs->busy, 0);
+               ucs->busy = 0;
        }
 
        if (!bcs->tx_skb->len) {
@@ -717,11 +726,10 @@ static int gigaset_probe(struct usb_interface *interface,
 
        dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
 
-       cs = gigaset_getunassignedcs(driver);
-       if (!cs) {
-               dev_warn(&udev->dev, "no free cardstate\n");
+       /* allocate memory for our device state and intialize it */
+       cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
+       if (!cs)
                return -ENODEV;
-       }
        ucs = cs->hw.usb;
 
        /* save off device structure ptrs for later use */
@@ -754,7 +762,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        endpoint = &hostif->endpoint[1].desc;
 
-       atomic_set(&ucs->busy, 0);
+       ucs->busy = 0;
 
        ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!ucs->read_urb) {
@@ -787,7 +795,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        /* tell common part that the device is ready */
        if (startmode == SM_LOCKED)
-               atomic_set(&cs->mstate, MS_LOCKED);
+               cs->mstate = MS_LOCKED;
 
        if (!gigaset_start(cs)) {
                tasklet_kill(&cs->write_tasklet);
@@ -808,7 +816,7 @@ error:
        usb_put_dev(ucs->udev);
        ucs->udev = NULL;
        ucs->interface = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
        return retval;
 }
 
@@ -842,7 +850,53 @@ static void gigaset_disconnect(struct usb_interface *interface)
        ucs->interface = NULL;
        ucs->udev = NULL;
        cs->dev = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
+}
+
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended or reset.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+
+       /* stop activity */
+       cs->connected = 0;      /* prevent rescheduling */
+       usb_kill_urb(cs->hw.usb->read_urb);
+       tasklet_kill(&cs->write_tasklet);
+       usb_kill_urb(cs->hw.usb->bulk_out_urb);
+
+       gig_dbg(DEBUG_SUSPEND, "suspend complete");
+       return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed or reset.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+       int rc;
+
+       /* resubmit interrupt URB */
+       cs->connected = 1;
+       rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL);
+       if (rc) {
+               dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc);
+               return rc;
+       }
+
+       gig_dbg(DEBUG_SUSPEND, "resume complete");
+       return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+       /* same as suspend */
+       return gigaset_suspend(intf, PMSG_ON);
 }
 
 static const struct gigaset_ops ops = {
@@ -878,11 +932,6 @@ static int __init usb_gigaset_init(void)
                                       &ops, THIS_MODULE)) == NULL)
                goto error;
 
-       /* allocate memory for our device state and intialize it */
-       cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
-       if (!cardstate)
-               goto error;
-
        /* register this driver with the USB subsystem */
        result = usb_register(&gigaset_usb_driver);
        if (result < 0) {
@@ -895,9 +944,7 @@ static int __init usb_gigaset_init(void)
        info(DRIVER_DESC);
        return 0;
 
-error: if (cardstate)
-               gigaset_freecs(cardstate);
-       cardstate = NULL;
+error:
        if (driver)
                gigaset_freedriver(driver);
        driver = NULL;
@@ -911,11 +958,16 @@ error:    if (cardstate)
  */
 static void __exit usb_gigaset_exit(void)
 {
+       int i;
+
        gigaset_blockdriver(driver); /* => probe will fail
                                      * => no gigaset_start any more
                                      */
 
-       gigaset_shutdown(cardstate);
+       /* stop all connected devices */
+       for (i = 0; i < driver->minors; i++)
+               gigaset_shutdown(driver->cs + i);
+
        /* from now on, no isdn callback should be possible */
 
        /* deregister this driver with the USB subsystem */
@@ -923,8 +975,6 @@ static void __exit usb_gigaset_exit(void)
        /* this will call the disconnect-callback */
        /* from now on, no disconnect/probe callback should be running */
 
-       gigaset_freecs(cardstate);
-       cardstate = NULL;
        gigaset_freedriver(driver);
        driver = NULL;
 }