Hi,

On Tue, Nov 12, 2002 at 11:59:02PM -0800, Greg KH wrote:
> > I think that's a rather low-risk patch that can be applied. That's why
> > I splitted it from the patch that fixes the "two-endpoints-only" issue
> > and the "can't unload" issue of the scanner driver (posted earlier on
> > linux-usb-devel).
> 
> Mind sending me a copy of these patches again?  It doesn't seem like
> Brian is very responsive lately...

Ok, here it is. Most of the code is from Sergey Vlasov
<[EMAIL PROTECTED]>. I've increased the version number, brought the
version number used in scanner.h in sync, added a ChangeLog entry
(including the previous vendor/device id additions).

I can't comment on the way, how the bugs are fixed in this patch
because I just don't know enough of kernel programming. However, the
code works for me and other users since some weeks without any
problem. It fixes the following bugs:

- can't rmmod scanner, because usage_count isn't 0 (especially if the
  scanner was disconnected during scan)
- scanning for devices takes very long (now down from 25 seconds to
  0.5 seconds with sane-1.0.9)
- lots of "Unable to access minor data" syslog messages are printed
  when scanning for devices
- only scanners with a bulk-out endpoint are supported

Bye,
  Henning

diff -u -r linux-2.4.20-rc1/drivers/usb/scanner.c 
linux-2.4.20-rc1-compile/drivers/usb/scanner.c
--- linux-2.4.20-rc1/drivers/usb/scanner.c      2002-11-07 13:45:15.000000000 +0100
+++ linux-2.4.20-rc1-compile/drivers/usb/scanner.c      2002-11-13 15:58:24.000000000 
++0100
@@ -1,7 +1,7 @@
 /* -*- linux-c -*- */
 
 /* 
- * Driver for USB Scanners (linux-2.4.18)
+ * Driver for USB Scanners (linux-2.4.21)
  *
  * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
  *
@@ -311,8 +311,17 @@
  *    - Changed maintainership from David E. Nelson to Brian
  *      Beattie <[EMAIL PROTECTED]>.
  *
+ * 0.4.9  11/13/2002
+ *    - Added some Mustek BearPaw and Lexmark IDs (from Henning 
+ *      Meier-Geinitz <[EMAIL PROTECTED]>),
+ *    - Support for scanners without bulk-out endpoint (from Sergey
+ *      Vlasov <[EMAIL PROTECTED]>).
+ *    - Fixed wrong usage count when devices were disconnected while opened
+ *      (from Sergey Vlasov <[EMAIL PROTECTED]>).
+ *    - "Unable to access minor data" is only a dbg message now and doesn't
+ *      clutter syslog.
+ *
  * TODO
- *    - Remove the 2/3 endpoint limitation
  *    - Performance
  *    - Select/poll methods
  *    - More testing
@@ -349,6 +358,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)
 {
@@ -386,26 +410,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);
@@ -433,11 +464,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;
 }
@@ -447,27 +480,15 @@
 {
        struct scn_usb_data *scn;
 
-       kdev_t scn_minor;
-
-       scn_minor = USB_SCN_MINOR (inode);
-
-       dbg("close_scanner: scn_minor:%d", scn_minor);
-
-       if (!p_scn_table[scn_minor]) {
-               err("close_scanner(%d): invalid scn_minor", scn_minor);
-               return -ENODEV;
-       }
+       scn = file->private_data;
 
-       down(&scn_mutex);
+       dbg("close_scanner: scn_minor:%d", scn->scn_minor);
 
-       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;
 
@@ -494,7 +515,14 @@
 
        scn = file->private_data;
 
-       down(&(scn->sem));
+       if (down_interruptible(&(scn->sem)) != 0)
+               return -ERESTARTSYS;
+
+       if (!scn->bulk_out_ep) {
+               /* This scanner does not have a bulk-out endpoint */
+               up(&(scn->sem));
+               return -EINVAL;
+       }
 
        scn_minor = scn->scn_minor;
 
@@ -582,7 +610,8 @@
 
        scn = file->private_data;
 
-       down(&(scn->sem));
+       if (down_interruptible(&(scn->sem)) != 0)
+               return -ERESTARTSYS;
 
        scn_minor = scn->scn_minor;
 
@@ -684,18 +713,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)
        {
@@ -902,8 +927,8 @@
 
        dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints);
 
-       if ((interface->bNumEndpoints != 2) && (interface->bNumEndpoints != 3)) {
-               info("probe_scanner: Only two or three endpoints supported.");
+       if ((interface->bNumEndpoints < 1) || (interface->bNumEndpoints > 3)) {
+               info("probe_scanner: Only 1, 2, or 3 endpoints supported.");
                return NULL;
        }
 
@@ -942,6 +967,12 @@
  */
 
        switch(interface->bNumEndpoints) {
+       case 1:
+               if (!have_bulk_in) {
+                       info("probe_scanner: One bulk-in endpoint required.");
+                       return NULL;
+               }
+               break;
        case 2:
                if (!have_bulk_in || !have_bulk_out) {
                        info("probe_scanner: Two bulk endpoints required.");
@@ -974,7 +1005,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;
@@ -989,6 +1020,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);
@@ -1054,6 +1087,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;
 
@@ -1075,29 +1109,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
Nur in linux-2.4.20-rc1-compile/drivers/usb/: scanner.c~.
diff -u -r linux-2.4.20-rc1/drivers/usb/scanner.h 
linux-2.4.20-rc1-compile/drivers/usb/scanner.h
--- linux-2.4.20-rc1/drivers/usb/scanner.h      2002-11-07 13:45:15.000000000 +0100
+++ linux-2.4.20-rc1-compile/drivers/usb/scanner.h      2002-11-13 15:47:40.000000000 
++0100
@@ -1,5 +1,5 @@
 /*
- * Driver for USB Scanners (linux-2.4.18)
+ * Driver for USB Scanners (linux-2.4.21)
  *
  * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
  *
@@ -41,7 +41,7 @@
  */
 // #define PV8630 
 
-#define DRIVER_VERSION "0.4.6"
+#define DRIVER_VERSION "0.4.9"
 #define DRIVER_DESC "USB Scanner Driver"
 
 #include <linux/usb.h>
@@ -249,6 +249,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;
@@ -260,6 +261,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. */
 };


-------------------------------------------------------
This sf.net email is sponsored by: Are you worried about 
your web server security? Click here for a FREE Thawte 
Apache SSL Guide and answer your Apache SSL security 
needs: http://www.gothawte.com/rd523.html
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to