]> err.no Git - linux-2.6/commitdiff
[PATCH] usb: fix uss720 schedule with interrupts off
authorThomas Sailer <sailer@ife.ee.ethz.ch>
Fri, 9 Sep 2005 08:43:50 +0000 (10:43 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 12 Sep 2005 19:23:53 +0000 (12:23 -0700)
This patch fixes the long standing schedule with interrupts off problem
of the uss720 driver. The problem is caused by the parport layer calling
the save and restore methods within a write_lock_irqsave guarded region.
The fix is to issue the control transaction requests required by save
and restore asynchronously.

Signed-off-by: Thomas Sailer, <sailer@ife.ee.ethz.ch>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/misc/uss720.c

index faa74436de52cdf539a14f53c5e950d7e1c06834..03fb70ef2eb3ec14e60c5f32188a24d78d5295b4 100644 (file)
@@ -3,8 +3,8 @@
 /*
  *     uss720.c  --  USS720 USB Parport Cable.
  *
- *     Copyright (C) 1999
- *         Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *     Copyright (C) 1999, 2005
+ *         Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
  *  Based on parport_pc.c
  *
  *  History:
- *   0.1  04.08.99  Created
- *   0.2  07.08.99  Some fixes mainly suggested by Tim Waugh
- *                 Interrupt handling currently disabled because
- *                 usb_request_irq crashes somewhere within ohci.c
- *                 for no apparent reason (that is for me, anyway)
- *                 ECP currently untested
- *   0.3  10.08.99  fixing merge errors
- *   0.4  13.08.99  Added Vendor/Product ID of Brad Hard's cable
- *   0.5  20.09.99  usb_control_msg wrapper used
- *        Nov01.00  usb_device_table support by Adam J. Richter
- *        08.04.01  Identify version on module load.  gb
+ *   0.1  04.08.1999  Created
+ *   0.2  07.08.1999  Some fixes mainly suggested by Tim Waugh
+ *                   Interrupt handling currently disabled because
+ *                   usb_request_irq crashes somewhere within ohci.c
+ *                   for no apparent reason (that is for me, anyway)
+ *                   ECP currently untested
+ *   0.3  10.08.1999  fixing merge errors
+ *   0.4  13.08.1999  Added Vendor/Product ID of Brad Hard's cable
+ *   0.5  20.09.1999  usb_control_msg wrapper used
+ *        Nov01.2000  usb_device_table support by Adam J. Richter
+ *        08.04.2001  Identify version on module load.  gb
+ *   0.6  02.09.2005  Fix "scheduling in interrupt" problem by making save/restore
+ *                    context asynchronous
  *
  */
 
 /*****************************************************************************/
 
+#define DEBUG
+
 #include <linux/module.h>
 #include <linux/socket.h>
 #include <linux/parport.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/kref.h>
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5"
-#define DRIVER_AUTHOR "Thomas M. Sailer, sailer@ife.ee.ethz.ch"
+#define DRIVER_VERSION "v0.6"
+#define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch"
 #define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"
 
 /* --------------------------------------------------------------------- */
 
 struct parport_uss720_private {
        struct usb_device *usbdev;
-       void *irqhandle;
-       unsigned int irqpipe;
-       unsigned char reg[7];  /* USB registers */
+       struct parport *pp;
+       struct kref ref_count;
+       __u8 reg[7];  /* USB registers */
+       struct list_head asynclist;
+       spinlock_t asynclock;
+};
+
+struct uss720_async_request {
+       struct parport_uss720_private *priv;
+       struct kref ref_count;
+       struct list_head asynclist;
+       struct completion compl;
+       struct urb *urb;
+       struct usb_ctrlrequest dr;
+       __u8 reg[7];
 };
 
 /* --------------------------------------------------------------------- */
 
-static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val)
+static void destroy_priv(struct kref *kref)
 {
-       struct parport_uss720_private *priv = pp->private_data;
-       struct usb_device *usbdev = priv->usbdev;
-       static const unsigned char regindex[9] = {
-               4, 0, 1, 5, 5, 0, 2, 3, 6
-       };
-       int ret;
+       struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);
 
-       if (!usbdev)
-               return -1;
-       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, 1000);
-       if (ret != 7) {
-               printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x expected 7\n",
-                      (unsigned int)reg, ret);
-               ret = -1;
-       } else {
+       usb_put_dev(priv->usbdev);
+       kfree(priv);
+       dbg("destroying priv datastructure");
+}
+
+static void destroy_async(struct kref *kref)
+{
+       struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count);
+       struct parport_uss720_private *priv = rq->priv;
+       unsigned long flags;
+
+       if (likely(rq->urb))
+               usb_free_urb(rq->urb);
+       spin_lock_irqsave(&priv->asynclock, flags);
+       list_del_init(&rq->asynclist);
+       spin_unlock_irqrestore(&priv->asynclock, flags);
+       kfree(rq);
+       kref_put(&priv->ref_count, destroy_priv);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void async_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+       struct uss720_async_request *rq;
+       struct parport *pp;
+       struct parport_uss720_private *priv;
+
+       rq = urb->context;
+       priv = rq->priv;
+       pp = priv->pp;
+       if (urb->status) {
+               err("async_complete: urb error %d", urb->status);
+       } else if (rq->dr.bRequest == 3) {
+               memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
-               printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n",
-                      (unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
-                      (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4],
-                      (unsigned int)priv->reg[5], (unsigned int)priv->reg[6]);
+               dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x",
+                   (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2],
+                   (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
+                   (unsigned int)priv->reg[6]);
 #endif
                /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
-               if (priv->reg[2] & priv->reg[1] & 0x10)
+               if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
                        parport_generic_irq(0, pp, NULL);
-               ret = 0;
        }
-       if (val)
-               *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
-       return ret;
+       complete(&rq->compl);
+       kref_put(&rq->ref_count, destroy_async);
 }
 
-static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val)
+static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv,
+                                                        __u8 request, __u8 requesttype, __u16 value, __u16 index,
+                                                        unsigned int mem_flags)
 {
-       struct parport_uss720_private *priv = pp->private_data;
-       struct usb_device *usbdev = priv->usbdev;
+       struct usb_device *usbdev;
+       struct uss720_async_request *rq;
+       unsigned long flags;
        int ret;
 
+       if (!priv)
+               return NULL;
+       usbdev = priv->usbdev;
        if (!usbdev)
-               return -1;
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, 1000);
-       if (ret) {
-               printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", 
-                      (unsigned int)reg, (unsigned int)val, ret);
-       } else {
-#if 0
-               printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n", 
-                      (unsigned int)reg, (unsigned int)val);
-#endif
+               return NULL;
+       rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
+       if (!rq) {
+               err("submit_async_request out of memory");
+               return NULL;
+       }
+       kref_init(&rq->ref_count);
+       INIT_LIST_HEAD(&rq->asynclist);
+       init_completion(&rq->compl);
+       kref_get(&priv->ref_count);
+       rq->priv = priv;
+       rq->urb = usb_alloc_urb(0, mem_flags);
+       if (!rq->urb) {
+               kref_put(&rq->ref_count, destroy_async);
+               err("submit_async_request out of memory");
+               return NULL;
+       }
+       rq->dr.bRequestType = requesttype;
+       rq->dr.bRequest = request;
+       rq->dr.wValue = cpu_to_le16(value);
+       rq->dr.wIndex = cpu_to_le16(index);
+       rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
+       usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),
+                            (unsigned char *)&rq->dr,
+                            (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);
+       /* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */
+       spin_lock_irqsave(&priv->asynclock, flags);
+       list_add_tail(&rq->asynclist, &priv->asynclist);
+       spin_unlock_irqrestore(&priv->asynclock, flags);
+       ret = usb_submit_urb(rq->urb, mem_flags);
+       if (!ret) {
+               kref_get(&rq->ref_count);
+               return rq;
        }
+       kref_put(&rq->ref_count, destroy_async);
+       err("submit_async_request submit_urb failed with %d", ret);
+       return NULL;
+}
+
+static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv)
+{
+       struct uss720_async_request *rq;
+       unsigned long flags;
+       unsigned int ret = 0;
+
+       spin_lock_irqsave(&priv->asynclock, flags);
+       list_for_each_entry(rq, &priv->asynclist, asynclist) {
+               usb_unlink_urb(rq->urb);
+               ret++;
+       }
+       spin_unlock_irqrestore(&priv->asynclock, flags);
        return ret;
 }
 
 /* --------------------------------------------------------------------- */
 
+static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, unsigned int mem_flags)
+{
+       struct parport_uss720_private *priv;
+       struct uss720_async_request *rq;
+       static const unsigned char regindex[9] = {
+               4, 0, 1, 5, 5, 0, 2, 3, 6
+       };
+       int ret;
+
+       if (!pp)
+               return -EIO;
+       priv = pp->private_data;
+       rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);
+       if (!rq) {
+               err("get_1284_register(%u) failed", (unsigned int)reg);
+               return -EIO;
+       }
+       if (!val) {
+               kref_put(&rq->ref_count, destroy_async);
+               return 0;
+       }
+       if (wait_for_completion_timeout(&rq->compl, HZ)) {
+               ret = rq->urb->status;
+               *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
+               if (ret)
+                       warn("get_1284_register: usb error %d", ret);
+               kref_put(&rq->ref_count, destroy_async);
+               return ret;
+       }
+       warn("get_1284_register timeout");
+       kill_all_async_requests_priv(priv);
+       return -EIO;
+}
+
+static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, unsigned int mem_flags)
+{
+       struct parport_uss720_private *priv;
+       struct uss720_async_request *rq;
+
+       if (!pp)
+               return -EIO;
+       priv = pp->private_data;
+       rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);
+       if (!rq) {
+               err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val);
+               return -EIO;
+       }
+       kref_put(&rq->ref_count, destroy_async);
+       return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
 /* ECR modes */
 #define ECR_SPP 00
 #define ECR_PS2 01
@@ -132,8 +269,9 @@ static int change_mode(struct parport *pp, int m)
 {
        struct parport_uss720_private *priv = pp->private_data;
        int mode;
+       __u8 reg;
 
-       if (get_1284_register(pp, 6, NULL))
+       if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
                return -EIO;
        /* Bits <7:5> contain the mode. */
        mode = (priv->reg[2] >> 5) & 0x7;
@@ -153,7 +291,7 @@ static int change_mode(struct parport *pp, int m)
                case ECR_ECP: /* ECP Parallel Port mode */
                        /* Poll slowly. */
                        for (;;) {
-                               if (get_1284_register(pp, 6, NULL))
+                               if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
                                        return -EIO;
                                if (priv->reg[2] & 0x01)
                                        break;
@@ -167,7 +305,9 @@ static int change_mode(struct parport *pp, int m)
                }
        }
        /* Set the mode. */
-       if (set_1284_register(pp, 6, m << 5))
+       if (set_1284_register(pp, 6, m << 5, GFP_KERNEL))
+               return -EIO;
+       if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
                return -EIO;
        return 0;
 }
@@ -179,7 +319,7 @@ static int clear_epp_timeout(struct parport *pp)
 {
        unsigned char stat;
 
-       if (get_1284_register(pp, 1, &stat))
+       if (get_1284_register(pp, 1, &stat, GFP_KERNEL))
                return 1;
        return stat & 1;
 }
@@ -205,14 +345,14 @@ static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
 
 static void parport_uss720_write_data(struct parport *pp, unsigned char d)
 {
-       set_1284_register(pp, 0, d);
+       set_1284_register(pp, 0, d, GFP_KERNEL);
 }
 
 static unsigned char parport_uss720_read_data(struct parport *pp)
 {
        unsigned char ret;
 
-       if (get_1284_register(pp, 0, &ret))
+       if (get_1284_register(pp, 0, &ret, GFP_KERNEL))
                return 0;
        return ret;
 }
@@ -222,7 +362,7 @@ static void parport_uss720_write_control(struct parport *pp, unsigned char d)
        struct parport_uss720_private *priv = pp->private_data; 
 
        d = (d & 0xf) | (priv->reg[1] & 0xf0);
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -241,7 +381,7 @@ static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned ch
        mask &= 0x0f;
        val &= 0x0f;
        d = (priv->reg[1] & (~mask)) ^ val;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return 0;
        priv->reg[1] = d;
        return d & 0xf;
@@ -251,7 +391,7 @@ static unsigned char parport_uss720_read_status(struct parport *pp)
 {
        unsigned char ret;
 
-       if (get_1284_register(pp, 1, &ret))
+       if (get_1284_register(pp, 1, &ret, GFP_KERNEL))
                return 0;
        return ret & 0xf8;
 }
@@ -262,7 +402,7 @@ static void parport_uss720_disable_irq(struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] & ~0x10;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -273,7 +413,7 @@ static void parport_uss720_enable_irq(struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] | 0x10;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -284,7 +424,7 @@ static void parport_uss720_data_forward (struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] & ~0x20;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -295,7 +435,7 @@ static void parport_uss720_data_reverse (struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] | 0x20;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -310,17 +450,23 @@ static void parport_uss720_save_state(struct parport *pp, struct parport_state *
 {
        struct parport_uss720_private *priv = pp->private_data; 
 
-       if (get_1284_register(pp, 2, NULL))
+#if 0
+       if (get_1284_register(pp, 2, NULL, GFP_ATOMIC))
                return;
+#endif
        s->u.pc.ctr = priv->reg[1];
        s->u.pc.ecr = priv->reg[2];
 }
 
 static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
 {
-       set_1284_register(pp, 2, s->u.pc.ctr);
-       set_1284_register(pp, 6, s->u.pc.ecr);
-       get_1284_register(pp, 2, NULL);
+       struct parport_uss720_private *priv = pp->private_data;
+
+       set_1284_register(pp, 2, s->u.pc.ctr, GFP_ATOMIC);
+       set_1284_register(pp, 6, s->u.pc.ecr, GFP_ATOMIC);
+       get_1284_register(pp, 2, NULL, GFP_ATOMIC);
+       priv->reg[1] = s->u.pc.ctr;
+       priv->reg[2] = s->u.pc.ecr;
 }
 
 static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
@@ -331,7 +477,7 @@ static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; got < length; got++) {
-               if (get_1284_register(pp, 4, (char *)buf))
+               if (get_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
                        break;
                buf++;
                if (priv->reg[0] & 0x01) {
@@ -352,10 +498,10 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf,
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; written < length; written++) {
-               if (set_1284_register(pp, 4, (char *)buf))
+               if (set_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
                        break;
                ((char*)buf)++;
-               if (get_1284_register(pp, 1, NULL))
+               if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
                        break;
                if (priv->reg[0] & 0x01) {
                        clear_epp_timeout(pp);
@@ -390,7 +536,7 @@ static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; got < length; got++) {
-               if (get_1284_register(pp, 3, (char *)buf))
+               if (get_1284_register(pp, 3, (char *)buf, GFP_KERNEL))
                        break;
                buf++;
                if (priv->reg[0] & 0x01) {
@@ -410,10 +556,10 @@ static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf,
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; written < length; written++) {
-               if (set_1284_register(pp, 3, *(char *)buf))
+               if (set_1284_register(pp, 3, *(char *)buf, GFP_KERNEL))
                        break;
                buf++;
-               if (get_1284_register(pp, 1, NULL))
+               if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
                        break;
                if (priv->reg[0] & 0x01) {
                        clear_epp_timeout(pp);
@@ -467,7 +613,7 @@ static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buff
        if (change_mode(pp, ECR_ECP))
                return 0;
        for (; written < len; written++) {
-               if (set_1284_register(pp, 5, *(char *)buffer))
+               if (set_1284_register(pp, 5, *(char *)buffer, GFP_KERNEL))
                        break;
                buffer++;
        }
@@ -536,93 +682,91 @@ static struct parport_operations parport_uss720_ops =
 static int uss720_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
-       struct usb_device *usbdev = interface_to_usbdev(intf);
+       struct usb_device *usbdev = usb_get_dev(interface_to_usbdev(intf));
        struct usb_host_interface *interface;
        struct usb_host_endpoint *endpoint;
        struct parport_uss720_private *priv;
        struct parport *pp;
+       unsigned char reg;
        int i;
 
-       printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n",
-              le16_to_cpu(usbdev->descriptor.idVendor),
-              le16_to_cpu(usbdev->descriptor.idProduct));
+       dbg("probe: vendor id 0x%x, device id 0x%x\n",
+           le16_to_cpu(usbdev->descriptor.idVendor),
+           le16_to_cpu(usbdev->descriptor.idProduct));
 
        /* our known interfaces have 3 alternate settings */
-       if (intf->num_altsetting != 3)
+       if (intf->num_altsetting != 3) {
+               usb_put_dev(usbdev);
                return -ENODEV;
-
+       }
        i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
-       printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
+       dbg("set inteface result %d", i);
 
        interface = intf->cur_altsetting;
 
        /*
         * Allocate parport interface 
         */
-       printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
-
-       if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
+       if (!(priv = kcalloc(sizeof(struct parport_uss720_private), 1, GFP_KERNEL))) {
+               usb_put_dev(usbdev);
                return -ENOMEM;
+       }
+       priv->pp = NULL;
+       priv->usbdev = usbdev;
+       kref_init(&priv->ref_count);
+       spin_lock_init(&priv->asynclock);
+       INIT_LIST_HEAD(&priv->asynclist);
        if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
-               printk(KERN_WARNING "usb-uss720: could not register parport\n");
+               warn("could not register parport");
                goto probe_abort;
        }
 
+       priv->pp = pp;
        pp->private_data = priv;
-       priv->usbdev = usbdev;
        pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
 
        /* set the USS720 control register to manual mode, no ECP compression, enable all ints */
-       set_1284_register(pp, 7, 0x00);
-       set_1284_register(pp, 6, 0x30);  /* PS/2 mode */
-       set_1284_register(pp, 2, 0x0c);
+       set_1284_register(pp, 7, 0x00, GFP_KERNEL);
+       set_1284_register(pp, 6, 0x30, GFP_KERNEL);  /* PS/2 mode */
+       set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
        /* debugging */
-       get_1284_register(pp, 0, NULL);
-       printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n",
-              priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+       get_1284_register(pp, 0, &reg, GFP_KERNEL);
+       dbg("reg: %02x %02x %02x %02x %02x %02x %02x",
+           priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
 
        endpoint = &interface->endpoint[2];
-       printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
-#if 0
-       priv->irqpipe = usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress);
-       i = usb_request_irq(usbdev, priv->irqpipe,
-                                 uss720_irq, endpoint->bInterval,
-                                 pp, &priv->irqhandle);
-       if (i) {
-               printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i);
-               goto probe_abort_port;
-       }
-#endif
+       dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
        parport_announce_port(pp);
 
-       usb_set_intfdata (intf, pp);
+       usb_set_intfdata(intf, pp);
        return 0;
 
-#if 0
-probe_abort_port:
-       parport_put_port(pp);
-#endif
 probe_abort:
-       kfree(priv);
+       kill_all_async_requests_priv(priv);
+       kref_put(&priv->ref_count, destroy_priv);
        return -ENODEV;
 }
 
 static void uss720_disconnect(struct usb_interface *intf)
 {
-       struct parport *pp = usb_get_intfdata (intf);
+       struct parport *pp = usb_get_intfdata(intf);
        struct parport_uss720_private *priv;
+       struct usb_device *usbdev;
 
-       usb_set_intfdata (intf, NULL);
+       dbg("disconnect");
+       usb_set_intfdata(intf, NULL);
        if (pp) {
                priv = pp->private_data;
-               parport_remove_port(pp);
-#if 0
-               usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
-#endif
+               usbdev = priv->usbdev;
                priv->usbdev = NULL;
+               priv->pp = NULL;
+               dbg("parport_remove_port");
+               parport_remove_port(pp);
                parport_put_port(pp);
-               kfree(priv);
+               kill_all_async_requests_priv(priv);
+               kref_put(&priv->ref_count, destroy_priv);
        }
+       dbg("disconnect done");
 }
 
 /* table of cables that work through this driver */
@@ -647,8 +791,8 @@ static struct usb_driver uss720_driver = {
 
 /* --------------------------------------------------------------------- */
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 static int __init uss720_init(void)
@@ -659,6 +803,9 @@ static int __init uss720_init(void)
                goto out;
 
        info(DRIVER_VERSION ":" DRIVER_DESC);
+       info("NOTE: this is a special purpose driver to allow nonstandard");
+       info("protocols (eg. bitbang) over USS720 usb to parallel cables");
+       info("If you just want to connect to a printer, use usblp instead");
 out:
        return retval;
 }