diff -ur ../orig/scanner.c ./scanner.c
--- ../orig/scanner.c	Thu Nov 29 08:44:06 2001
+++ ./scanner.c	Sun Mar 24 19:23:35 2002
@@ -334,6 +334,21 @@
  */ 
 #include "scanner.h"
 
+static void usb_scanner_free(struct scn_usb_data *scn);
+
+static inline void
+usb_scanner_inc_use(struct scn_usb_data *scn)
+{
+	atomic_inc(&scn->users);
+}
+
+static inline void
+usb_scanner_dec_use(struct scn_usb_data *scn)
+{
+	if (atomic_dec_and_test(&scn->users))
+		usb_scanner_free(scn);
+}
+
 static void
 irq_scanner(struct urb *urb)
 {
@@ -371,26 +386,33 @@
 
 	MOD_INC_USE_COUNT;
 
-	down(&scn_mutex);
-
 	scn_minor = USB_SCN_MINOR(inode);
 
 	dbg("open_scanner: scn_minor:%d", scn_minor);
 
-	if (!p_scn_table[scn_minor]) {
+	if (down_interruptible(&scn_mutex) != 0) {
+		MOD_DEC_USE_COUNT;
+		return -ERESTARTSYS;
+	}
+
+	scn = p_scn_table[scn_minor];
+	if (!scn) {
 		up(&scn_mutex);
 		MOD_DEC_USE_COUNT;
-		err("open_scanner(%d): Unable to access minor data", scn_minor);
+		dbg("open_scanner(%d): Unable to access minor data", scn_minor);
 		return -ENODEV;
 	}
 
-	scn = p_scn_table[scn_minor];
+	usb_scanner_inc_use(scn); /* Make sure the device won't go away */
 
-	dev = scn->scn_dev;
+	up(&scn_mutex); /* Now handled by the above */
 
-	down(&(scn->sem));	/* Now protect the scn_usb_data structure */ 
+	if (down_interruptible(&(scn->open_sem)) != 0) {
+		err = -ERESTARTSYS;
+		goto out_error_nounlock;
+	}
 
-	up(&scn_mutex); /* Now handled by the above */
+	dev = scn->scn_dev;
 
 	if (!dev) {
 		err("open_scanner(%d): Scanner device not present", scn_minor);
@@ -418,11 +440,13 @@
 
 
 out_error:
+	up(&(scn->open_sem)); /* Wake up any possible contending processes */
 
-	up(&(scn->sem)); /* Wake up any possible contending processes */
-
-	if (err)
+out_error_nounlock:
+	if (err) {
+		usb_scanner_dec_use(scn);
 		MOD_DEC_USE_COUNT;
+	}
 
 	return err;
 }
@@ -432,27 +456,15 @@
 {
 	struct scn_usb_data *scn;
 
-	kdev_t scn_minor;
-
-	scn_minor = USB_SCN_MINOR (inode);
-
-	dbg("close_scanner: scn_minor:%d", scn_minor);
+	scn = file->private_data;
 
-	if (!p_scn_table[scn_minor]) {
-		err("close_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENODEV;
-	}
+	dbg("close_scanner: scn_minor:%d", scn->scn_minor);
 
-	down(&scn_mutex);
-
-	scn = p_scn_table[scn_minor];
-	down(&(scn->sem));
 	scn->isopen = 0;
 
 	file->private_data = NULL;
 
-	up(&scn_mutex);
-	up(&(scn->sem));
+	usb_scanner_dec_use(scn);
 
 	MOD_DEC_USE_COUNT;
 
@@ -479,7 +491,8 @@
 
 	scn = file->private_data;
 
-	down(&(scn->sem));
+	if (down_interruptible(&(scn->sem)) != 0)
+		return -ERESTARTSYS;
 
 	scn_minor = scn->scn_minor;
 
@@ -567,7 +580,8 @@
 
 	scn = file->private_data;
 
-	down(&(scn->sem));
+	if (down_interruptible(&(scn->sem)) != 0)
+		return -ERESTARTSYS;
 
 	scn_minor = scn->scn_minor;
 
@@ -669,18 +683,14 @@
 ioctl_scanner(struct inode *inode, struct file *file,
 	      unsigned int cmd, unsigned long arg)
 {
+	struct scn_usb_data *scn;
 	struct usb_device *dev;
 
 	kdev_t scn_minor;
 
-	scn_minor = USB_SCN_MINOR(inode);
-
-	if (!p_scn_table[scn_minor]) {
-		err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENODEV;
-	}
-
-	dev = p_scn_table[scn_minor]->scn_dev;
+	scn = file->private_data;
+	dev = scn->scn_dev;
+	scn_minor = scn->scn_minor;
 
 	switch (cmd)
 	{
@@ -959,7 +969,7 @@
 	}
 
 /* Check to make sure that the last slot isn't already taken */
-	if (p_scn_table[scn_minor]) {
+	if (scn_minor >= SCN_MAX_MNR) {
 		err("probe_scanner: No more minor devices remaining.");
 		up(&scn_mutex);
 		return NULL;
@@ -974,6 +984,8 @@
 	}
 	memset (scn, 0, sizeof(struct scn_usb_data));
 
+	atomic_set(&scn->users, 1);
+	init_MUTEX(&(scn->open_sem));
 	init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
 
 	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
@@ -1039,6 +1051,7 @@
 	scn->intr_ep = have_intr;
 	scn->present = 1;
 	scn->scn_dev = dev;
+	usb_inc_dev_use(dev);
 	scn->scn_minor = scn_minor;
 	scn->isopen = 0;
 
@@ -1060,29 +1073,37 @@
 }
 
 static void
-disconnect_scanner(struct usb_device *dev, void *ptr)
+usb_scanner_free(struct scn_usb_data *scn)
 {
-	struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
-
-	down (&scn_mutex);
-	down (&(scn->sem));
+	dbg("usb_scanner_free(%d): freeing scn=%p", scn->scn_minor, scn);
 
 	if(scn->intr_ep) {
 		dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
 		usb_unlink_urb(&scn->scn_irq);
 	}
-        usb_driver_release_interface(&scanner_driver,
-                &scn->scn_dev->actconfig->interface[scn->ifnum]);
 
+	usb_dec_dev_use(scn->scn_dev);
 	kfree(scn->ibuf);
 	kfree(scn->obuf);
 
+	kfree (scn);
+}
+
+static void
+disconnect_scanner(struct usb_device *dev, void *ptr)
+{
+	struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
+
+	down (&scn_mutex);
+        usb_driver_release_interface(&scanner_driver,
+                &scn->scn_dev->actconfig->interface[scn->ifnum]);
+
 	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
 	devfs_unregister(scn->devfs);
 	p_scn_table[scn->scn_minor] = NULL;
-	up (&(scn->sem));
-	kfree (scn);
 	up (&scn_mutex);
+
+	usb_scanner_dec_use(scn);
 }
 
 static struct
diff -ur ../orig/scanner.h ./scanner.h
--- ../orig/scanner.h	Thu Nov 29 08:44:06 2001
+++ ./scanner.h	Sun Mar 24 19:12:51 2002
@@ -239,6 +239,7 @@
 static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
 
 struct scn_usb_data {
+	atomic_t users;		/* Reference count */
 	struct usb_device *scn_dev;
 	devfs_handle_t devfs;	/* devfs device */
 	struct urb scn_irq;
@@ -250,6 +251,7 @@
 	char *obuf, *ibuf;	/* transfer buffers */
 	char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */
 	wait_queue_head_t rd_wait_q; /* read timeouts */
+	struct semaphore open_sem; /* lock to prevent concurrent opens */
 	struct semaphore sem; /* lock to prevent concurrent reads or writes */
 	unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */
 };
