From sailer@ife.ee.ethz.ch Fri Sep  9 02:24:34 2005
From: Thomas Sailer <sailer@ife.ee.ethz.ch>
Cc: gregkh@suse.de, greg@kroah.com
Subject: usb: fix uss720 schedule with interrupts off
Date: Fri, 09 Sep 2005 10:43:50 +0200
Message-Id: <1126255430.4382.7.camel@playstation2.hb9jnx.ampr.org>

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 |  393 +++++++++++++++++++++++++++++++---------------
 1 file changed, 270 insertions(+), 123 deletions(-)

--- gregkh-2.6.orig/drivers/usb/misc/uss720.c	2005-09-12 11:10:10.000000000 -0700
+++ gregkh-2.6/drivers/usb/misc/uss720.c	2005-09-12 11:11:43.000000000 -0700
@@ -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
@@ -23,103 +23,240 @@
  *  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 *p
 {
 	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 *p
 		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 *p
 		}
 	}
 	/* 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 parp
 {
 	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, voi
 
 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_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
 	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
 {
 	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(s
 	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(st
 	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 
 	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 
 	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(st
 {
 	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_da
 	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_d
 	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_ad
 	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_a
 	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_a
 	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
 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;
 }