]> git.hungrycats.org Git - linux/commitdiff
USB
authorGreg Kroah-Hartman <greg@kroah.com>
Thu, 4 Apr 2002 15:18:16 +0000 (07:18 -0800)
committerGreg Kroah-Hartman <greg@kroah.com>
Thu, 4 Apr 2002 15:18:16 +0000 (07:18 -0800)
fixed lib Makefile problem with usb files moving
moved drivers/usb/scanner/ to drivers/usb/image/

23 files changed:
drivers/usb/class/Makefile.lib [new file with mode: 0644]
drivers/usb/image/Config.in [new file with mode: 0644]
drivers/usb/image/Makefile [new file with mode: 0644]
drivers/usb/image/dc2xx.c [new file with mode: 0644]
drivers/usb/image/hpusbscsi.c [new file with mode: 0644]
drivers/usb/image/hpusbscsi.h [new file with mode: 0644]
drivers/usb/image/mdc800.c [new file with mode: 0644]
drivers/usb/image/microtek.c [new file with mode: 0644]
drivers/usb/image/microtek.h [new file with mode: 0644]
drivers/usb/image/scanner.c [new file with mode: 0644]
drivers/usb/image/scanner.h [new file with mode: 0644]
drivers/usb/net/Makefile.lib [deleted file]
drivers/usb/scanner/Config.in [deleted file]
drivers/usb/scanner/Makefile [deleted file]
drivers/usb/scanner/dc2xx.c [deleted file]
drivers/usb/scanner/hpusbscsi.c [deleted file]
drivers/usb/scanner/hpusbscsi.h [deleted file]
drivers/usb/scanner/mdc800.c [deleted file]
drivers/usb/scanner/microtek.c [deleted file]
drivers/usb/scanner/microtek.h [deleted file]
drivers/usb/scanner/scanner.c [deleted file]
drivers/usb/scanner/scanner.h [deleted file]
lib/Makefile

diff --git a/drivers/usb/class/Makefile.lib b/drivers/usb/class/Makefile.lib
new file mode 100644 (file)
index 0000000..891c918
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_CATC)         += crc32.o
diff --git a/drivers/usb/image/Config.in b/drivers/usb/image/Config.in
new file mode 100644 (file)
index 0000000..8ae0266
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# USB Imageing devices configuration
+#
+comment 'USB Imaging devices'
+dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
+dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
+dep_tristate '  HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+
+# Turn on CONFIG_USB_IMAGE if any of the drivers are compiled into the kernel to
+# make our Makefile logic a bit simpler
+if [ "$CONFIG_USB_DC2XX" = "y" -o "$CONFIG_USB_MDC800" = "y" ]; then
+   define_bool CONFIG_USB_IMAGE y
+fi
+if [ "$CONFIG_USB_SCANNER" = "y" -o "$CONFIG_USB_MICROTEK" = "y" -o "$CONFIG_USB_HPUSBSCSI" = "y" ]; then
+   define_bool CONFIG_USB_IMAGE y
+fi
+   
diff --git a/drivers/usb/image/Makefile b/drivers/usb/image/Makefile
new file mode 100644 (file)
index 0000000..ee46e08
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for USB Image drivers
+#
+
+O_TARGET       := usb-image.o
+
+obj-$(CONFIG_USB_DC2XX)                += dc2xx.o
+obj-$(CONFIG_USB_MDC800)       += mdc800.o
+obj-$(CONFIG_USB_HPUSBSCSI)    += hpusbscsi.o
+obj-$(CONFIG_USB_MICROTEK)     += microtek.o
+obj-$(CONFIG_USB_SCANNER)      += scanner.o
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/image/dc2xx.c b/drivers/usb/image/dc2xx.c
new file mode 100644 (file)
index 0000000..08c7485
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * USB driver for Kodak DC-2XX series digital still cameras
+ *
+ * The protocol here is the same as the one going over a serial line, but
+ * it uses USB for speed.  Set up /dev/kodak, get gphoto (www.gphoto.org),
+ * and have fun!
+ *
+ * This should also work for a number of other digital (non-Kodak) cameras,
+ * by adding the vendor and product IDs to the table below.  They'll need
+ * to be the sort using USB just as a fast bulk data channel.
+ */
+
+/*
+ * HISTORY
+ *
+ * 26 August, 1999 -- first release (0.1), works with my DC-240.
+ *     The DC-280 (2Mpixel) should also work, but isn't tested.
+ *     If you use gphoto, make sure you have the USB updates.
+ *     Lives in a 2.3.14 or so Linux kernel, in drivers/usb.
+ * 31 August, 1999 -- minor update to recognize DC-260 and handle
+ *     its endpoints being in a different order.  Note that as
+ *     of gPhoto 0.36pre, the USB updates are integrated.
+ * 12 Oct, 1999 -- handle DC-280 interface class (0xff not 0x0);
+ *     added timeouts to bulk_msg calls.  Minor updates, docs.
+ * 03 Nov, 1999 -- update for 2.3.25 kernel API changes.
+ * 08 Jan, 2000 .. multiple camera support
+ * 12 Aug, 2000 .. add some real locking, remove an Oops
+ * 10 Oct, 2000 .. usb_device_id table created. 
+ * 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter
+ * 08 Apr, 2001 .. Identify version on module load. gb
+ *
+ * Thanks to:  the folk who've provided USB product IDs, sent in
+ * patches, and shared their successes!
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/devfs_fs_kernel.h>
+
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+
+/* /dev/usb dir. */
+extern devfs_handle_t usb_devfs_handle;                        
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_AUTHOR "David Brownell, <dbrownell@users.sourceforge.net>"
+#define DRIVER_DESC "USB Camera Driver for Kodak DC-2xx series cameras"
+
+
+/* current USB framework handles max of 16 USB devices per driver */
+#define        MAX_CAMERAS             16
+
+/* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
+#define        USB_CAMERA_MINOR_BASE   80
+
+
+// XXX remove packet size limit, now that bulk transfers seem fixed
+
+/* Application protocol limit is 0x8002; USB has disliked that limit! */
+#define        MAX_PACKET_SIZE         0x2000          /* e.g. image downloading */
+
+#define        MAX_READ_RETRY          5               /* times to retry reads */
+#define        MAX_WRITE_RETRY         5               /* times to retry writes */
+#define        RETRY_TIMEOUT           (HZ)            /* sleep between retries */
+
+
+/* table of cameras that work through this driver */
+static struct usb_device_id camera_table [] = {
+       /* These have the same application level protocol */  
+       { USB_DEVICE(0x040a, 0x0120) },         // Kodak DC-240
+       { USB_DEVICE(0x040a, 0x0130) },         // Kodak DC-280
+       { USB_DEVICE(0x040a, 0x0131) },         // Kodak DC-5000
+       { USB_DEVICE(0x040a, 0x0132) },         // Kodak DC-3400
+
+       /* These have a different application level protocol which
+        * is part of the Flashpoint "DigitaOS".  That supports some
+        * non-camera devices, and some non-Kodak cameras.
+        * Use this driver to get USB and "OpenDis" to talk.
+        */  
+       { USB_DEVICE(0x040a, 0x0100) },         // Kodak DC-220
+       { USB_DEVICE(0x040a, 0x0110) },         // Kodak DC-260
+       { USB_DEVICE(0x040a, 0x0111) },         // Kodak DC-265
+       { USB_DEVICE(0x040a, 0x0112) },         // Kodak DC-290
+       { USB_DEVICE(0xf003, 0x6002) },         // HP PhotoSmart C500
+       { USB_DEVICE(0x03f0, 0x4102) },         // HP PhotoSmart C618
+       { USB_DEVICE(0x0a17, 0x1001) },         // Pentax EI-200
+
+       /* Other USB devices may well work here too, so long as they
+        * just stick to half duplex bulk packet exchanges.  That
+        * means, among other things, no iso or interrupt endpoints.
+        */
+
+       { }                                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, camera_table);
+
+
+struct camera_state {
+       struct usb_device       *dev;           /* USB device handle */
+       int                     inEP;           /* read endpoint */
+       int                     outEP;          /* write endpoint */
+       const struct usb_device_id      *info;  /* DC-240, etc */
+       int                     subminor;       /* which minor dev #? */
+       struct semaphore        sem;            /* locks this struct */
+
+       /* this is non-null iff the device is open */
+       char                    *buf;           /* buffer for I/O */
+
+       devfs_handle_t          devfs;          /* devfs device */
+
+       /* always valid */
+       wait_queue_head_t       wait;           /* for timed waits */
+};
+
+/* Support multiple cameras, possibly of different types.  */
+static struct camera_state *minor_data [MAX_CAMERAS];
+
+/* make this an rwlock if contention becomes an issue */
+static DECLARE_MUTEX (state_table_mutex);
+
+static ssize_t camera_read (struct file *file,
+       char *buf, size_t len, loff_t *ppos)
+{
+       struct camera_state     *camera;
+       int                     retries;
+       int                     retval = 0;
+
+       if (len > MAX_PACKET_SIZE)
+               return -EINVAL;
+
+       camera = (struct camera_state *) file->private_data;
+       down (&camera->sem);
+       if (!camera->dev) {
+               up (&camera->sem);
+               return -ENODEV;
+       }
+
+       /* Big reads are common, for image downloading.  Smaller ones
+        * are also common (even "directory listing" commands don't
+        * send very much data).  We preserve packet boundaries here,
+        * they matter in the application protocol.
+        */
+       for (retries = 0; retries < MAX_READ_RETRY; retries++) {
+               int                     count;
+
+               if (signal_pending (current)) {
+                       retval = -EINTR;
+                       break;
+               }
+
+               retval = usb_bulk_msg (camera->dev,
+                         usb_rcvbulkpipe (camera->dev, camera->inEP),
+                         camera->buf, len, &count, HZ*10);
+
+               dbg ("read (%Zd) - 0x%x %d", len, retval, count);
+
+               if (!retval) {
+                       if (copy_to_user (buf, camera->buf, count))
+                               retval = -EFAULT;
+                       else
+                               retval = count;
+                       break;
+               }
+               if (retval != -ETIMEDOUT)
+                       break;
+               interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT);
+
+               dbg ("read (%Zd) - retry", len);
+       }
+       up (&camera->sem);
+       return retval;
+}
+
+static ssize_t camera_write (struct file *file,
+       const char *buf, size_t len, loff_t *ppos)
+{
+       struct camera_state     *camera;
+       ssize_t                 bytes_written = 0;
+
+       if (len > MAX_PACKET_SIZE)
+               return -EINVAL;
+
+       camera = (struct camera_state *) file->private_data;
+       down (&camera->sem);
+       if (!camera->dev) {
+               up (&camera->sem);
+               return -ENODEV;
+       }
+       
+       /* most writes will be small: simple commands, sometimes with
+        * parameters.  putting images (like borders) into the camera
+        * would be the main use of big writes.
+        */
+       while (len > 0) {
+               char            *obuf = camera->buf;
+               int             maxretry = MAX_WRITE_RETRY;
+               unsigned long   copy_size, thistime;
+
+               /* it's not clear that retrying can do any good ... or that
+                * fragmenting application packets into N writes is correct.
+                */
+               thistime = copy_size = len;
+               if (copy_from_user (obuf, buf, copy_size)) {
+                       bytes_written = -EFAULT;
+                       break;
+               }
+               while (thistime) {
+                       int             result;
+                       int             count;
+
+                       if (signal_pending (current)) {
+                               if (!bytes_written)
+                                       bytes_written = -EINTR;
+                               goto done;
+                       }
+
+                       result = usb_bulk_msg (camera->dev,
+                                usb_sndbulkpipe (camera->dev, camera->outEP),
+                                obuf, thistime, &count, HZ*10);
+
+                       if (result)
+                               dbg ("write USB err - %d", result);
+
+                       if (count) {
+                               obuf += count;
+                               thistime -= count;
+                               maxretry = MAX_WRITE_RETRY;
+                               continue;
+                       } else if (!result)
+                               break;
+                               
+                       if (result == -ETIMEDOUT) {     /* NAK - delay a bit */
+                               if (!maxretry--) {
+                                       if (!bytes_written)
+                                               bytes_written = -ETIME;
+                                       goto done;
+                               }
+                                interruptible_sleep_on_timeout (&camera->wait,
+                                       RETRY_TIMEOUT);
+                               continue;
+                       } 
+                       if (!bytes_written)
+                               bytes_written = -EIO;
+                       goto done;
+               }
+               bytes_written += copy_size;
+               len -= copy_size;
+               buf += copy_size;
+       }
+done:
+       up (&camera->sem);
+       dbg ("wrote %Zd", bytes_written); 
+       return bytes_written;
+}
+
+static int camera_open (struct inode *inode, struct file *file)
+{
+       struct camera_state     *camera = NULL;
+       int                     subminor;
+       int                     value = 0;
+
+       down (&state_table_mutex);
+       subminor = minor (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
+       if (subminor < 0 || subminor >= MAX_CAMERAS
+                       || !(camera = minor_data [subminor])) {
+               up (&state_table_mutex);
+               return -ENODEV;
+       }
+       down (&camera->sem);
+       up (&state_table_mutex);
+
+       if (camera->buf) {
+               value = -EBUSY;
+               goto done;
+       }
+
+       if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) {
+               value = -ENOMEM;
+               goto done;
+       }
+
+       dbg ("open #%d", subminor); 
+
+       file->private_data = camera;
+done:
+       up (&camera->sem);
+       return value;
+}
+
+static int camera_release (struct inode *inode, struct file *file)
+{
+       struct camera_state     *camera;
+       int                     subminor;
+
+       camera = (struct camera_state *) file->private_data;
+       down (&state_table_mutex);
+       down (&camera->sem);
+
+       if (camera->buf) {
+               kfree (camera->buf);
+               camera->buf = 0;
+       }
+       subminor = camera->subminor;
+
+       /* If camera was unplugged with open file ... */
+       if (!camera->dev) {
+               minor_data [subminor] = NULL;
+               kfree (camera);
+       } else
+               up (&camera->sem);
+       
+       up (&state_table_mutex);
+
+       dbg ("close #%d", subminor); 
+
+       return 0;
+}
+
+       /* XXX should define some ioctls to expose camera type
+        * to applications ... what USB exposes should suffice.
+        * apps should be able to see the camera type.
+        */
+static /* const */ struct file_operations usb_camera_fops = {
+           /* Uses GCC initializer extension; simpler to maintain */
+       owner:          THIS_MODULE,
+       read:           camera_read,
+       write:          camera_write,
+       open:           camera_open,
+       release:        camera_release,
+};
+
+
+
+static void *
+camera_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *camera_info)
+{
+       int                             i;
+       struct usb_interface_descriptor *interface;
+       struct usb_endpoint_descriptor  *endpoint;
+       int                             direction, ep;
+       char name[8];
+       struct camera_state             *camera = NULL;
+
+
+       /* these have one config, one interface */
+       if (dev->descriptor.bNumConfigurations != 1
+                       || dev->config[0].bNumInterfaces != 1) {
+               dbg ("Bogus camera config info");
+               return NULL;
+       }
+
+       /* models differ in how they report themselves */
+       interface = &dev->actconfig->interface[ifnum].altsetting[0];
+       if ((interface->bInterfaceClass != USB_CLASS_PER_INTERFACE
+               && interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+                       || interface->bInterfaceSubClass != 0
+                       || interface->bInterfaceProtocol != 0
+                       || interface->bNumEndpoints != 2
+                       ) {
+               dbg ("Bogus camera interface info");
+               return NULL;
+       }
+
+
+       /* select "subminor" number (part of a minor number) */
+       down (&state_table_mutex);
+       for (i = 0; i < MAX_CAMERAS; i++) {
+               if (!minor_data [i])
+                       break;
+       }
+       if (i >= MAX_CAMERAS) {
+               info ("Ignoring additional USB Camera");
+               goto bye;
+       }
+
+       /* allocate & init camera state */
+       camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL);
+       if (!camera) {
+               err ("no memory!");
+               goto bye;
+       }
+
+       init_MUTEX (&camera->sem);
+       camera->info = camera_info;
+       camera->subminor = i;
+       camera->buf = NULL;
+       init_waitqueue_head (&camera->wait);
+
+
+       /* get input and output endpoints (either order) */
+       endpoint = interface->endpoint;
+       camera->outEP = camera->inEP =  -1;
+
+       ep = endpoint [0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       direction = endpoint [0].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+       if (direction == USB_DIR_IN)
+               camera->inEP = ep;
+       else
+               camera->outEP = ep;
+
+       ep = endpoint [1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       direction = endpoint [1].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+       if (direction == USB_DIR_IN)
+               camera->inEP = ep;
+       else
+               camera->outEP = ep;
+
+       if (camera->outEP == -1 || camera->inEP == -1
+                       || endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK
+                       || endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK
+                       ) {
+               dbg ("Bogus endpoints");
+               goto error;
+       }
+
+       info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor,
+               USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor);
+
+       camera->dev = dev;
+       usb_inc_dev_use (dev);
+
+       /* If we have devfs, register the device */
+       sprintf(name, "dc2xx%d", camera->subminor);
+       camera->devfs = devfs_register(usb_devfs_handle, name,
+                                      DEVFS_FL_DEFAULT, USB_MAJOR,
+                                      USB_CAMERA_MINOR_BASE + camera->subminor,
+                                      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+                                      S_IWGRP, &usb_camera_fops, NULL);
+
+       goto bye;
+
+error:
+       minor_data [camera->subminor] = NULL;
+       kfree (camera);
+       camera = NULL;
+bye:
+       up (&state_table_mutex);
+       return camera;
+}
+
+static void camera_disconnect(struct usb_device *dev, void *ptr)
+{
+       struct camera_state     *camera = (struct camera_state *) ptr;
+       int                     subminor = camera->subminor;
+
+       down (&state_table_mutex);
+       down (&camera->sem);
+
+       devfs_unregister(camera->devfs); 
+
+       /* If camera's not opened, we can clean up right away.
+        * Else apps see a disconnect on next I/O; the release cleans.
+        */
+       if (!camera->buf) {
+               minor_data [subminor] = NULL;
+               kfree (camera);
+               camera = NULL;
+       } else
+               camera->dev = NULL;
+
+       info ("USB Camera #%d disconnected", subminor);
+       usb_dec_dev_use (dev);
+
+       if (camera != NULL)
+               up (&camera->sem);
+       up (&state_table_mutex);
+}
+
+static /* const */ struct usb_driver camera_driver = {
+       name:           "dc2xx",
+
+       id_table:       camera_table,
+       probe:          camera_probe,
+       disconnect:     camera_disconnect,
+
+       fops:           &usb_camera_fops,
+       minor:          USB_CAMERA_MINOR_BASE
+};
+
+
+int __init usb_dc2xx_init(void)
+{
+       if (usb_register (&camera_driver) < 0)
+               return -1;
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+       return 0;
+}
+
+void __exit usb_dc2xx_cleanup(void)
+{
+       usb_deregister (&camera_driver);
+}
+
+module_init (usb_dc2xx_init);
+module_exit (usb_dc2xx_cleanup);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c
new file mode 100644 (file)
index 0000000..4cbf59a
--- /dev/null
@@ -0,0 +1,598 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <asm/atomic.h>
+#include <linux/blk.h>
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#include "../../scsi/sd.h"
+
+#include "hpusbscsi.h"
+
+#define DEBUG(x...) \
+       printk( KERN_DEBUG x )
+
+static char *states[]={"FREE", "BEGINNING", "WORKING", "ERROR", "WAIT", "PREMATURE"};
+
+#define TRACE_STATE printk(KERN_DEBUG"hpusbscsi->state = %s at line %d\n", states[hpusbscsi->state], __LINE__)
+
+/* global variables */
+
+struct list_head hpusbscsi_devices;
+//LIST_HEAD(hpusbscsi_devices);
+
+/* USB related parts */
+
+static void *
+hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
+                    const struct usb_device_id *id)
+{
+       struct hpusbscsi *new;
+       struct usb_interface_descriptor *altsetting =
+               &(dev->actconfig->interface[interface].altsetting[0]);
+
+       int i, result;
+
+       /* basic check */
+
+       if (altsetting->bNumEndpoints != 3) {
+               printk (KERN_ERR "Wrong number of endpoints\n");
+               return NULL;
+       }
+
+       /* descriptor allocation */
+
+       new =
+               (struct hpusbscsi *) kmalloc (sizeof (struct hpusbscsi),
+                                             GFP_KERNEL);
+       if (new == NULL)
+               return NULL;
+       DEBUG ("Allocated memory\n");
+       memset (new, 0, sizeof (struct hpusbscsi));
+       new->dataurb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!new->dataurb) {
+               kfree (new);
+               return NULL;
+       }
+       new->controlurb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!new->controlurb) {
+               usb_free_urb (new->dataurb);
+               kfree (new);
+               return NULL;
+       }
+       new->dev = dev;
+       init_waitqueue_head (&new->pending);
+       init_waitqueue_head (&new->deathrow);
+       INIT_LIST_HEAD (&new->lh);
+
+
+
+       /* finding endpoints */
+
+       for (i = 0; i < altsetting->bNumEndpoints; i++) {
+               if (
+                   (altsetting->endpoint[i].
+                    bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                   USB_ENDPOINT_XFER_BULK) {
+                       if (altsetting->endpoint[i].
+                           bEndpointAddress & USB_DIR_IN) {
+                               new->ep_in =
+                                       altsetting->endpoint[i].
+                                       bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       } else {
+                               new->ep_out =
+                                       altsetting->endpoint[i].
+                                       bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       }
+               } else {
+                       new->ep_int =
+                               altsetting->endpoint[i].
+                               bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+                       new->interrupt_interval= altsetting->endpoint[i].bInterval;
+               }
+       }
+
+       /* USB initialisation magic for the simple case */
+
+       result = usb_set_interface (dev, altsetting->bInterfaceNumber, 0);
+
+       switch (result) {
+       case 0:         /* no error */
+               break;
+
+       case -EPIPE:
+               usb_clear_halt (dev, usb_sndctrlpipe (dev, 0));
+               break;
+
+       default:
+               printk (KERN_ERR "unknown error %d from usb_set_interface\n",
+                        result);
+               goto err_out;
+       }
+
+       /* making a template for the scsi layer to fake detection of a scsi device */
+
+       memcpy (&(new->ctempl), &hpusbscsi_scsi_host_template,
+               sizeof (hpusbscsi_scsi_host_template));
+       (struct hpusbscsi *) new->ctempl.proc_dir = new;
+       new->ctempl.module = THIS_MODULE;
+
+       if (scsi_register_host(&new->ctempl))
+               goto err_out;
+
+       new->sense_command[0] = REQUEST_SENSE;
+       new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
+
+       /* adding to list for module unload */
+       list_add (&hpusbscsi_devices, &new->lh);
+
+       return new;
+
+      err_out:
+       usb_free_urb (new->controlurb);
+       usb_free_urb (new->dataurb);
+       kfree (new);
+       return NULL;
+}
+
+static void
+hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
+{
+                 usb_unlink_urb((((struct hpusbscsi *) ptr)->controlurb));
+       ((struct hpusbscsi *) ptr)->dev = NULL;
+}
+
+static struct usb_device_id hpusbscsi_usb_ids[] = {
+       {USB_DEVICE (0x03f0, 0x0701)},  /* HP 53xx */
+       {USB_DEVICE (0x03f0, 0x0801)},  /* HP 7400 */
+       {USB_DEVICE (0x0638, 0x026a)},  /*Scan Dual II */
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hpusbscsi_usb_ids);
+MODULE_LICENSE("GPL");
+
+
+static struct usb_driver hpusbscsi_usb_driver = {
+       name:"hpusbscsi",
+       probe:hpusbscsi_usb_probe,
+       disconnect:hpusbscsi_usb_disconnect,
+       id_table:hpusbscsi_usb_ids,
+};
+
+/* module initialisation */
+
+int __init
+hpusbscsi_init (void)
+{
+       int result;
+
+       INIT_LIST_HEAD (&hpusbscsi_devices);
+       DEBUG ("Driver loaded\n");
+
+       if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) {
+               printk (KERN_ERR "hpusbscsi: driver registration failed\n");
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+void __exit
+hpusbscsi_exit (void)
+{
+       struct list_head *tmp;
+       struct list_head *old;
+       struct hpusbscsi * o;
+
+       for (tmp = hpusbscsi_devices.next; tmp != &hpusbscsi_devices;/*nothing */) {
+               old = tmp;
+               tmp = tmp->next;
+               o = (struct hpusbscsi *)old;
+               usb_unlink_urb(o->controlurb);
+               scsi_unregister_host(&o->ctempl);
+               usb_free_urb(o->controlurb);
+               usb_free_urb(o->dataurb);
+               kfree(old);
+       }
+
+       usb_deregister (&hpusbscsi_usb_driver);
+}
+
+module_init (hpusbscsi_init);
+module_exit (hpusbscsi_exit);
+
+/* interface to the scsi layer */
+
+static int
+hpusbscsi_scsi_detect (struct SHT *sht)
+{
+       /* Whole function stolen from usb-storage */
+
+       struct hpusbscsi *desc = (struct hpusbscsi *) sht->proc_dir;
+       /* What a hideous hack! */
+
+       char local_name[48];
+
+
+       /* set up the name of our subdirectory under /proc/scsi/ */
+       sprintf (local_name, "hpusbscsi-%d", desc->number);
+       sht->proc_name = kmalloc (strlen (local_name) + 1, GFP_KERNEL);
+       /* FIXME: where is this freed ? */
+
+       if (!sht->proc_name) {
+               return 0;
+       }
+
+       strcpy (sht->proc_name, local_name);
+
+       sht->proc_dir = NULL;
+
+       /* build and submit an interrupt URB for status byte handling */
+       FILL_INT_URB(desc->controlurb,
+                       desc->dev,
+                       usb_rcvintpipe(desc->dev,desc->ep_int),
+                       &desc->scsi_state_byte,
+                       1,
+                       control_interrupt_callback,
+                       desc,
+                       desc->interrupt_interval
+       );
+
+       if ( 0  >  usb_submit_urb(desc->controlurb, GFP_KERNEL)) {
+               kfree(sht->proc_name);
+               return 0;
+       }
+
+       /* In host->hostdata we store a pointer to desc */
+       desc->host = scsi_register (sht, sizeof (desc));
+       if (desc->host == NULL) {
+               kfree (sht->proc_name);
+               usb_unlink_urb(desc->controlurb);
+               return 0;
+       }
+       desc->host->hostdata[0] = (unsigned long) desc;
+
+
+       return 1;
+}
+
+static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
+{
+       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
+       usb_urb_callback usb_callback;
+       int res;
+
+       hpusbscsi->use_count++;
+
+       /* we don't answer for anything but our single device on any faked host controller */
+       if ( srb->device->lun || srb->device->id || srb->device->channel ) {
+               if (callback) {
+                       srb->result = DID_BAD_TARGET;
+                       callback(srb);
+               }
+                       goto out;
+       }
+
+       /* Now we need to decide which callback to give to the urb we send the command with */
+
+       if (!srb->bufflen) {
+               if (srb->cmnd[0] == REQUEST_SENSE){
+                       hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
+                       usb_callback = request_sense_callback;
+               } else {
+                       usb_callback = simple_command_callback;
+               }
+       } else {
+               if (likely(srb->use_sg)) {
+                       usb_callback = scatter_gather_callback;
+                       hpusbscsi->fragment = 0;
+               } else {
+                       usb_callback = simple_payload_callback;
+               }
+               /* Now we find out which direction data is to be transfered in */
+               hpusbscsi->current_data_pipe = DIRECTION_IS_IN(srb->cmnd[0]) ?
+                       usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in)
+               :
+                       usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out)
+               ;
+       }
+
+
+       TRACE_STATE;
+
+        /* We zero the sense buffer to avoid confusing user space */
+        memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+
+       hpusbscsi->state = HP_STATE_BEGINNING;
+       TRACE_STATE;
+
+       /* We prepare the urb for writing out the scsi command */
+       FILL_BULK_URB(
+               hpusbscsi->dataurb,
+               hpusbscsi->dev,
+               usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
+               srb->cmnd,
+               srb->cmd_len,
+               usb_callback,
+               hpusbscsi
+       );
+       hpusbscsi->scallback = callback;
+       hpusbscsi->srb = srb;
+
+       res = usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC);
+       if (unlikely(res)) {
+               hpusbscsi->state = HP_STATE_FREE;
+               TRACE_STATE;
+               if (likely(callback != NULL)) {
+                       srb->result = DID_ERROR;
+                       callback(srb);
+               }
+       }
+
+out:
+       hpusbscsi->use_count--;
+       return 0;
+}
+
+static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb)
+{
+       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
+
+       printk(KERN_DEBUG"SCSI reset requested.\n");
+       //usb_reset_device(hpusbscsi->dev);
+       //printk(KERN_DEBUG"SCSI reset completed.\n");
+       hpusbscsi->state = HP_STATE_FREE;
+
+       return 0;
+}
+
+static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
+{
+       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
+       printk(KERN_DEBUG"Requested is canceled.\n");
+
+       usb_unlink_urb(hpusbscsi->dataurb);
+       usb_unlink_urb(hpusbscsi->controlurb);
+       hpusbscsi->state = HP_STATE_FREE;
+
+       return SCSI_ABORT_PENDING;
+}
+
+/* usb interrupt handlers - they are all running IN INTERRUPT ! */
+
+static void handle_usb_error (struct hpusbscsi *hpusbscsi)
+{
+       if (likely(hpusbscsi->scallback != NULL)) {
+               hpusbscsi->srb->result = DID_ERROR;
+               hpusbscsi->scallback(hpusbscsi->srb);
+       }
+       hpusbscsi->state = HP_STATE_FREE;
+}
+
+static void  control_interrupt_callback (struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+       u8 scsi_state;
+
+DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
+       if(unlikely(u->status < 0)) {
+                if (likely(hpusbscsi->state != HP_STATE_FREE))
+                        handle_usb_error(hpusbscsi);
+               return;
+       }
+
+       scsi_state = hpusbscsi->scsi_state_byte;
+       if (hpusbscsi->state != HP_STATE_ERROR) {
+               hpusbscsi->srb->result &= SCSI_ERR_MASK;
+               hpusbscsi->srb->result |= scsi_state;
+       }
+
+       if (scsi_state == CHECK_CONDITION << 1) {
+               if (hpusbscsi->state == HP_STATE_WAIT) {
+                       issue_request_sense(hpusbscsi);
+               } else {
+                       /* we request sense after an eventual data transfer */
+                       hpusbscsi->state = HP_STATE_ERROR;
+               }
+       }
+
+       if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1 )
+               /* we do a callback to the scsi layer if and only if all data has been transfered */
+               hpusbscsi->scallback(hpusbscsi->srb);
+
+       TRACE_STATE;
+       switch (hpusbscsi->state) {
+       case HP_STATE_WAIT:
+               hpusbscsi->state = HP_STATE_FREE;
+       TRACE_STATE;
+               break;
+       case HP_STATE_WORKING:
+       case HP_STATE_BEGINNING:
+               hpusbscsi->state = HP_STATE_PREMATURE;
+       TRACE_STATE;
+               break;
+       case HP_STATE_ERROR:
+               break;
+       default:
+               printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
+       TRACE_STATE;
+               hpusbscsi->state = HP_STATE_FREE;
+       TRACE_STATE;
+               break;
+       }
+}
+
+static void simple_command_callback(struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+       if (unlikely(u->status<0)) {
+               handle_usb_error(hpusbscsi);
+               return;
+        }
+       TRACE_STATE;
+       if (hpusbscsi->state != HP_STATE_PREMATURE) {
+               TRACE_STATE;
+               hpusbscsi->state = HP_STATE_WAIT;
+       } else {
+               if (likely(hpusbscsi->scallback != NULL))
+                       hpusbscsi->scallback(hpusbscsi->srb);
+               hpusbscsi->state = HP_STATE_FREE;
+       TRACE_STATE;
+       }
+}
+
+static void scatter_gather_callback(struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+        struct scatterlist *sg = hpusbscsi->srb->buffer;
+        usb_urb_callback callback;
+        int res;
+
+        DEBUG("Going through scatter/gather\n");
+        if (unlikely(u->status < 0)) {
+                handle_usb_error(hpusbscsi);
+                return;
+        }
+
+        if (hpusbscsi->fragment + 1 != hpusbscsi->srb->use_sg)
+                callback = scatter_gather_callback;
+        else
+                callback = simple_done;
+
+       TRACE_STATE;
+        if (hpusbscsi->state != HP_STATE_PREMATURE)
+               hpusbscsi->state = HP_STATE_WORKING;
+       TRACE_STATE;
+
+        FILL_BULK_URB(
+                u,
+                hpusbscsi->dev,
+                hpusbscsi->current_data_pipe,
+                page_address(sg[hpusbscsi->fragment].page) +
+               sg[hpusbscsi->fragment].offset,
+                sg[hpusbscsi->fragment++].length,
+                callback,
+                hpusbscsi
+        );
+
+        res = usb_submit_urb(u, GFP_ATOMIC);
+        if (unlikely(res))
+                handle_usb_error(hpusbscsi);
+       TRACE_STATE;
+}
+
+static void simple_done (struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+
+        if (unlikely(u->status < 0)) {
+                handle_usb_error(hpusbscsi);
+                return;
+        }
+        DEBUG("Data transfer done\n");
+       TRACE_STATE;
+       if (hpusbscsi->state != HP_STATE_PREMATURE) {
+               if (unlikely(u->status < 0)) {
+                       handle_usb_error(hpusbscsi);
+               } else {
+                       if (hpusbscsi->state != HP_STATE_ERROR) {
+                               hpusbscsi->state = HP_STATE_WAIT;
+                       } else {
+                               issue_request_sense(hpusbscsi);
+                       }                       
+               }
+       } else {
+               if (likely(hpusbscsi->scallback != NULL))
+                       hpusbscsi->scallback(hpusbscsi->srb);
+               hpusbscsi->state = HP_STATE_FREE;
+       }
+}
+
+static void simple_payload_callback (struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+       int res;
+
+       if (unlikely(u->status<0)) {
+                handle_usb_error(hpusbscsi);
+               return;
+        }
+
+       FILL_BULK_URB(
+               u,
+               hpusbscsi->dev,
+               hpusbscsi->current_data_pipe,
+               hpusbscsi->srb->buffer,
+               hpusbscsi->srb->bufflen,
+               simple_done,
+               hpusbscsi
+       );
+
+       res = usb_submit_urb(u, GFP_ATOMIC);
+       if (unlikely(res)) {
+                handle_usb_error(hpusbscsi);
+               return;
+        }
+       TRACE_STATE;
+       if (hpusbscsi->state != HP_STATE_PREMATURE) {
+               hpusbscsi->state = HP_STATE_WORKING;
+       TRACE_STATE;
+       } 
+}
+
+static void request_sense_callback (struct urb *u)
+{
+       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+
+       if (u->status<0) {
+                handle_usb_error(hpusbscsi);
+               return;
+        }
+
+       FILL_BULK_URB(
+               u,
+               hpusbscsi->dev,
+               hpusbscsi->current_data_pipe,
+               hpusbscsi->srb->sense_buffer,
+               SCSI_SENSE_BUFFERSIZE,
+               simple_done,
+               hpusbscsi
+       );
+
+       if (0 > usb_submit_urb(u, GFP_ATOMIC)) {
+               handle_usb_error(hpusbscsi);
+               return;
+       }
+       if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR)
+               hpusbscsi->state = HP_STATE_WORKING;
+}
+
+static void issue_request_sense (struct hpusbscsi *hpusbscsi)
+{
+       FILL_BULK_URB(
+               hpusbscsi->dataurb,
+               hpusbscsi->dev,
+               usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out),
+               &hpusbscsi->sense_command,
+               SENSE_COMMAND_SIZE,
+               request_sense_callback,
+               hpusbscsi
+       );
+
+       hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
+
+       if (0 > usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC)) {
+               handle_usb_error(hpusbscsi);
+       }
+}
+
diff --git a/drivers/usb/image/hpusbscsi.h b/drivers/usb/image/hpusbscsi.h
new file mode 100644 (file)
index 0000000..87d1d7e
--- /dev/null
@@ -0,0 +1,96 @@
+/* Header file for the hpusbscsi driver */
+/* (C) Copyright 2001 Oliver Neukum */
+/* sponsored by the Linux Usb Project */
+/* large parts based on or taken from code by John Fremlin and Matt Dharm */
+/* this file is licensed under the GPL */
+
+/* A big thanks to Jose for untiring testing */
+
+typedef void (*usb_urb_callback) (struct urb *);
+typedef void (*scsi_callback)(Scsi_Cmnd *);
+
+#define SENSE_COMMAND_SIZE 6
+#define HPUSBSCSI_SENSE_LENGTH 0x16
+
+struct hpusbscsi
+{
+        struct list_head lh;
+        struct usb_device *dev; /* NULL indicates unplugged device */
+        int ep_out;
+        int ep_in;
+        int ep_int;
+        int interrupt_interval;
+
+        struct Scsi_Host *host;
+        Scsi_Host_Template ctempl;
+        int number;
+       scsi_callback scallback;
+       Scsi_Cmnd *srb;
+       u8 sense_command[SENSE_COMMAND_SIZE];
+
+        int use_count;
+        wait_queue_head_t pending;
+        wait_queue_head_t deathrow;
+
+        struct urb *dataurb;
+        struct urb *controlurb;
+        int fragment;
+
+        int state;
+        int current_data_pipe;
+
+        u8 scsi_state_byte;
+};
+
+#define SCSI_ERR_MASK ~0x3fu
+
+static const unsigned char scsi_command_direction[256/8] = {
+       0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+       0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define DIRECTION_IS_IN(x) ((scsi_command_direction[x>>3] >> (x & 7)) & 1)
+
+static int hpusbscsi_scsi_detect (struct SHT * sht);
+static void simple_command_callback(struct urb *u);
+static void scatter_gather_callback(struct urb *u);
+static void simple_payload_callback (struct urb *u);
+static void request_sense_callback (struct urb *u);
+static void control_interrupt_callback (struct urb *u);
+static void simple_done (struct urb *u);
+static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
+static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
+static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
+static void issue_request_sense (struct hpusbscsi *hpusbscsi);
+
+static Scsi_Host_Template hpusbscsi_scsi_host_template = {
+       name:           "hpusbscsi",
+       detect:         hpusbscsi_scsi_detect,
+//     release:        hpusbscsi_scsi_release,
+       queuecommand:   hpusbscsi_scsi_queuecommand,
+
+       eh_abort_handler:       hpusbscsi_scsi_abort,
+       eh_host_reset_handler:  hpusbscsi_scsi_host_reset,
+
+       sg_tablesize:           SG_ALL,
+       can_queue:              1,
+       this_id:                -1,
+       cmd_per_lun:            1,
+       present:                0,
+       unchecked_isa_dma:      FALSE,
+       use_clustering:         TRUE,
+       emulated:               TRUE
+};
+
+/* defines for internal driver state */
+#define HP_STATE_FREE                 0  /*ready for next request */
+#define HP_STATE_BEGINNING      1  /*command being transfered */
+#define HP_STATE_WORKING         2  /* data transfer stage */
+#define HP_STATE_ERROR             3  /* error has been reported */
+#define HP_STATE_WAIT                 4  /* waiting for status transfer */
+#define HP_STATE_PREMATURE              5 /* status prematurely reported */
+
+
+
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
new file mode 100644 (file)
index 0000000..d06d72c
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * copyright (C) 1999/2000 by Henning Zabel <henning@uni-paderborn.de>
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ *     USB-Kernel Driver for the Mustek MDC800 Digital Camera
+ *     (c) 1999/2000 Henning Zabel <henning@uni-paderborn.de>
+ *
+ *
+ * The driver brings the USB functions of the MDC800 to Linux.
+ * To use the Camera you must support the USB Protocoll of the camera
+ * to the Kernel Node.
+ * The Driver uses a misc device Node. Create it with :
+ * mknod /dev/mustek c 180 32
+ *
+ * The driver supports only one camera.
+ * 
+ * Fix: mdc800 used sleep_on and slept with io_lock held.
+ * Converted sleep_on to waitqueues with schedule_timeout and made io_lock
+ * a semaphore from a spinlock.
+ * by Oliver Neukum <520047054719-0001@t-online.de>
+ * (02/12/2001)
+ * 
+ * Identify version on module load.
+ * (08/04/2001) gb
+ *
+ * version 0.7.5
+ * Fixed potential SMP races with Spinlocks.
+ * Thanks to Oliver Neukum <oliver.neukum@lrz.uni-muenchen.de> who 
+ * noticed the race conditions.
+ * (30/10/2000)
+ *
+ * Fixed: Setting urb->dev before submitting urb.
+ * by Greg KH <greg@kroah.com>
+ * (13/10/2000)
+ *
+ * version 0.7.3
+ * bugfix : The mdc800->state field gets set to READY after the
+ * the diconnect function sets it to NOT_CONNECTED. This makes the
+ * driver running like the camera is connected and causes some
+ * hang ups.
+ *
+ * version 0.7.1
+ * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
+ * problems when compiled as Module.
+ * (04/04/2000)
+ *
+ * The mdc800 driver gets assigned the USB Minor 32-47. The Registration
+ * was updated to use these values.
+ * (26/03/2000)
+ *
+ * The Init und Exit Module Function are updated.
+ * (01/03/2000)
+ *
+ * version 0.7.0
+ * Rewrite of the driver : The driver now uses URB's. The old stuff
+ * has been removed.
+ *
+ * version 0.6.0
+ * Rewrite of this driver: The Emulation of the rs232 protocoll
+ * has been removed from the driver. A special executeCommand function
+ * for this driver is included to gphoto.
+ * The driver supports two kind of communication to bulk endpoints.
+ * Either with the dev->bus->ops->bulk... or with callback function.
+ * (09/11/1999)
+ *
+ * version 0.5.0:
+ * first Version that gets a version number. Most of the needed
+ * functions work.
+ * (20/10/1999)
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+
+#include <linux/usb.h>
+#include <linux/fs.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.7.5 (30/10/2000)"
+#define DRIVER_AUTHOR "Henning Zabel <henning@uni-paderborn.de>"
+#define DRIVER_DESC "USB Driver for Mustek MDC800 Digital Camera"
+
+/* Vendor and Product Information */
+#define MDC800_VENDOR_ID       0x055f
+#define MDC800_PRODUCT_ID      0xa800
+
+/* Timeouts (msec) */
+#define TO_DOWNLOAD_GET_READY          1500
+#define TO_DOWNLOAD_GET_BUSY           1500
+#define TO_WRITE_GET_READY             1000
+#define TO_DEFAULT_COMMAND             5000
+#define TO_READ_FROM_IRQ               TO_DEFAULT_COMMAND
+#define TO_GET_READY                   TO_DEFAULT_COMMAND
+
+/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
+#define MDC800_DEVICE_MINOR_BASE 32
+
+
+/**************************************************************************
+       Data and structs
+***************************************************************************/
+
+
+typedef enum {
+       NOT_CONNECTED, READY, WORKING, DOWNLOAD
+} mdc800_state;
+
+
+/* Data for the driver */
+struct mdc800_data
+{
+       struct usb_device *     dev;                    // Device Data
+       mdc800_state            state;
+
+       unsigned int            endpoint [4];
+
+       struct urb *            irq_urb;
+       wait_queue_head_t       irq_wait;
+       int                     irq_woken;
+       char*                   irq_urb_buffer;
+
+       int                     camera_busy;          // is camera busy ?
+       int                     camera_request_ready; // Status to synchronize with irq
+       char                    camera_response [8];  // last Bytes send after busy
+
+       struct urb *            write_urb;
+       char*                   write_urb_buffer;
+       wait_queue_head_t       write_wait;
+       int                     written;
+
+
+       struct urb *            download_urb;
+       char*                   download_urb_buffer;
+       wait_queue_head_t       download_wait;
+       int                     downloaded;
+       int                     download_left;          // Bytes left to download ?
+
+
+       /* Device Data */
+       char                    out [64];       // Answer Buffer
+       int                     out_ptr;        // Index to the first not readen byte
+       int                     out_count;      // Bytes in the buffer
+
+       int                     open;           // Camera device open ?
+       struct semaphore        io_lock;        // IO -lock
+
+       char                    in [8];         // Command Input Buffer
+       int                     in_count;
+
+       int                     pic_index;      // Cache for the Imagesize (-1 for nothing cached )
+       int                     pic_len;
+};
+
+
+/* Specification of the Endpoints */
+static struct usb_endpoint_descriptor mdc800_ed [4] =
+{
+       { 0,0, 0x01, 0x02,  8, 0,0,0 },
+       { 0,0, 0x82, 0x03,  8, 0,0,0 },
+       { 0,0, 0x03, 0x02, 64, 0,0,0 },
+       { 0,0, 0x84, 0x02, 64, 0,0,0 }
+};
+
+
+/* The Variable used by the driver */
+static struct mdc800_data* mdc800=0;
+
+
+/***************************************************************************
+       The USB Part of the driver
+****************************************************************************/
+
+static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b)
+{
+       return (
+                  ( a->bEndpointAddress == b->bEndpointAddress )
+               && ( a->bmAttributes     == b->bmAttributes     )
+               && ( a->wMaxPacketSize   == b->wMaxPacketSize   )
+       );
+}
+
+
+/*
+ * Checks wether the camera responds busy
+ */
+static int mdc800_isBusy (char* ch)
+{
+       int i=0;
+       while (i<8)
+       {
+               if (ch [i] != (char)0x99)
+                       return 0;
+               i++;
+       }
+       return 1;
+}
+
+
+/*
+ * Checks wether the Camera is ready
+ */
+static int mdc800_isReady (char *ch)
+{
+       int i=0;
+       while (i<8)
+       {
+               if (ch [i] != (char)0xbb)
+                       return 0;
+               i++;
+       }
+       return 1;
+}
+
+
+
+/*
+ * USB IRQ Handler for InputLine
+ */
+static void mdc800_usb_irq (struct urb *urb)
+{
+       int data_received=0, wake_up;
+       unsigned char* b=urb->transfer_buffer;
+       struct mdc800_data* mdc800=urb->context;
+
+       if (urb->status >= 0)
+       {
+
+               //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+               if (mdc800_isBusy (b))
+               {
+                       if (!mdc800->camera_busy)
+                       {
+                               mdc800->camera_busy=1;
+                               dbg ("gets busy");
+                       }
+               }
+               else
+               {
+                       if (mdc800->camera_busy && mdc800_isReady (b))
+                       {
+                               mdc800->camera_busy=0;
+                               dbg ("gets ready");
+                       }
+               }
+               if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
+               {
+                       /* Store Data in camera_answer field */
+                       dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+                       memcpy (mdc800->camera_response,b,8);
+                       data_received=1;
+               }
+       }
+       wake_up= ( mdc800->camera_request_ready > 0 )
+               &&
+               (
+                       ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy))
+               ||
+                       ((mdc800->camera_request_ready == 2) && data_received)
+               ||
+                       ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
+               ||
+                       (urb->status < 0)
+               );
+
+       if (wake_up)
+       {
+               mdc800->camera_request_ready=0;
+               mdc800->irq_woken=1;
+               wake_up_interruptible (&mdc800->irq_wait);
+       }
+}
+
+
+/*
+ * Waits a while until the irq responds that camera is ready
+ *
+ *  mode : 0: Wait for camera gets ready
+ *         1: Wait for receiving data
+ *         2: Wait for camera gets busy
+ *
+ * msec: Time to wait
+ */
+static int mdc800_usb_waitForIRQ (int mode, int msec)
+{
+        DECLARE_WAITQUEUE(wait, current);
+
+       mdc800->camera_request_ready=1+mode;
+
+       add_wait_queue(&mdc800->irq_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       if (!mdc800->irq_woken)
+       {
+               schedule_timeout (msec*HZ/1000);
+       }
+        remove_wait_queue(&mdc800->irq_wait, &wait);
+       set_current_state(TASK_RUNNING);
+       mdc800->irq_woken = 0;
+
+       if (mdc800->camera_request_ready>0)
+       {
+               mdc800->camera_request_ready=0;
+               err ("timeout waiting for camera.");
+               return -1;
+       }
+       
+       if (mdc800->state == NOT_CONNECTED)
+       {
+               warn ("Camera gets disconnected during waiting for irq.");
+               mdc800->camera_request_ready=0;
+               return -2;
+       }
+       
+       return 0;
+}
+
+
+/*
+ * The write_urb callback function
+ */
+static void mdc800_usb_write_notify (struct urb *urb)
+{
+       struct mdc800_data* mdc800=urb->context;
+
+       if (urb->status != 0)
+       {
+               err ("writing command fails (status=%i)", urb->status);
+       }
+       else
+       {       
+               mdc800->state=READY;
+       }
+       mdc800->written = 1;
+       wake_up_interruptible (&mdc800->write_wait);
+}
+
+
+/*
+ * The download_urb callback function
+ */
+static void mdc800_usb_download_notify (struct urb *urb)
+{
+       struct mdc800_data* mdc800=urb->context;
+
+       if (urb->status == 0)
+       {
+               /* Fill output buffer with these data */
+               memcpy (mdc800->out,  urb->transfer_buffer, 64);
+               mdc800->out_count=64;
+               mdc800->out_ptr=0;
+               mdc800->download_left-=64;
+               if (mdc800->download_left == 0)
+               {
+                       mdc800->state=READY;
+               }
+       }
+       else
+       {
+               err ("request bytes fails (status:%i)", urb->status);
+       }
+       mdc800->downloaded = 1;
+       wake_up_interruptible (&mdc800->download_wait);
+}
+
+
+/***************************************************************************
+       Probing for the Camera
+ ***************************************************************************/
+
+static struct usb_driver mdc800_usb_driver;
+
+/*
+ * Callback to search the Mustek MDC800 on the USB Bus
+ */
+static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum,
+                              const struct usb_device_id *id)
+{
+       int i,j;
+       struct usb_interface_descriptor *intf_desc;
+       int irq_interval=0;
+
+       dbg ("(mdc800_usb_probe) called.");
+
+
+       if (mdc800->dev != 0)
+       {
+               warn ("only one Mustek MDC800 is supported.");
+               return 0;
+       }
+
+       if (dev->descriptor.bNumConfigurations != 1)
+       {
+               err ("probe fails -> wrong Number of Configuration");
+               return 0;
+       }
+       intf_desc=&dev->actconfig->interface[ifnum].altsetting[0];
+
+       if (
+                       ( intf_desc->bInterfaceClass != 0xff )
+               ||      ( intf_desc->bInterfaceSubClass != 0 )
+               || ( intf_desc->bInterfaceProtocol != 0 )
+               || ( intf_desc->bNumEndpoints != 4)
+       )
+       {
+               err ("probe fails -> wrong Interface");
+               return 0;
+       }
+
+       /* Check the Endpoints */
+       for (i=0; i<4; i++)
+       {
+               mdc800->endpoint[i]=-1;
+               for (j=0; j<4; j++)
+               {
+                       if (mdc800_endpoint_equals (&intf_desc->endpoint [j],&mdc800_ed [i]))
+                       {
+                               mdc800->endpoint[i]=intf_desc->endpoint [j].bEndpointAddress ;
+                               if (i==1)
+                               {
+                                       irq_interval=intf_desc->endpoint [j].bInterval;
+                               }
+
+                               continue;
+                       }
+               }
+               if (mdc800->endpoint[i] == -1)
+               {
+                       err ("probe fails -> Wrong Endpoints.");
+                       return 0;
+               }
+       }
+
+
+       usb_driver_claim_interface (&mdc800_usb_driver, &dev->actconfig->interface[ifnum], mdc800);
+       if (usb_set_interface (dev, ifnum, 0) < 0)
+       {
+               err ("MDC800 Configuration fails.");
+               return 0;
+       }
+
+       info ("Found Mustek MDC800 on USB.");
+
+       down (&mdc800->io_lock);
+
+       mdc800->dev=dev;
+       mdc800->open=0;
+
+       /* Setup URB Structs */
+       FILL_INT_URB (
+               mdc800->irq_urb,
+               mdc800->dev,
+               usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]),
+               mdc800->irq_urb_buffer,
+               8,
+               mdc800_usb_irq,
+               mdc800,
+               irq_interval
+       );
+
+       FILL_BULK_URB (
+               mdc800->write_urb,
+               mdc800->dev,
+               usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]),
+               mdc800->write_urb_buffer,
+               8,
+               mdc800_usb_write_notify,
+               mdc800
+       );
+
+       FILL_BULK_URB (
+               mdc800->download_urb,
+               mdc800->dev,
+               usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]),
+               mdc800->download_urb_buffer,
+               64,
+               mdc800_usb_download_notify,
+               mdc800
+       );
+
+       mdc800->state=READY;
+
+       up (&mdc800->io_lock);
+       
+       return mdc800;
+}
+
+
+/*
+ * Disconnect USB device (maybe the MDC800)
+ */
+static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
+{
+       struct mdc800_data* mdc800=(struct mdc800_data*) ptr;
+
+       dbg ("(mdc800_usb_disconnect) called");
+
+       if (mdc800->state == NOT_CONNECTED)
+               return;
+       
+       mdc800->state=NOT_CONNECTED;
+
+       usb_unlink_urb (mdc800->irq_urb);
+       usb_unlink_urb (mdc800->write_urb);
+       usb_unlink_urb (mdc800->download_urb);
+
+       usb_driver_release_interface (&mdc800_usb_driver, &dev->actconfig->interface[1]);
+
+       mdc800->dev=0;
+       info ("Mustek MDC800 disconnected from USB.");
+}
+
+
+/***************************************************************************
+       The Misc device Part (file_operations)
+****************************************************************************/
+
+/*
+ * This Function calc the Answersize for a command.
+ */
+static int mdc800_getAnswerSize (char command)
+{
+       switch ((unsigned char) command)
+       {
+               case 0x2a:
+               case 0x49:
+               case 0x51:
+               case 0x0d:
+               case 0x20:
+               case 0x07:
+               case 0x01:
+               case 0x25:
+               case 0x00:
+                       return 8;
+
+               case 0x05:
+               case 0x3e:
+                       return mdc800->pic_len;
+
+               case 0x09:
+                       return 4096;
+
+               default:
+                       return 0;
+       }
+}
+
+
+/*
+ * Init the device: (1) alloc mem (2) Increase MOD Count ..
+ */
+static int mdc800_device_open (struct inode* inode, struct file *file)
+{
+       int retval=0;
+       int errn=0;
+
+       down (&mdc800->io_lock);
+       
+       if (mdc800->state == NOT_CONNECTED)
+       {
+               errn=-EBUSY;
+               goto error_out;
+       }
+       if (mdc800->open)
+       {
+               errn=-EBUSY;
+               goto error_out;
+       }
+
+       mdc800->in_count=0;
+       mdc800->out_count=0;
+       mdc800->out_ptr=0;
+       mdc800->pic_index=0;
+       mdc800->pic_len=-1;
+       mdc800->download_left=0;
+
+       mdc800->camera_busy=0;
+       mdc800->camera_request_ready=0;
+
+       retval=0;
+       mdc800->irq_urb->dev = mdc800->dev;
+       if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
+       {
+               err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+               errn = -EIO;
+               goto error_out;
+       }
+
+       mdc800->open=1;
+       dbg ("Mustek MDC800 device opened.");
+
+error_out:
+       up (&mdc800->io_lock);
+       return errn;
+}
+
+
+/*
+ * Close the Camera and release Memory
+ */
+static int mdc800_device_release (struct inode* inode, struct file *file)
+{
+       int retval=0;
+       dbg ("Mustek MDC800 device closed.");
+
+       down (&mdc800->io_lock);
+       if (mdc800->open && (mdc800->state != NOT_CONNECTED))
+       {
+               usb_unlink_urb (mdc800->irq_urb);
+               usb_unlink_urb (mdc800->write_urb);
+               usb_unlink_urb (mdc800->download_urb);
+               mdc800->open=0;
+       }
+       else
+       {
+               retval=-EIO;
+       }
+
+       up(&mdc800->io_lock);
+       return retval;
+}
+
+
+/*
+ * The Device read callback Function
+ */
+static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
+{
+       int   left=len, sts=len; /* single transfer size */
+       char* ptr=buf;
+       DECLARE_WAITQUEUE(wait, current);
+
+       down (&mdc800->io_lock);
+       if (mdc800->state == NOT_CONNECTED)
+       {
+               up (&mdc800->io_lock);
+               return -EBUSY;
+       }
+       if (mdc800->state == WORKING)
+       {
+               warn ("Illegal State \"working\" reached during read ?!");
+               up (&mdc800->io_lock);
+               return -EBUSY;
+       }
+       if (!mdc800->open)
+       {
+               up (&mdc800->io_lock);
+               return -EBUSY;
+       }
+
+       while (left)
+       {
+               if (signal_pending (current)) 
+               {
+                       up (&mdc800->io_lock);
+                       return -EINTR;
+               }
+
+               sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
+
+               if (sts <= 0)
+               {
+                       /* Too less Data in buffer */
+                       if (mdc800->state == DOWNLOAD)
+                       {
+                               mdc800->out_count=0;
+                               mdc800->out_ptr=0;
+
+                               /* Download -> Request new bytes */
+                               mdc800->download_urb->dev = mdc800->dev;
+                               if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
+                               {
+                                       err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+                                       up (&mdc800->io_lock);
+                                       return len-left;
+                               }
+                               add_wait_queue(&mdc800->download_wait, &wait);
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               if (!mdc800->downloaded)
+                               {
+                                       schedule_timeout (TO_DOWNLOAD_GET_READY*HZ/1000);
+                               }
+                               set_current_state(TASK_RUNNING);
+                               remove_wait_queue(&mdc800->download_wait, &wait);
+                               mdc800->downloaded = 0;
+                               if (mdc800->download_urb->status != 0)
+                               {
+                                       err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
+                                       up (&mdc800->io_lock);
+                                       return len-left;
+                               }
+                       }
+                       else
+                       {
+                               /* No more bytes -> that's an error*/
+                               up (&mdc800->io_lock);
+                               return -EIO;
+                       }
+               }
+               else
+               {
+                       /* memcpy Bytes */
+                       memcpy (ptr, &mdc800->out [mdc800->out_ptr], sts);
+                       ptr+=sts;
+                       left-=sts;
+                       mdc800->out_ptr+=sts;
+               }
+       }
+
+       up (&mdc800->io_lock);
+       return len-left;
+}
+
+
+/*
+ * The Device write callback Function
+ * If a 8Byte Command is received, it will be send to the camera.
+ * After this the driver initiates the request for the answer or
+ * just waits until the camera becomes ready.
+ */
+static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
+{
+       int i=0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       down (&mdc800->io_lock);
+       if (mdc800->state != READY)
+       {
+               up (&mdc800->io_lock);
+               return -EBUSY;
+       }
+       if (!mdc800->open )
+       {
+               up (&mdc800->io_lock);
+               return -EBUSY;
+       }
+
+       while (i<len)
+       {
+               if (signal_pending (current)) 
+               {
+                       up (&mdc800->io_lock);
+                       return -EINTR;
+               }
+
+               /* check for command start */
+               if (buf [i] == (char) 0x55)
+               {
+                       mdc800->in_count=0;
+                       mdc800->out_count=0;
+                       mdc800->out_ptr=0;
+                       mdc800->download_left=0;
+               }
+
+               /* save command byte */
+               if (mdc800->in_count < 8)
+               {
+                       mdc800->in[mdc800->in_count]=buf[i];
+                       mdc800->in_count++;
+               }
+               else
+               {
+                       err ("Command is to long !\n");
+                       up (&mdc800->io_lock);
+                       return -EIO;
+               }
+
+               /* Command Buffer full ? -> send it to camera */
+               if (mdc800->in_count == 8)
+               {
+                       int answersize;
+
+                       if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
+                       {
+                               err ("Camera didn't get ready.\n");
+                               up (&mdc800->io_lock);
+                               return -EIO;
+                       }
+
+                       answersize=mdc800_getAnswerSize (mdc800->in[1]);
+
+                       mdc800->state=WORKING;
+                       memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
+                       mdc800->write_urb->dev = mdc800->dev;
+                       if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
+                       {
+                               err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+                               up (&mdc800->io_lock);
+                               return -EIO;
+                       }
+                       add_wait_queue(&mdc800->write_wait, &wait);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (!mdc800->written)
+                       {
+                               schedule_timeout (TO_WRITE_GET_READY*HZ/1000);
+                       }
+                        set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&mdc800->write_wait, &wait);
+                       mdc800->written = 0;
+                       if (mdc800->state == WORKING)
+                       {
+                               usb_unlink_urb (mdc800->write_urb);
+                               up (&mdc800->io_lock);
+                               return -EIO;
+                       }
+
+                       switch ((unsigned char) mdc800->in[1])
+                       {
+                               case 0x05: /* Download Image */
+                               case 0x3e: /* Take shot in Fine Mode (WCam Mode) */
+                                       if (mdc800->pic_len < 0)
+                                       {
+                                               err ("call 0x07 before 0x05,0x3e");
+                                               mdc800->state=READY;
+                                               up (&mdc800->io_lock);
+                                               return -EIO;
+                                       }
+                                       mdc800->pic_len=-1;
+
+                               case 0x09: /* Download Thumbnail */
+                                       mdc800->download_left=answersize+64;
+                                       mdc800->state=DOWNLOAD;
+                                       mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY);
+                                       break;
+
+
+                               default:
+                                       if (answersize)
+                                       {
+
+                                               if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
+                                               {
+                                                       err ("requesting answer from irq fails");
+                                                       up (&mdc800->io_lock);
+                                                       return -EIO;
+                                               }
+
+                                               /* Write dummy data, (this is ugly but part of the USB Protokoll */
+                                               /* if you use endpoint 1 as bulk and not as irq */
+                                               memcpy (mdc800->out, mdc800->camera_response,8);
+
+                                               /* This is the interpreted answer */
+                                               memcpy (&mdc800->out[8], mdc800->camera_response,8);
+
+                                               mdc800->out_ptr=0;
+                                               mdc800->out_count=16;
+
+                                               /* Cache the Imagesize, if command was getImageSize */
+                                               if (mdc800->in [1] == (char) 0x07)
+                                               {
+                                                       mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
+
+                                                       dbg ("cached imagesize = %i",mdc800->pic_len);
+                                               }
+
+                                       }
+                                       else
+                                       {
+                                               if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
+                                               {
+                                                       err ("Command Timeout.");
+                                                       up (&mdc800->io_lock);
+                                                       return -EIO;
+                                               }
+                                       }
+                                       mdc800->state=READY;
+                                       break;
+                       }
+               }
+               i++;
+       }
+       up (&mdc800->io_lock);
+       return i;
+}
+
+
+/***************************************************************************
+       Init and Cleanup this driver (Structs and types)
+****************************************************************************/
+
+/* File Operations of this drivers */
+static struct file_operations mdc800_device_ops =
+{
+       owner:          THIS_MODULE,
+       read:           mdc800_device_read,
+       write:          mdc800_device_write,
+       open:           mdc800_device_open,
+       release:        mdc800_device_release,
+};
+
+
+
+static struct usb_device_id mdc800_table [] = {
+       { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, mdc800_table);
+/*
+ * USB Driver Struct for this device
+ */
+static struct usb_driver mdc800_usb_driver =
+{
+       name:           "mdc800",
+       probe:          mdc800_usb_probe,
+       disconnect:     mdc800_usb_disconnect,
+       fops:           &mdc800_device_ops,
+       minor:          MDC800_DEVICE_MINOR_BASE,
+       id_table:       mdc800_table
+};
+
+
+
+/************************************************************************
+       Init and Cleanup this driver (Main Functions)
+*************************************************************************/
+
+#define try(A)           if ((A) == 0) goto cleanup_on_fail;
+#define try_free_mem(A)  if (A != 0) { kfree (A); A=0; }
+#define try_free_urb(A)  if (A != 0) { usb_free_urb (A); A=0; }
+
+int __init usb_mdc800_init (void)
+{
+       /* Allocate Memory */
+       try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
+
+       memset(mdc800, 0, sizeof(struct mdc800_data));
+       mdc800->dev=0;
+       mdc800->open=0;
+       mdc800->state=NOT_CONNECTED;
+       init_MUTEX (&mdc800->io_lock);
+
+       init_waitqueue_head (&mdc800->irq_wait);
+       init_waitqueue_head (&mdc800->write_wait);
+       init_waitqueue_head (&mdc800->download_wait);
+
+       mdc800->irq_woken = 0;
+       mdc800->downloaded = 0;
+       mdc800->written = 0;
+
+       try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
+       try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
+       try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL));
+
+       try (mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL));
+       try (mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL));
+       try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL));
+
+       /* Register the driver */
+       if (usb_register (&mdc800_usb_driver) < 0)
+               goto cleanup_on_fail;
+
+       info (DRIVER_VERSION ":" DRIVER_DESC);
+
+       return 0;
+
+       /* Clean driver up, when something fails */
+
+cleanup_on_fail:
+
+       if (mdc800 != 0)
+       {
+               err ("can't alloc memory!");
+
+               try_free_mem (mdc800->download_urb_buffer);
+               try_free_mem (mdc800->write_urb_buffer);
+               try_free_mem (mdc800->irq_urb_buffer);
+
+               try_free_urb (mdc800->write_urb);
+               try_free_urb (mdc800->download_urb);
+               try_free_urb (mdc800->irq_urb);
+
+               kfree (mdc800);
+       }
+       mdc800=0;
+       return -1;
+}
+
+
+void __exit usb_mdc800_cleanup (void)
+{
+       usb_deregister (&mdc800_usb_driver);
+
+       usb_free_urb (mdc800->irq_urb);
+       usb_free_urb (mdc800->download_urb);
+       usb_free_urb (mdc800->write_urb);
+
+       kfree (mdc800->irq_urb_buffer);
+       kfree (mdc800->write_urb_buffer);
+       kfree (mdc800->download_urb_buffer);
+
+       kfree (mdc800);
+       mdc800=0;
+}
+
+module_init (usb_mdc800_init);
+module_exit (usb_mdc800_cleanup);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
new file mode 100644 (file)
index 0000000..6b2591e
--- /dev/null
@@ -0,0 +1,1065 @@
+/* Driver for Microtek Scanmaker X6 USB scanner, and possibly others.
+ *
+ * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
+ * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *
+ * Parts shamelessly stolen from usb-storage and copyright by their
+ * authors. Thanks to Matt Dharm for giving us permission!
+ *
+ * This driver implements a SCSI host controller driver and a USB
+ * device driver. To avoid confusion, all the USB related stuff is
+ * prefixed by mts_usb_ and all the SCSI stuff by mts_scsi_.
+ *
+ * Microtek (www.microtek.com) did not release the specifications for
+ * their USB protocol to us, so we had to reverse engineer them. We
+ * don't know for which models they are valid.
+ *
+ * The X6 USB has three bulk endpoints, one output (0x1) down which
+ * commands and outgoing data are sent, and two input: 0x82 from which
+ * normal data is read from the scanner (in packets of maximum 32
+ * bytes) and from which the status byte is read, and 0x83 from which
+ * the results of a scan (or preview) are read in up to 64 * 1024 byte
+ * chunks by the Windows driver. We don't know how much it is possible
+ * to read at a time from 0x83.
+ *
+ * It seems possible to read (with URB transfers) everything from 0x82
+ * in one go, without bothering to read in 32 byte chunks.
+ *
+ * There seems to be an optimisation of a further READ implicit if
+ * you simply read from 0x83.
+ *
+ * Guessed protocol:
+ *
+ *     Send raw SCSI command to EP 0x1
+ *
+ *     If there is data to receive:
+ *             If the command was READ datatype=image:
+ *                     Read a lot of data from EP 0x83
+ *             Else:
+ *                     Read data from EP 0x82
+ *     Else:
+ *             If there is data to transmit:
+ *                     Write it to EP 0x1
+ *
+ *     Read status byte from EP 0x82
+ *
+ * References:
+ *
+ * The SCSI command set for the scanner is available from
+ *     ftp://ftp.microtek.com/microtek/devpack/
+ *
+ * Microtek NV sent us a more up to date version of the document. If
+ * you want it, just send mail.
+ *
+ * Status:
+ *
+ *     Untested with multiple scanners.
+ *     Untested on SMP.
+ *     Untested on a bigendian machine.
+ *
+ * History:
+ *
+ *     20000417 starting history
+ *     20000417 fixed load oops
+ *     20000417 fixed unload oops
+ *     20000419 fixed READ IMAGE detection
+ *     20000424 started conversion to use URBs
+ *     20000502 handled short transfers as errors
+ *     20000513 rename and organisation of functions (john)
+ *     20000513 added IDs for all products supported by Windows driver (john)
+ *     20000514 Rewrote mts_scsi_queuecommand to use URBs (john)
+ *     20000514 Version 0.0.8j
+ *      20000514 Fix reporting of non-existant devices to SCSI layer (john)
+ *     20000514 Added MTS_DEBUG_INT (john)
+ *     20000514 Changed "usb-microtek" to "microtek" for consistency (john)
+ *     20000514 Stupid bug fixes (john)
+ *     20000514 Version 0.0.9j
+ *     20000515 Put transfer context and URB in mts_desc (john)
+ *     20000515 Added prelim turn off debugging support (john)
+ *     20000515 Version 0.0.10j
+ *      20000515 Fixed up URB allocation (clear URB on alloc) (john)
+ *      20000515 Version 0.0.11j
+ *     20000516 Removed unnecessary spinlock in mts_transfer_context (john)
+ *     20000516 Removed unnecessary up on instance lock in mts_remove_nolock (john)
+ *     20000516 Implemented (badly) scsi_abort (john)
+ *     20000516 Version 0.0.12j
+ *      20000517 Hopefully removed mts_remove_nolock quasideadlock (john)
+ *      20000517 Added mts_debug_dump to print ll USB info (john)
+ *     20000518 Tweaks and documentation updates (john)
+ *     20000518 Version 0.0.13j
+ *     20000518 Cleaned up abort handling (john)
+ *     20000523 Removed scsi_command and various scsi_..._resets (john)
+ *     20000523 Added unlink URB on scsi_abort, now OHCI supports it (john)
+ *     20000523 Fixed last tiresome compile warning (john)
+ *     20000523 Version 0.0.14j (though version 0.1 has come out?)
+ *     20000602 Added primitive reset
+ *     20000602 Version 0.2.0
+ *     20000603 various cosmetic changes
+ *     20000603 Version 0.2.1
+ *     20000620 minor cosmetic changes
+ *     20000620 Version 0.2.2
+ *     20000822 Hopefully fixed deadlock in mts_remove_nolock()
+ *     20000822 Fixed minor race in mts_transfer_cleanup()
+ *     20000822 Fixed deadlock on submission error in queuecommand
+ *     20000822 Version 0.2.3
+ *     20000913 Reduced module size if debugging is off
+ *     20000913 Version 0.2.4
+ *      20010210 New abort logic
+ *      20010210 Version 0.3.0
+ *     20010217 Merged scatter/gather
+ *     20010218 Version 0.4.0
+ *     20010218 Cosmetic fixes
+ *     20010218 Version 0.4.1
+ *      20010306 Abort while using scatter/gather
+ *      20010306 Version 0.4.2
+ *      20010311 Remove all timeouts and tidy up generally (john)
+ *     20010320 check return value of scsi_register()
+ *     20010320 Version 0.4.3
+ *     20010408 Identify version on module load.
+ *     20011003 Fix multiple requests
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/proc_fs.h>
+
+#include <asm/atomic.h>
+#include <linux/blk.h>
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#include "../../scsi/sd.h"
+
+#include "microtek.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.4.3"
+#define DRIVER_AUTHOR "John Fremlin <vii@penguinpowered.com>, Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>"
+#define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver"
+
+/* Should we do debugging? */
+
+//#define MTS_DO_DEBUG
+
+/* USB layer driver interface */
+
+static void *mts_usb_probe(struct usb_device *dev, unsigned int interface,
+                        const struct usb_device_id *id);
+static void mts_usb_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_device_id mts_usb_ids [];
+
+static struct usb_driver mts_usb_driver = {
+       name:           "microtekX6",
+       probe:          mts_usb_probe,
+       disconnect:     mts_usb_disconnect,
+       id_table:       mts_usb_ids,
+};
+
+
+/* Internal driver stuff */
+
+#define MTS_VERSION    "0.4.3"
+#define MTS_NAME       "microtek usb (rev " MTS_VERSION "): "
+
+#define MTS_WARNING(x...) \
+       printk( KERN_WARNING MTS_NAME x )
+#define MTS_ERROR(x...) \
+       printk( KERN_ERR MTS_NAME x )
+#define MTS_INT_ERROR(x...) \
+       MTS_ERROR(x)
+#define MTS_MESSAGE(x...) \
+       printk( KERN_INFO MTS_NAME x )
+
+#if defined MTS_DO_DEBUG
+
+#define MTS_DEBUG(x...) \
+       printk( KERN_DEBUG MTS_NAME x )
+
+#define MTS_DEBUG_GOT_HERE() \
+       MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ )
+#define MTS_DEBUG_INT() \
+       do { MTS_DEBUG_GOT_HERE(); \
+            MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
+            MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+             mts_debug_dump(context->instance);\
+          } while(0)
+#else
+
+#define MTS_NUL_STATEMENT do { } while(0)
+
+#define MTS_DEBUG(x...)        MTS_NUL_STATEMENT
+#define MTS_DEBUG_GOT_HERE() MTS_NUL_STATEMENT
+#define MTS_DEBUG_INT() MTS_NUL_STATEMENT
+
+#endif
+
+
+
+#define MTS_INT_INIT()\
+       struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context; \
+       MTS_DEBUG_INT();\
+
+#ifdef MTS_DO_DEBUG
+
+static inline void mts_debug_dump(struct mts_desc* desc) {
+       MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n",
+                 (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0],
+                 (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0]
+               );
+       MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n",
+                 usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
+                 usb_rcvbulkpipe(desc->usb_dev,desc->ep_response),
+                 usb_rcvbulkpipe(desc->usb_dev,desc->ep_image)
+               );
+}
+
+
+static inline void mts_show_command(Scsi_Cmnd *srb)
+{
+       char *what = NULL;
+
+       switch (srb->cmnd[0]) {
+       case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+       case REZERO_UNIT: what = "REZERO_UNIT"; break;
+       case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+       case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+       case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+       case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+       case READ_6: what = "READ_6"; break;
+       case WRITE_6: what = "WRITE_6"; break;
+       case SEEK_6: what = "SEEK_6"; break;
+       case READ_REVERSE: what = "READ_REVERSE"; break;
+       case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+       case SPACE: what = "SPACE"; break;
+       case INQUIRY: what = "INQUIRY"; break;
+       case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+       case MODE_SELECT: what = "MODE_SELECT"; break;
+       case RESERVE: what = "RESERVE"; break;
+       case RELEASE: what = "RELEASE"; break;
+       case COPY: what = "COPY"; break;
+       case ERASE: what = "ERASE"; break;
+       case MODE_SENSE: what = "MODE_SENSE"; break;
+       case START_STOP: what = "START_STOP"; break;
+       case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+       case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+       case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+       case SET_WINDOW: what = "SET_WINDOW"; break;
+       case READ_CAPACITY: what = "READ_CAPACITY"; break;
+       case READ_10: what = "READ_10"; break;
+       case WRITE_10: what = "WRITE_10"; break;
+       case SEEK_10: what = "SEEK_10"; break;
+       case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+       case VERIFY: what = "VERIFY"; break;
+       case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+       case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+       case SEARCH_LOW: what = "SEARCH_LOW"; break;
+       case SET_LIMITS: what = "SET_LIMITS"; break;
+       case READ_POSITION: what = "READ_POSITION"; break;
+       case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+       case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+       case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+       case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+       case COMPARE: what = "COMPARE"; break;
+       case COPY_VERIFY: what = "COPY_VERIFY"; break;
+       case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+       case READ_BUFFER: what = "READ_BUFFER"; break;
+       case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+       case READ_LONG: what = "READ_LONG"; break;
+       case WRITE_LONG: what = "WRITE_LONG"; break;
+       case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+       case WRITE_SAME: what = "WRITE_SAME"; break;
+       case READ_TOC: what = "READ_TOC"; break;
+       case LOG_SELECT: what = "LOG_SELECT"; break;
+       case LOG_SENSE: what = "LOG_SENSE"; break;
+       case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+       case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+       case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
+       case READ_12: what = "READ_12"; break;
+       case WRITE_12: what = "WRITE_12"; break;
+       case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+       case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+       case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+       case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+       case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+       case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+       case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+       default:
+               MTS_DEBUG("can't decode command\n");
+               goto out;
+               break;
+       }
+       MTS_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len);
+
+ out:
+       MTS_DEBUG( "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+              srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5],
+              srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
+}
+
+#else
+
+static inline void mts_show_command(Scsi_Cmnd * dummy)
+{
+}
+
+static inline void mts_debug_dump(struct mts_desc* dummy)
+{
+}
+
+#endif
+
+static inline void mts_urb_abort(struct mts_desc* desc) {
+       MTS_DEBUG_GOT_HERE();
+       mts_debug_dump(desc);
+
+       usb_unlink_urb( desc->urb );
+}
+
+static struct mts_desc * mts_list; /* list of active scanners */
+struct semaphore mts_list_semaphore;
+
+/* Internal list operations */
+
+static
+void mts_remove_nolock( struct mts_desc* to_remove )
+{
+       MTS_DEBUG( "removing 0x%x from list\n",
+                  (int)to_remove );
+
+       lock_kernel();
+       mts_urb_abort(to_remove);
+
+       MTS_DEBUG_GOT_HERE();
+
+       if ( to_remove != mts_list ) {
+               MTS_DEBUG_GOT_HERE();
+               if (to_remove->prev && to_remove->next)
+                       to_remove->prev->next = to_remove->next;
+       } else {
+               MTS_DEBUG_GOT_HERE();
+               mts_list = to_remove->next;
+               if (mts_list) {
+                       MTS_DEBUG_GOT_HERE();
+                       mts_list->prev = 0;
+               }
+       }
+
+       if ( to_remove->next ) {
+               MTS_DEBUG_GOT_HERE();
+               to_remove->next->prev = to_remove->prev;
+       }
+
+       MTS_DEBUG_GOT_HERE();
+       scsi_unregister_host(&to_remove->ctempl);
+       unlock_kernel();
+
+       usb_free_urb(to_remove->urb);
+       kfree( to_remove );
+}
+
+static
+void mts_add_nolock( struct mts_desc* to_add )
+{
+       MTS_DEBUG( "adding 0x%x to list\n", (int)to_add );
+
+       to_add->prev = 0;
+       to_add->next = mts_list;
+       if ( mts_list ) {
+               mts_list->prev = to_add;
+       }
+
+       mts_list = to_add;
+}
+
+
+
+
+/* SCSI driver interface */
+
+/* scsi related functions - dummies for now mostly */
+
+static int mts_scsi_release(struct Scsi_Host *psh)
+{
+       MTS_DEBUG_GOT_HERE();
+
+       return 0;
+}
+
+static int mts_scsi_abort (Scsi_Cmnd *srb)
+{
+       struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+
+       MTS_DEBUG_GOT_HERE();
+
+       mts_urb_abort(desc);
+
+       return SCSI_ABORT_PENDING;
+}
+
+static int mts_scsi_host_reset (Scsi_Cmnd *srb)
+{
+       struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+
+       MTS_DEBUG_GOT_HERE();
+       mts_debug_dump(desc);
+
+       usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */
+       return 0;  /* RANT why here 0 and not SUCCESS */
+}
+
+/* the core of the scsi part */
+
+/* faking a detection - which can't fail :-) */
+
+static int mts_scsi_detect (struct SHT * sht)
+{
+       /* Whole function stolen from usb-storage */
+
+       struct mts_desc * desc = (struct mts_desc *)sht->proc_dir;
+       /* What a hideous hack! */
+
+       char local_name[48];
+
+       MTS_DEBUG_GOT_HERE();
+
+       /* set up the name of our subdirectory under /proc/scsi/ */
+       sprintf(local_name, "microtek-%d", desc->host_number);
+       sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
+       /* FIXME: where is this freed ? */
+
+       if (!sht->proc_name) {
+               MTS_ERROR( "unable to allocate memory for proc interface!!\n" );
+               return 0;
+       }
+
+       strcpy(sht->proc_name, local_name);
+
+       sht->proc_dir = NULL;
+
+       /* In host->hostdata we store a pointer to desc */
+       desc->host = scsi_register(sht, sizeof(desc));
+       if (desc->host == NULL) {
+               MTS_ERROR("Cannot register due to low memory");
+               kfree(sht->proc_name);
+               return 0;
+       }
+       desc->host->hostdata[0] = (unsigned long)desc;
+/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */
+
+       return 1;
+}
+
+
+
+/* Main entrypoint: SCSI commands are dispatched to here */
+
+
+
+static
+int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
+
+static void mts_transfer_cleanup( struct urb *transfer );
+static void mts_do_sg(struct urb * transfer);
+
+
+inline static
+void mts_int_submit_urb (struct urb* transfer,
+                       int pipe,
+                       void* data,
+                       unsigned length,
+                       mts_usb_urb_callback callback )
+/* Interrupt context! */
+
+/* Holding transfer->context->lock! */
+{
+       int res;
+
+       MTS_INT_INIT();
+
+       FILL_BULK_URB(transfer,
+                     context->instance->usb_dev,
+                     pipe,
+                     data,
+                     length,
+                     callback,
+                     context
+               );
+
+       transfer->status = 0;
+
+       res = usb_submit_urb( transfer, GFP_ATOMIC );
+       if ( unlikely(res) ) {
+               MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
+               context->srb->result = DID_ERROR << 16;
+               mts_transfer_cleanup(transfer);
+       }
+       return;
+}
+
+
+static void mts_transfer_cleanup( struct urb *transfer )
+/* Interrupt context! */
+{
+       MTS_INT_INIT();
+
+       if ( likely(context->final_callback != NULL) )
+               context->final_callback(context->srb);
+
+}
+
+static void mts_transfer_done( struct urb *transfer )
+{
+       MTS_INT_INIT();
+
+       context->srb->result &= MTS_SCSI_ERR_MASK;
+       context->srb->result |= (unsigned)context->status<<1;
+
+       mts_transfer_cleanup(transfer);
+
+       return;
+}
+
+
+static void mts_get_status( struct urb *transfer )
+/* Interrupt context! */
+{
+       MTS_INT_INIT();
+
+       mts_int_submit_urb(transfer,
+                          usb_rcvbulkpipe(context->instance->usb_dev,
+                                          context->instance->ep_response),
+                          &context->status,
+                          1,
+                          mts_transfer_done );
+}
+
+static void mts_data_done( struct urb* transfer )
+/* Interrupt context! */
+{
+       MTS_INT_INIT();
+
+       if ( context->data_length != transfer->actual_length ) {
+               context->srb->resid = context->data_length - transfer->actual_length;
+       } else if ( unlikely(transfer->status) ) {
+               context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+       }
+
+       mts_get_status(transfer);
+
+       return;
+}
+
+
+static void mts_command_done( struct urb *transfer )
+/* Interrupt context! */
+{
+       MTS_INT_INIT();
+
+       if ( unlikely(transfer->status) ) {
+               if (transfer->status == -ENOENT) {
+                       /* We are being killed */
+                       MTS_DEBUG_GOT_HERE();
+                       context->srb->result = DID_ABORT<<16;
+                } else {
+                       /* A genuine error has occured */
+                       MTS_DEBUG_GOT_HERE();
+
+                       context->srb->result = DID_ERROR<<16;
+                }
+               mts_transfer_cleanup(transfer);
+
+               return;
+       }
+
+       if ( context->data ) {
+               mts_int_submit_urb(transfer,
+                                  context->data_pipe,
+                                  context->data,
+                                  context->data_length,
+                                  context->srb->use_sg ? mts_do_sg : mts_data_done);
+       } else mts_get_status(transfer);
+
+       return;
+}
+
+static void mts_do_sg (struct urb* transfer)
+{
+       struct scatterlist * sg;
+       MTS_INT_INIT();
+       
+       MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
+
+       if (unlikely(transfer->status)) {
+                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+               mts_transfer_cleanup(transfer);
+        }
+
+       sg = context->srb->buffer;
+       context->fragment++;
+       mts_int_submit_urb(transfer,
+                          context->data_pipe,
+                          page_address(sg[context->fragment].page) +
+                          sg[context->fragment].offset,
+                          sg[context->fragment].length,
+                          context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg);
+       return;
+}
+
+static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 };
+static const u8 mts_read_image_sig_len = 4;
+static const unsigned char mts_direction[256/8] = {
+       0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+       0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)
+
+static void
+mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
+{
+       int pipe;
+       struct scatterlist * sg;
+       
+       MTS_DEBUG_GOT_HERE();
+
+       desc->context.instance = desc;
+       desc->context.srb = srb;
+       desc->context.fragment = 0;
+
+       if (!srb->use_sg) {
+               if ( !srb->bufflen ){
+                       desc->context.data = 0;
+                       desc->context.data_length = 0;
+                       return;
+               } else {
+                       desc->context.data = srb->buffer;
+                       desc->context.data_length = srb->bufflen;
+                       MTS_DEBUG("length = %d or %d\n",
+                                 srb->request_bufflen, srb->bufflen);
+               }
+       } else {
+               MTS_DEBUG("Using scatter/gather\n");
+               sg = srb->buffer;
+               desc->context.data = page_address(sg[0].page) + sg[0].offset;
+               desc->context.data_length = sg[0].length;
+       }
+
+
+       /* can't rely on srb->sc_data_direction */
+
+       /* Brutally ripped from usb-storage */
+
+       if ( !memcmp( srb->cmnd, mts_read_image_sig, mts_read_image_sig_len )
+) {            pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_image);
+               MTS_DEBUG( "transfering from desc->ep_image == %d\n",
+                          (int)desc->ep_image );
+       } else if ( MTS_DIRECTION_IS_IN(srb->cmnd[0]) ) {
+                       pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_response);
+                       MTS_DEBUG( "transfering from desc->ep_response == %d\n",
+                                  (int)desc->ep_response);
+       } else {
+               MTS_DEBUG("transfering to desc->ep_out == %d\n",
+                         (int)desc->ep_out);
+               pipe = usb_sndbulkpipe(desc->usb_dev,desc->ep_out);
+       }
+       desc->context.data_pipe = pipe;
+}
+
+
+static
+int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
+{
+       struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+       int err = 0;
+       int res;
+
+       MTS_DEBUG_GOT_HERE();
+       mts_show_command(srb);
+       mts_debug_dump(desc);
+
+       if ( srb->device->lun || srb->device->id || srb->device->channel ) {
+
+               MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel );
+
+               MTS_DEBUG("this device doesn't exist\n");
+
+               srb->result = DID_BAD_TARGET << 16;
+
+               if(likely(callback != NULL))
+                       callback(srb);
+
+               goto out;
+       }
+
+       
+       FILL_BULK_URB(desc->urb,
+                     desc->usb_dev,
+                     usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
+                     srb->cmnd,
+                     srb->cmd_len,
+                     mts_command_done,
+                     &desc->context
+                     );
+
+
+       mts_build_transfer_context( srb, desc );
+       desc->context.final_callback = callback;
+       
+       /* here we need ATOMIC as we are called with the iolock */
+       res=usb_submit_urb(desc->urb, GFP_ATOMIC);
+
+       if(unlikely(res)){
+               MTS_ERROR("error %d submitting URB\n",(int)res);
+               srb->result = DID_ERROR << 16;
+
+               if(likely(callback != NULL))
+                       callback(srb);
+
+       }
+
+out:
+       return err;
+}
+/*
+ * this defines our 'host'
+ */
+
+/* NOTE: This is taken from usb-storage, should be right. */
+
+
+static Scsi_Host_Template mts_scsi_host_template = {
+       name:           "microtekX6",
+       detect:         mts_scsi_detect,
+       release:        mts_scsi_release,
+       queuecommand:   mts_scsi_queuecommand,
+
+       eh_abort_handler:       mts_scsi_abort,
+       eh_host_reset_handler:  mts_scsi_host_reset,
+
+       sg_tablesize:           SG_ALL,
+       can_queue:              1,
+       this_id:                -1,
+       cmd_per_lun:            1,
+       present:                0,
+       unchecked_isa_dma:      FALSE,
+       use_clustering:         TRUE,
+       emulated:               TRUE
+};
+
+
+/* USB layer driver interface implementation */
+
+static void mts_usb_disconnect (struct usb_device *dev, void *ptr)
+{
+       struct mts_desc* to_remove = (struct mts_desc*)ptr;
+
+       MTS_DEBUG_GOT_HERE();
+
+       /* leave the list - lock it */
+       down(&mts_list_semaphore);
+
+       mts_remove_nolock(to_remove);
+
+       up(&mts_list_semaphore);
+}
+
+struct vendor_product
+{
+       char* name;
+       enum
+       {
+               mts_sup_unknown=0,
+               mts_sup_alpha,
+               mts_sup_full
+       }
+       support_status;
+} ;
+
+
+/* These are taken from the msmUSB.inf file on the Windows driver CD */
+const static struct vendor_product mts_supported_products[] =
+{
+       { "Phantom 336CX",      mts_sup_unknown},
+       { "Phantom 336CX",      mts_sup_unknown},
+       { "Scanmaker X6",       mts_sup_alpha},
+       { "Phantom C6",         mts_sup_unknown},
+       { "Phantom 336CX",      mts_sup_unknown},
+       { "ScanMaker V6USL",    mts_sup_unknown},
+       { "ScanMaker V6USL",    mts_sup_unknown},
+       { "Scanmaker V6UL",     mts_sup_unknown},
+       { "Scanmaker V6UPL",    mts_sup_alpha},
+};
+
+/* The entries of microtek_table must correspond, line-by-line to
+   the entries of mts_supported_products[]. */
+
+static struct usb_device_id mts_usb_ids [] =
+{
+       { USB_DEVICE(0x4ce, 0x0300) },
+       { USB_DEVICE(0x5da, 0x0094) },
+       { USB_DEVICE(0x5da, 0x0099) },
+       { USB_DEVICE(0x5da, 0x009a) },
+       { USB_DEVICE(0x5da, 0x00a0) },
+       { USB_DEVICE(0x5da, 0x00a3) },
+       { USB_DEVICE(0x5da, 0x80a3) },
+       { USB_DEVICE(0x5da, 0x80ac) },
+       { USB_DEVICE(0x5da, 0x00b6) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, mts_usb_ids);
+
+
+static void * mts_usb_probe (struct usb_device *dev, unsigned int interface,
+                            const struct usb_device_id *id)
+{
+       int i;
+       int result;
+       int ep_out = -1;
+       int ep_in_set[3]; /* this will break if we have more than three endpoints
+                          which is why we check */
+       int *ep_in_current = ep_in_set;
+
+       struct mts_desc * new_desc;
+       struct vendor_product const* p;
+
+       /* the altsettting 0 on the interface we're probing */
+       struct usb_interface_descriptor *altsetting;
+
+       MTS_DEBUG_GOT_HERE();
+       MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev );
+
+       MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n",
+                  (int)dev->descriptor.idProduct,
+                  (int)dev->descriptor.idVendor );
+
+       MTS_DEBUG_GOT_HERE();
+
+       p = &mts_supported_products[id - mts_usb_ids];
+
+       MTS_DEBUG_GOT_HERE();
+
+       MTS_DEBUG( "found model %s\n", p->name );
+       if ( p->support_status != mts_sup_full )
+               MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n",
+                            p->name );
+
+       /* the altsettting 0 on the interface we're probing */
+       altsetting =
+               &(dev->actconfig->interface[interface].altsetting[0]);
+
+
+       /* Check if the config is sane */
+
+       if ( altsetting->bNumEndpoints != MTS_EP_TOTAL ) {
+               MTS_WARNING( "expecting %d got %d endpoints! Bailing out.\n",
+                            (int)MTS_EP_TOTAL, (int)altsetting->bNumEndpoints );
+               return NULL;
+       }
+
+       for( i = 0; i < altsetting->bNumEndpoints; i++ ) {
+               if ((altsetting->endpoint[i].bmAttributes &
+                    USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
+
+                       MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n",
+                            (int)altsetting->endpoint[i].bEndpointAddress );
+               } else {
+                       if (altsetting->endpoint[i].bEndpointAddress &
+                           USB_DIR_IN)
+                               *ep_in_current++
+                                       = altsetting->endpoint[i].bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       else {
+                               if ( ep_out != -1 ) {
+                                       MTS_WARNING( "can only deal with one output endpoints. Bailing out." );
+                                       return NULL;
+                               }
+
+                               ep_out = altsetting->endpoint[i].bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       }
+               }
+
+       }
+
+
+       if ( ep_out == -1 ) {
+               MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
+               return NULL;
+       }
+
+
+       /* I don't understand the following fully (it's from usb-storage) -- John */
+
+       /* set the interface -- STALL is an acceptable response here */
+       result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
+
+       MTS_DEBUG("usb_set_interface returned %d.\n",result);
+       switch( result )
+       {
+       case 0: /* no error */
+               break;
+               
+       case -EPIPE:
+               usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+               MTS_DEBUG( "clearing clearing stall on control interface\n" );
+               break;
+               
+       default:
+               MTS_DEBUG( "unknown error %d from usb_set_interface\n",
+                       (int)result );
+               return NULL;
+       }
+       
+       
+       /* allocating a new descriptor */
+       new_desc = (struct mts_desc *)kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
+       if (new_desc == NULL)
+       {
+               MTS_ERROR("couldn't allocate scanner desc, bailing out!\n");
+               return NULL;
+       }
+
+       memset( new_desc, 0, sizeof(*new_desc) );
+       new_desc->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!new_desc->urb) {
+               kfree(new_desc);
+               return NULL;
+       }
+               
+       /* initialising that descriptor */
+       new_desc->usb_dev = dev;
+       new_desc->interface = interface;
+
+       init_MUTEX(&new_desc->lock);
+
+       if(mts_list){
+               new_desc->host_number = mts_list->host_number+1;
+       } else {
+               new_desc->host_number = 0;
+       }
+       
+       /* endpoints */
+       
+       new_desc->ep_out = ep_out;
+       new_desc->ep_response = ep_in_set[0];
+       new_desc->ep_image = ep_in_set[1];
+
+
+       if ( new_desc->ep_out != MTS_EP_OUT )
+               MTS_WARNING( "will this work? Command EP is not usually %d\n",
+                            (int)new_desc->ep_out );
+
+       if ( new_desc->ep_response != MTS_EP_RESPONSE )
+               MTS_WARNING( "will this work? Response EP is not usually %d\n",
+                            (int)new_desc->ep_response );
+
+       if ( new_desc->ep_image != MTS_EP_IMAGE )
+               MTS_WARNING( "will this work? Image data EP is not usually %d\n",
+                            (int)new_desc->ep_image );
+
+
+       /* Initialize the host template based on the default one */
+       memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template));
+       /* HACK from usb-storage - this is needed for scsi detection */
+       (struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */
+
+       MTS_DEBUG("registering SCSI module\n");
+
+       new_desc->ctempl.module = THIS_MODULE;
+       result = scsi_register_host(&new_desc->ctempl);
+       /* Will get hit back in microtek_detect by this func */
+       if ( result )
+       {
+               MTS_ERROR( "error %d from scsi_register_host! Help!\n",
+                          (int)result );
+
+               /* FIXME: need more cleanup? */
+               kfree( new_desc );
+               return NULL;
+       }
+       MTS_DEBUG_GOT_HERE();
+
+       /* FIXME: the bomb is armed, must the host be registered under lock ? */
+       /* join the list - lock it */
+       down(&mts_list_semaphore);
+
+       mts_add_nolock( new_desc );
+
+       up(&mts_list_semaphore);
+
+
+       MTS_DEBUG("completed probe and exiting happily\n");
+
+       return (void *)new_desc;
+}
+
+
+
+/* get us noticed by the rest of the kernel */
+
+int __init microtek_drv_init(void)
+{
+       int result;
+
+       MTS_DEBUG_GOT_HERE();
+       init_MUTEX(&mts_list_semaphore);
+
+       if ((result = usb_register(&mts_usb_driver)) < 0) {
+               MTS_DEBUG("usb_register returned %d\n", result );
+               return -1;
+       } else {
+               MTS_DEBUG("driver registered.\n");
+       }
+
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+
+       return 0;
+}
+
+void __exit microtek_drv_exit(void)
+{
+       struct mts_desc* next;
+
+       MTS_DEBUG_GOT_HERE();
+
+       usb_deregister(&mts_usb_driver);
+
+       down(&mts_list_semaphore);
+
+       while (mts_list) {
+               /* keep track of where the next one is */
+               next = mts_list->next;
+
+               mts_remove_nolock( mts_list );
+
+               /* advance the list pointer */
+               mts_list = next;
+       }
+
+       up(&mts_list_semaphore);
+}
+
+module_init(microtek_drv_init);
+module_exit(microtek_drv_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+
diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h
new file mode 100644 (file)
index 0000000..7ab7cb3
--- /dev/null
@@ -0,0 +1,60 @@
+ /*
+ * Driver for Microtek Scanmaker X6 USB scanner and possibly others.
+ * 
+ * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
+ * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *
+ * See microtek.c for history
+ *
+ */
+
+typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *);
+typedef void (*mts_usb_urb_callback) (struct urb *);
+
+
+struct mts_transfer_context
+{
+       struct mts_desc* instance;
+       mts_scsi_cmnd_callback final_callback;
+       Scsi_Cmnd *srb;
+       
+       void* data;
+       unsigned data_length;
+       int data_pipe;
+       int fragment;
+
+       u8 status; /* status returned from ep_response after command completion */
+};
+
+
+struct mts_desc {
+       struct mts_desc *next;
+       struct mts_desc *prev;
+
+       struct usb_device *usb_dev;
+
+       int interface;
+
+       /* Endpoint addresses */
+       u8 ep_out;
+       u8 ep_response;
+       u8 ep_image;
+
+       struct Scsi_Host * host;
+       Scsi_Host_Template ctempl;
+       int host_number;
+
+       struct semaphore lock;
+
+       struct urb *urb;
+       struct mts_transfer_context context;
+};
+
+
+#define MTS_EP_OUT     0x1
+#define MTS_EP_RESPONSE        0x2
+#define MTS_EP_IMAGE   0x3
+#define MTS_EP_TOTAL   0x3
+
+#define MTS_SCSI_ERR_MASK ~0x3fu
+
diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
new file mode 100644 (file)
index 0000000..22eabc5
--- /dev/null
@@ -0,0 +1,1125 @@
+/* -*- linux-c -*- */
+
+/* 
+ * Driver for USB Scanners (linux-2.4.12)
+ *
+ * Copyright (C) 1999, 2000, 2001 David E. Nelson
+ *
+ * Portions may be copyright Brad Keryan and Michael Gee.
+ *
+ * David E. Nelson (dnelson@jump.net)
+ * 
+ * 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 the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Originally based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
+ *
+ * History
+ *
+ *  0.1  8/31/1999
+ *
+ *    Developed/tested using linux-2.3.15 with minor ohci.c changes to
+ *    support short packes during bulk xfer mode.  Some testing was
+ *    done with ohci-hcd but the performace was low.  Very limited
+ *    testing was performed with uhci but I was unable to get it to
+ *    work.  Initial relase to the linux-usb development effort.
+ *
+ *
+ *  0.2  10/16/1999
+ *
+ *    - Device can't be opened unless a scanner is plugged into the USB.
+ *    - Finally settled on a reasonable value for the I/O buffer's.
+ *    - Cleaned up write_scanner()
+ *    - Disabled read/write stats
+ *    - A little more code cleanup
+ *
+ *
+ *  0.3  10/18/1999
+ *
+ *    - Device registration changed to reflect new device
+ *      allocation/registration for linux-2.3.22+.
+ *    - Adopted David Brownell's <david-b@pacbell.net> technique for 
+ *      assigning bulk endpoints.
+ *    - Removed unnessesary #include's
+ *    - Scanner model now reported via syslog INFO after being detected 
+ *      *and* configured.
+ *    - Added user specified vendor:product USB ID's which can be passed 
+ *      as module parameters.
+ *
+ *
+ *  0.3.1
+ *
+ *    - Applied patches for linux-2.3.25.
+ *    - Error number reporting changed to reflect negative return codes.
+ *
+ *
+ *  0.3.2
+ *
+ *    - Applied patches for linux-2.3.26 to scanner_init().
+ *    - Debug read/write stats now report values as signed decimal.
+ *
+ *
+ *  0.3.3
+ *
+ *    - Updated the bulk_msg() calls to usb usb_bulk_msg().
+ *    - Added a small delay in the write_scanner() method to aid in
+ *      avoiding NULL data reads on HP scanners.  We'll see how this works.
+ *    - Return values from usb_bulk_msg() now ignore positive values for
+ *      use with the ohci driver.
+ *    - Added conditional debugging instead of commenting/uncommenting
+ *      all over the place.
+ *    - kfree()'d the pointer after using usb_string() as documented in
+ *      linux-usb-api.txt.
+ *    - Added usb_set_configuration().  It got lost in version 0.3 -- ack!
+ *    - Added the HP 5200C USB Vendor/Product ID's.
+ *
+ *
+ *  0.3.4  1/23/2000
+ *
+ *    - Added Greg K-H's <greg@kroah.com> patch for better handling of 
+ *      Product/Vendor detection.
+ *    - The driver now autoconfigures its endpoints including interrupt
+ *      endpoints if one is detected.  The concept was originally based
+ *      upon David Brownell's method.
+ *    - Added some Seiko/Epson ID's. Thanks to Karl Heinz 
+ *      Kremer <khk@khk.net>.
+ *    - Added some preliminary ioctl() calls for the PV8630 which is used
+ *      by the HP4200. The ioctl()'s still have to be registered. Thanks 
+ *      to Adrian Perez Jorge <adrianpj@easynews.com>.
+ *    - Moved/migrated stuff to scanner.h
+ *    - Removed the usb_set_configuration() since this is handled by
+ *      the usb_new_device() routine in usb.c.
+ *    - Added the HP 3300C.  Thanks to Bruce Tenison.
+ *    - Changed user specified vendor/product id so that root hub doesn't
+ *      get falsely attached to. Thanks to Greg K-H.
+ *    - Added some Mustek ID's. Thanks to Gernot Hoyler 
+ *      <Dr.Hoyler@t-online.de>.
+ *    - Modified the usb_string() reporting.  See kfree() comment above.
+ *    - Added Umax Astra 2000U. Thanks to Doug Alcorn <doug@lathi.net>.
+ *    - Updated the printk()'s to use the info/warn/dbg macros.
+ *    - Updated usb_bulk_msg() argument types to fix gcc warnings.
+ *
+ *
+ *  0.4  2/4/2000
+ *
+ *    - Removed usb_string() from probe_scanner since the core now does a
+ *      good job of reporting what was connnected.  
+ *    - Finally, simultaneous multiple device attachment!
+ *    - Fixed some potential memory freeing issues should memory allocation
+ *      fail in probe_scanner();
+ *    - Some fixes to disconnect_scanner().
+ *    - Added interrupt endpoint support.
+ *    - Added Agfa SnapScan Touch. Thanks to Jan Van den Bergh
+ *      <jan.vandenbergh@cs.kuleuven.ac.be>.
+ *    - Added Umax 1220U ID's. Thanks to Maciek Klimkowski
+ *      <mac@nexus.carleton.ca>.
+ *    - Fixed bug in write_scanner(). The buffer was not being properly
+ *      updated for writes larger than OBUF_SIZE. Thanks to Henrik 
+ *      Johansson <henrikjo@post.utfors.se> for identifying it.
+ *    - Added Microtek X6 ID's. Thanks to Oliver Neukum
+ *      <Oliver.Neukum@lrz.uni-muenchen.de>.
+ *
+ * 
+ *  0.4.1  2/15/2000
+ *  
+ *    - Fixed 'count' bug in read_scanner(). Thanks to Henrik
+ *      Johansson <henrikjo@post.utfors.se> for identifying it.  Amazing
+ *      it has worked this long.
+ *    - Fixed '>=' bug in both read/write_scanner methods.
+ *    - Cleaned up both read/write_scanner() methods so that they are 
+ *      a little more readable.
+ *    - Added a lot of Microtek ID's.  Thanks to Adrian Perez Jorge.
+ *    - Adopted the __initcall().
+ *    - Added #include <linux/init.h> to scanner.h for __initcall().
+ *    - Added one liner in irq_scanner() to keep gcc from complaining 
+ *      about an unused variable (data) if debugging was disabled
+ *      in scanner.c.
+ *    - Increased the timeout parameter in read_scanner() to 120 Secs.
+ *
+ *
+ *  0.4.2  3/23/2000
+ *
+ *    - Added Umax 1236U ID.  Thanks to Philipp Baer <ph_baer@npw.net>.
+ *    - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
+ *      Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
+ *    - Fixed error number reported for non-existant devices.  Thanks to
+ *      Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
+ *    - Added Acer Prisascan 620U ID's.  Thanks to Joao <joey@knoware.nl>.
+ *    - Replaced __initcall() with module_init()/module_exit(). Updates
+ *      from patch-2.3.48.
+ *    - Replaced file_operations structure with new syntax.  Updates
+ *      from patch-2.3.49.
+ *    - Changed #include "usb.h" to #include <linux/usb.h>
+ *    - Added #define SCN_IOCTL to exclude development areas 
+ *      since 2.4.x is about to be released. This mainly affects the 
+ *      ioctl() stuff.  See scanner.h for more details.
+ *    - Changed the return value for signal_pending() from -ERESTARTSYS to
+ *      -EINTR.
+ *
+ *
+ * 0.4.3  4/30/2000
+ *
+ *    - Added Umax Astra 2200 ID.  Thanks to Flynn Marquardt 
+ *      <flynn@isr.uni-stuttgart.de>.
+ *    - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>.
+ *    - Added access time update for the device file courtesy of Paul
+ *      Mackerras <paulus@samba.org>.  This allows a user space daemon
+ *      to turn the lamp off for a Umax 1220U scanner after a prescribed
+ *      time.
+ *    - Fixed HP S20 ID's.  Thanks to Ruud Linders <rlinders@xs4all.nl>.
+ *    - Added Acer ScanPrisa 620U ID. Thanks to Oliver
+ *      Schwartz <Oliver.Schwartz@gmx.de> via sane-devel mail list.
+ *    - Fixed bug in read_scanner for copy_to_user() function.  The returned
+ *      value should be 'partial' not 'this_read'.
+ *    - Fixed bug in read_scanner. 'count' should be decremented 
+ *      by 'this_read' and not by 'partial'.  This resulted in twice as many
+ *      calls to read_scanner() for small amounts of data and possibly
+ *      unexpected returns of '0'.  Thanks to Karl Heinz 
+ *      Kremer <khk@khk.net> and Alain Knaff <Alain.Knaff@ltnb.lu>
+ *      for discovering this.
+ *    - Integrated Randy Dunlap's <randy.dunlap@intel.com> patch for a
+ *      scanner lookup/ident table. Thanks Randy.
+ *    - Documentation updates.
+ *    - Added wait queues to read_scanner().
+ *
+ *
+ * 0.4.3.1
+ *
+ *    - Fixed HP S20 ID's...again..sigh.  Thanks to Ruud
+ *      Linders <rlinders@xs4all.nl>.
+ *
+ * 0.4.4
+ *    - Added addtional Mustek ID's (BearPaw 1200, 600 CU, 1200 USB,
+ *      and 1200 UB.  Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
+ *    - Added the Vuego Scan Brisa 340U ID's.  Apparently this scanner is
+ *      marketed by Acer Peripherals as a cheap 300 dpi model. Thanks to
+ *      David Gundersen <gundersd@paradise.net.nz>.
+ *    - Added the Epson Expression1600 ID's. Thanks to Karl Heinz
+ *      Kremer <khk@khk.net>.
+ *
+ * 0.4.5  2/28/2001
+ *    - Added Mustek ID's (BearPaw 2400, 1200 CU Plus, BearPaw 1200F).
+ *      Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
+ *    - Added read_timeout module parameter to override RD_NAK_TIMEOUT
+ *      when read()'ing from devices.
+ *    - Stalled pipes are now checked and cleared with
+ *      usb_clear_halt() for the read_scanner() function. This should
+ *      address the "funky result: -32" error messages.
+ *    - Removed Microtek scanner ID's.  Microtek scanners are now
+ *      supported via the drivers/usb/microtek.c driver.
+ *    - Added scanner specific read timeout's.
+ *    - Return status errors are NEGATIVE!!!  This should address the
+ *      "funky result: -110" error messages.
+ *    - Replaced USB_ST_TIMEOUT with ETIMEDOUT.
+ *    - rd_nak was still defined in MODULE_PARM.  It's been updated with
+ *      read_timeout.  Thanks to Mark W. Webb <markwebb@adelphia.net> for
+ *      reporting this bug.
+ *    - Added Epson Perfection 1640SU and 1640SU Photo.  Thanks to
+ *      Jean-Luc <f5ibh@db0bm.ampr.org> and Manuel
+ *      Pelayo <Manuel.Pelayo@sesips.org>. Reported to work fine by Manuel.
+ *
+ * 0.4.6  9/27/2001
+ *    - Added IOCTL's to report back scanner USB ID's.  Thanks to
+ *      Karl Heinz <khk@lynx.phpwebhosting.com>
+ *    - Added Umax Astra 2100U ID's.  Thanks to Ron
+ *      Wellsted <ron@wellsted.org.uk>.
+ *      and Manuel Pelayo <Manuel.Pelayo@sesips.org>.
+ *    - Added HP 3400 ID's. Thanks to Harald Hannelius <harald@iki.fi>
+ *      and Bertrik Sikken <bertrik@zonnet.nl>.  Reported to work at
+ *      htpp://home.zonnet.nl/bertrik/hp3300c/hp3300c.htm.
+ *    - Added Minolta Dimage Scan Dual II ID's.  Thanks to Jose Paulo
+ *      Moitinho de Almeida <moitinho@civil.ist.utl.pt>
+ *    - Confirmed addition for SnapScan E20.  Thanks to Steffen Hübner
+ *      <hueb_s@gmx.de>.
+ *    - Added Lifetec LT9385 ID's.  Thanks to Van Bruwaene Kris
+ *      <krvbr@yahoo.co.uk>
+ *    - Added Agfa SnapScan e26 ID's.  Reported to work with SANE
+ *      1.0.5.  Thanks to Falk Sauer <falk@mgnkatze.franken.de>.
+ *    - Added HP 4300 ID's.  Thanks to Stefan Schlosser
+ *      <castla@grmmbl.org>.
+ *    - Added Relisis Episode ID's.  Thanks to Manfred
+ *      Morgner <odb-devel@gmx.net>.
+ *    - Added many Acer ID's. Thanks to Oliver
+ *      Schwartz <Oliver.Schwartz@gmx.de>.
+ *    - Added Snapscan e40 ID's.  Thanks to Oliver
+ *      Schwartz <Oliver.Schwartz@gmx.de>.
+ *    - Thanks to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *      for helping with races.
+ *    - Added Epson Perfection 1650 ID's. Thanks to Karl Heinz
+ *      Kremer <khk@khk.net>.
+ *    - Added Epson Perfection 2450 ID's (aka GT-9700 for the Japanese
+ *      market).  Thanks to Karl Heinz Kremer <khk@khk.net>.
+ *    - Added Mustek 600 USB ID's.  Thanks to Marcus
+ *      Alanen <maalanen@ra.abo.fi>.
+ *    - Added Acer ScanPrisa 1240UT ID's.  Thanks to Morgan
+ *      Collins <sirmorcant@morcant.org>.
+ *    - Incorporated devfs patches!! Thanks to Tom Rini
+ *      <trini@kernel.crashing.org>, Pavel Roskin <proski@gnu.org>,
+ *      Greg KH <greg@kroah.com>, Yves Duret <yduret@mandrakesoft.com>,
+ *      Flavio Stanchina <flavio.stanchina@tin.it>.
+ *    - Removed Minolta ScanImage II.  This scanner uses USB SCSI.  Thanks
+ *      to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> for pointing
+ *      this out.
+ *    - Added additional SMP locking.  Thanks to David Brownell and 
+ *      Oliver Neukum for their help.
+ *    - Added version reporting - reports for both module load and modinfo
+ *    - Started path to hopefully straighten/clean out ioctl()'s.
+ *    - Users are now notified to consult the Documentation/usb/scanner.txt
+ *      for common error messages rather than the maintainer.
+ *
+ * 0.4.7  11/28/2001
+ *    - Fixed typo in Documentation/scanner.txt.  Thanks to
+ *      Karel <karel.vervaeke@pandora.be> for pointing it out.
+ *    - Added ID's for a Memorex 6136u. Thanks to Álvaro Gaspar de
+ *      Valenzuela" <agaspard@utsi.edu>.
+ *    - Added ID's for Agfa e25.  Thanks to Heinrich 
+ *      Rust <Heinrich.Rust@gmx.de>.  Also reported to work with
+ *      Linux and SANE (?).
+ *    - Added Canon FB620U, D646U, and 1220U ID's.  Thanks to Paul
+ *      Rensing <Paul_Rensing@StanfordAlumni.org>.  For more info
+ *      on Linux support for these models, contact 
+ *      salvestrini@users.sourceforge.net.
+ *    - Added Plustek OpticPro UT12, OpticPro U24, KYE/Genius
+ *      ColorPage-HR6 V2 ID's in addition to many "Unknown" models
+ *      under those vendors.  Thanks to
+ *      Jaeger, Gerhard" <g.jaeger@earthling.net>.  These scanner are
+ *      apparently based upon the LM983x IC's.
+ *    - Applied Frank's patch that addressed some locking and module
+ *      referencing counts.  Thanks to both
+ *      Frank Zago <fzago@greshamstorage.com> and
+ *      Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
+ *
+ * TODO
+ *    - Performance
+ *    - Select/poll methods
+ *    - More testing
+ *    - Proper registry/assignment for LM9830 ioctl's
+ *
+ *
+ *  Thanks to:
+ *
+ *    - All the folks on the linux-usb list who put up with me. :)  This 
+ *      has been a great learning experience for me.
+ *    - To Linus Torvalds for this great OS.
+ *    - The GNU folks.
+ *    - The folks that forwarded Vendor:Product ID's to me.
+ *    - Johannes Erdfelt for the loaning of a USB analyzer for tracking an
+ *      issue with HP-4100 and uhci.
+ *    - Adolfo Montero for his assistance.
+ *    - All the folks who chimed in with reports and suggestions.
+ *    - All the developers that are working on USB SANE backends or other
+ *      applications to use USB scanners.
+ *
+ *  Performance:
+ *
+ *    System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner
+ *            300 dpi scan of the entire bed
+ *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec
+ *       8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
+
+#include <asm/byteorder.h>
+
+/* 
+ * Scanner definitions, macros, module info, 
+ * debug/ioctl/data_dump enable, and other constants.
+ */ 
+#include "scanner.h"
+
+static void
+irq_scanner(struct urb *urb)
+{
+
+/*
+ * For the meantime, this is just a placeholder until I figure out what
+ * all I want to do with it -- or somebody else for that matter.
+ */
+
+       struct scn_usb_data *scn;
+       unsigned char *data;
+       scn = urb->context;
+
+       data = &scn->button;
+       data += 0;              /* Keep gcc from complaining about unused var */
+
+       if (urb->status) {
+               return;
+       }
+
+       dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
+
+       return;
+}
+
+static int
+open_scanner(struct inode * inode, struct file * file)
+{
+       struct scn_usb_data *scn;
+       struct usb_device *dev;
+
+       int scn_minor;
+
+       int err=0;
+
+       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]) {
+               up(&scn_mutex);
+               MOD_DEC_USE_COUNT;
+               err("open_scanner(%d): Unable to access minor data", scn_minor);
+               return -ENODEV;
+       }
+
+       scn = p_scn_table[scn_minor];
+
+       dev = scn->scn_dev;
+
+       down(&(scn->sem));      /* Now protect the scn_usb_data structure */ 
+
+       up(&scn_mutex); /* Now handled by the above */
+
+       if (!dev) {
+               err("open_scanner(%d): Scanner device not present", scn_minor);
+               err = -ENODEV;
+               goto out_error;
+       }
+
+       if (!scn->present) {
+               err("open_scanner(%d): Scanner is not present", scn_minor);
+               err = -ENODEV;
+               goto out_error;
+       }
+
+       if (scn->isopen) {
+               err("open_scanner(%d): Scanner device is already open", scn_minor);
+               err = -EBUSY;
+               goto out_error;
+       }
+
+       init_waitqueue_head(&scn->rd_wait_q);
+
+       scn->isopen = 1;
+
+       file->private_data = scn; /* Used by the read and write methods */
+
+
+out_error:
+
+       up(&(scn->sem)); /* Wake up any possible contending processes */
+
+       if (err)
+               MOD_DEC_USE_COUNT;
+
+       return err;
+}
+
+static int
+close_scanner(struct inode * inode, struct file * file)
+{
+       struct scn_usb_data *scn;
+
+       int 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;
+       }
+
+       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));
+
+       MOD_DEC_USE_COUNT;
+
+       return 0;
+}
+
+static ssize_t
+write_scanner(struct file * file, const char * buffer,
+              size_t count, loff_t *ppos)
+{
+       struct scn_usb_data *scn;
+       struct usb_device *dev;
+
+       ssize_t bytes_written = 0; /* Overall count of bytes written */
+       ssize_t ret = 0;
+
+       int scn_minor;
+
+       int this_write;         /* Number of bytes to write */
+       int partial;            /* Number of bytes successfully written */
+       int result = 0;
+
+       char *obuf;
+
+       scn = file->private_data;
+
+       down(&(scn->sem));
+
+       scn_minor = scn->scn_minor;
+
+       obuf = scn->obuf;
+
+       dev = scn->scn_dev;
+
+       file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+
+       while (count > 0) {
+
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count;
+
+               if (copy_from_user(scn->obuf, buffer, this_write)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
+               dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
+
+               if (result == -ETIMEDOUT) {     /* NAK -- shouldn't happen */
+                       warn("write_scanner: NAK received.");
+                       ret = result;
+                       break;
+               } else if (result < 0) { /* We should not get any I/O errors */
+                       warn("write_scanner(%d): funky result: %d. Consult Documentataion/usb/scanner.txt.", scn_minor, result);
+                       ret = -EIO;
+                       break;
+               }
+
+#ifdef WR_DATA_DUMP
+               if (partial) {
+                       unsigned char cnt, cnt_max;
+                       cnt_max = (partial > 24) ? 24 : partial;
+                       printk(KERN_DEBUG "dump(%d): ", scn_minor);
+                       for (cnt=0; cnt < cnt_max; cnt++) {
+                               printk("%X ", obuf[cnt]);
+                       }
+                       printk("\n");
+               }
+#endif
+               if (partial != this_write) { /* Unable to write all contents of obuf */
+                       ret = -EIO;
+                       break;
+               }
+
+               if (partial) { /* Data written */
+                       buffer += partial;
+                       count -= partial;
+                       bytes_written += partial;
+               } else { /* No data written */
+                       ret = 0;
+                       break;
+               }
+       }
+       up(&(scn->sem));
+       mdelay(5);              /* This seems to help with SANE queries */
+       return ret ? ret : bytes_written;
+}
+
+static ssize_t
+read_scanner(struct file * file, char * buffer,
+             size_t count, loff_t *ppos)
+{
+       struct scn_usb_data *scn;
+       struct usb_device *dev;
+
+       ssize_t bytes_read;     /* Overall count of bytes_read */
+       ssize_t ret;
+
+       int scn_minor;
+       int partial;            /* Number of bytes successfully read */
+       int this_read;          /* Max number of bytes to read */
+       int result;
+       int rd_expire = RD_EXPIRE;
+
+       char *ibuf;
+
+       scn = file->private_data;
+
+       down(&(scn->sem));
+
+       scn_minor = scn->scn_minor;
+
+       ibuf = scn->ibuf;
+
+       dev = scn->scn_dev;
+
+       bytes_read = 0;
+       ret = 0;
+
+       file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
+                                                            atime of
+                                                            the device
+                                                            node */
+       while (count > 0) {
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
+
+               result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, scn->rd_nak_timeout);
+               dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
+
+/*
+ * Scanners are sometimes inheriently slow since they are mechanical
+ * in nature.  USB bulk reads tend to timeout while the scanner is
+ * positioning, resetting, warming up the lamp, etc if the timeout is
+ * set too low.  A very long timeout parameter for bulk reads was used
+ * to overcome this limitation, but this sometimes resulted in folks
+ * having to wait for the timeout to expire after pressing Ctrl-C from
+ * an application. The user was sometimes left with the impression
+ * that something had hung or crashed when in fact the USB read was
+ * just waiting on data.  So, the below code retains the same long
+ * timeout period, but splits it up into smaller parts so that
+ * Ctrl-C's are acted upon in a reasonable amount of time.
+ */
+
+               if (result == -ETIMEDOUT) { /* NAK */
+                       if (!partial) { /* No data */
+                               if (--rd_expire <= 0) { /* Give it up */
+                                       warn("read_scanner(%d): excessive NAK's received", scn_minor);
+                                       ret = result;
+                                       break;
+                               } else { /* Keep trying to read data */
+                                       interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout);
+                                       continue;
+                               }
+                       } else { /* Timeout w/ some data */
+                               goto data_recvd;
+                       }
+               }
+               
+               if (result == -EPIPE) { /* No hope */
+                       if(usb_clear_halt(dev, scn->bulk_in_ep)) {
+                               err("read_scanner(%d): Failure to clear endpoint halt condition (%Zd).", scn_minor, ret);
+                       }
+                       ret = result;
+                       break;
+               } else if ((result < 0) && (result != -EREMOTEIO)) {
+                       warn("read_scanner(%d): funky result:%d. Consult Documentation/usb/scanner.txt.", scn_minor, (int)result);
+                       ret = -EIO;
+                       break;
+               }
+
+       data_recvd:
+
+#ifdef RD_DATA_DUMP
+               if (partial) {
+                       unsigned char cnt, cnt_max;
+                       cnt_max = (partial > 24) ? 24 : partial;
+                       printk(KERN_DEBUG "dump(%d): ", scn_minor);
+                       for (cnt=0; cnt < cnt_max; cnt++) {
+                               printk("%X ", ibuf[cnt]);
+                       }
+                       printk("\n");
+               }
+#endif
+
+               if (partial) { /* Data returned */
+                       if (copy_to_user(buffer, ibuf, partial)) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       count -= this_read; /* Compensate for short reads */
+                       bytes_read += partial; /* Keep tally of what actually was read */
+                       buffer += partial;
+               } else {
+                       ret = 0;
+                       break;
+               }
+       }
+       up(&(scn->sem));
+       return ret ? ret : bytes_read;
+}
+
+static int
+ioctl_scanner(struct inode *inode, struct file *file,
+             unsigned int cmd, unsigned long arg)
+{
+       struct usb_device *dev;
+
+       int 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;
+
+       switch (cmd)
+       {
+       case SCANNER_IOCTL_VENDOR :
+               return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
+       case SCANNER_IOCTL_PRODUCT :
+               return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
+#ifdef PV8630
+       case PV8630_IOCTL_INREQUEST :
+       {
+               int result;
+
+               struct {
+                       __u8  data;
+                       __u8  request;
+                       __u16 value;
+                       __u16 index;
+               } args;
+
+               if (copy_from_user(&args, (void *)arg, sizeof(args)))
+                       return -EFAULT;
+
+               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                        args.request, USB_TYPE_VENDOR|
+                                        USB_RECIP_DEVICE|USB_DIR_IN,
+                                        args.value, args.index, &args.data,
+                                        1, HZ*5);
+
+               dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
+
+               if (copy_to_user((void *)arg, &args, sizeof(args)))
+                       return -EFAULT;
+
+               dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);
+
+               return result;
+       }
+       case PV8630_IOCTL_OUTREQUEST :
+       {
+               int result;
+
+               struct {
+                       __u8  request;
+                       __u16 value;
+                       __u16 index;
+               } args;
+
+               if (copy_from_user(&args, (void *)arg, sizeof(args)))
+                       return -EFAULT;
+
+               dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
+
+               result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                        args.request, USB_TYPE_VENDOR|
+                                        USB_RECIP_DEVICE|USB_DIR_OUT,
+                                        args.value, args.index, NULL,
+                                        0, HZ*5);
+
+               dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);
+
+               return result;
+       }
+#endif /* PV8630 */
+       case SCANNER_IOCTL_CTRLMSG:
+       {
+               struct ctrlmsg_ioctl {
+                       struct usb_ctrlrequest  req;
+                       void                    *data;
+               } cmsg;
+               int pipe, nb, ret;
+               unsigned char buf[64];
+               if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
+                       return -EFAULT;
+
+               nb = le16_to_cpup(&cmsg.req.wLength);
+
+               if (nb > sizeof(buf))
+                       return -EINVAL;
+
+               if ((cmsg.req.bRequestType & 0x80) == 0) {
+                       pipe = usb_sndctrlpipe(dev, 0);
+                       if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
+                               return -EFAULT;
+               } else {
+                       pipe = usb_rcvctrlpipe(dev, 0);
+               }
+
+               ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
+                                     cmsg.req.bRequestType,
+                                     le16_to_cpup(&cmsg.req.wValue),
+                                     le16_to_cpup(&cmsg.req.wIndex),
+                                     buf, nb, HZ);
+
+               if (ret < 0) {
+                       err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
+                       return -EIO;
+               }
+
+               if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
+                       return -EFAULT;
+
+               return 0;
+       }
+       default:
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+static struct
+file_operations usb_scanner_fops = {
+       read:           read_scanner,
+       write:          write_scanner,
+       ioctl:          ioctl_scanner,
+       open:           open_scanner,
+       release:        close_scanner,
+};
+
+static void *
+probe_scanner(struct usb_device *dev, unsigned int ifnum,
+             const struct usb_device_id *id)
+{
+       struct scn_usb_data *scn;
+       struct usb_interface_descriptor *interface;
+       struct usb_endpoint_descriptor *endpoint;
+
+       int ep_cnt;
+       int ix;
+       int scn_minor;
+
+       char valid_device = 0;
+       char have_bulk_in, have_bulk_out, have_intr;
+       char name[10];
+
+       if (vendor != -1 && product != -1) {
+               info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
+       }
+
+       dbg("probe_scanner: USB dev address:%p", dev);
+       dbg("probe_scanner: ifnum:%u", ifnum);
+
+/*
+ * 1. Check Vendor/Product
+ * 2. Determine/Assign Bulk Endpoints
+ * 3. Determine/Assign Intr Endpoint
+ */
+
+/*
+ * There doesn't seem to be an imaging class defined in the USB
+ * Spec. (yet).  If there is, HP isn't following it and it doesn't
+ * look like anybody else is either.  Therefore, we have to test the
+ * Vendor and Product ID's to see what we have.  Also, other scanners
+ * may be able to use this driver by specifying both vendor and
+ * product ID's as options to the scanner module in conf.modules.
+ *
+ * NOTE: Just because a product is supported here does not mean that
+ * applications exist that support the product.  It's in the hopes
+ * that this will allow developers a means to produce applications
+ * that will support USB products.
+ *
+ * Until we detect a device which is pleasing, we silently punt.
+ */
+
+       for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct usb_device_id); ix++) {
+               if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
+                   (dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
+                       valid_device = 1;
+                       break;
+                }
+       }
+       if (dev->descriptor.idVendor == vendor &&   /* User specified */
+           dev->descriptor.idProduct == product) { /* User specified */
+               valid_device = 1;
+       }
+
+        if (!valid_device)
+                return NULL;    /* We didn't find anything pleasing */
+
+/*
+ * After this point we can be a little noisy about what we are trying to
+ *  configure.
+ */
+
+       if (dev->descriptor.bNumConfigurations != 1) {
+               info("probe_scanner: Only one device configuration is supported.");
+               return NULL;
+       }
+
+       if (dev->config[0].bNumInterfaces != 1) {
+               info("probe_scanner: Only one device interface is supported.");
+               return NULL;
+       }
+
+       interface = dev->config[0].interface[ifnum].altsetting;
+       endpoint = interface[ifnum].endpoint;
+
+/*
+ * Start checking for two bulk endpoints OR two bulk endpoints *and* one
+ * interrupt endpoint. If we have an interrupt endpoint go ahead and
+ * setup the handler. FIXME: This is a future enhancement...
+ */
+
+       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.");
+               return NULL;
+       }
+
+       ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
+
+       while (ep_cnt < interface->bNumEndpoints) {
+
+               if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {
+                       ep_cnt++;
+                       have_bulk_in = ep_cnt;
+                       dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
+                       continue;
+               }
+
+               if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
+                       ep_cnt++;
+                       have_bulk_out = ep_cnt;
+                       dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
+                       continue;
+               }
+
+               if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {
+                       ep_cnt++;
+                       have_intr = ep_cnt;
+                       dbg("probe_scanner: intr_ep:%d", have_intr);
+                       continue;
+               }
+               info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
+               return NULL;    /* Shouldn't ever get here unless we have something weird */
+       }
+
+
+/*
+ * Perform a quick check to make sure that everything worked as it
+ * should have.
+ */
+
+       switch(interface->bNumEndpoints) {
+       case 2:
+               if (!have_bulk_in || !have_bulk_out) {
+                       info("probe_scanner: Two bulk endpoints required.");
+                       return NULL;
+               }
+               break;
+       case 3:
+               if (!have_bulk_in || !have_bulk_out || !have_intr) {
+                       info("probe_scanner: Two bulk endpoints and one interrupt endpoint required.");
+                       return NULL;
+               }
+               break;
+       default:
+               info("probe_scanner: Endpoint determination failed --  consult Documentation/usb/scanner.txt");
+               return NULL;
+       }
+
+
+/*
+ * Determine a minor number and initialize the structure associated
+ * with it.  The problem with this is that we are counting on the fact
+ * that the user will sequentially add device nodes for the scanner
+ * devices.  */
+       
+       down(&scn_mutex);
+
+       for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
+               if (!p_scn_table[scn_minor])
+                       break;
+       }
+
+/* Check to make sure that the last slot isn't already taken */
+       if (p_scn_table[scn_minor]) {
+               err("probe_scanner: No more minor devices remaining.");
+               up(&scn_mutex);
+               return NULL;
+       }
+
+       dbg("probe_scanner: Allocated minor:%d", scn_minor);
+
+       if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
+               err("probe_scanner: Out of memory.");
+               up(&scn_mutex);
+               return NULL;
+       }
+       memset (scn, 0, sizeof(struct scn_usb_data));
+
+       scn->scn_irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!scn->scn_irq) {
+               kfree(scn);
+               up(&scn_mutex);
+               return NULL;
+       }
+
+       init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
+
+       dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
+
+/* Ok, if we detected an interrupt EP, setup a handler for it */
+       if (have_intr) {
+               dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
+               FILL_INT_URB(scn->scn_irq, dev,
+                            usb_rcvintpipe(dev, have_intr),
+                            &scn->button, 1, irq_scanner, scn,
+                            // endpoint[(int)have_intr].bInterval);
+                            250);
+
+               if (usb_submit_urb(scn->scn_irq, GFP_KERNEL)) {
+                       err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
+                       kfree(scn);
+                       up(&scn_mutex);
+                       return NULL;
+               }
+       }
+
+
+/* Ok, now initialize all the relevant values */
+       if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+               err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
+               kfree(scn);
+               up(&scn_mutex);
+               return NULL;
+       }
+       dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);
+
+       if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+               err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
+               kfree(scn->obuf);
+               kfree(scn);
+               up(&scn_mutex);
+               return NULL;
+       }
+       dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
+       
+
+       switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
+       case 0x04b8:            /* Seiko/Epson */
+               scn->rd_nak_timeout = HZ * 40;
+               break;
+       case 0x055f:            /* Mustek */
+       case 0x0400:            /* Another Mustek */
+       case 0x0ff5:            /* And yet another Mustek */
+               scn->rd_nak_timeout = HZ * 1;
+       default:
+               scn->rd_nak_timeout = RD_NAK_TIMEOUT;
+       }
+
+
+       if (read_timeout > 0) { /* User specified read timeout overrides everything */
+               info("probe_scanner: User specified USB read timeout - %d", read_timeout);
+               scn->rd_nak_timeout = read_timeout;
+       }
+
+
+       scn->bulk_in_ep = have_bulk_in;
+       scn->bulk_out_ep = have_bulk_out;
+       scn->intr_ep = have_intr;
+       scn->present = 1;
+       scn->scn_dev = dev;
+       scn->scn_minor = scn_minor;
+       scn->isopen = 0;
+
+       sprintf(name, "scanner%d", scn->scn_minor);
+       
+       scn->devfs = devfs_register(usb_devfs_handle, name,
+                                   DEVFS_FL_DEFAULT, USB_MAJOR,
+                                   SCN_BASE_MNR + scn->scn_minor,
+                                   S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+                                   S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
+       if (scn->devfs == NULL)
+               dbg("scanner%d: device node registration failed", scn_minor);
+
+       p_scn_table[scn_minor] = scn;
+
+       up(&scn_mutex);
+
+       return scn;
+}
+
+static void
+disconnect_scanner(struct usb_device *dev, void *ptr)
+{
+       struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
+
+       down (&scn_mutex);
+       down (&(scn->sem));
+
+       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]);
+
+       kfree(scn->ibuf);
+       kfree(scn->obuf);
+
+       dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
+       devfs_unregister(scn->devfs);
+       p_scn_table[scn->scn_minor] = NULL;
+       usb_free_urb(scn->scn_irq);
+       up (&(scn->sem));
+       kfree (scn);
+       up (&scn_mutex);
+}
+
+static struct
+usb_driver scanner_driver = {
+       name:           "usbscanner",
+       probe:          probe_scanner,
+       disconnect:     disconnect_scanner,
+       fops:           &usb_scanner_fops,
+       minor:          SCN_BASE_MNR,
+       id_table:       NULL, /* This would be scanner_device_ids, but we
+                                need to check every USB device, in case
+                                we match a user defined vendor/product ID. */
+};
+
+void __exit
+usb_scanner_exit(void)
+{
+       usb_deregister(&scanner_driver);
+}
+
+int __init
+usb_scanner_init (void)
+{
+        if (usb_register(&scanner_driver) < 0)
+                return -1;
+
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+       return 0;
+}
+
+module_init(usb_scanner_init);
+module_exit(usb_scanner_exit);
diff --git a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h
new file mode 100644 (file)
index 0000000..be6c26a
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Driver for USB Scanners (linux-2.4.12)
+ *
+ * Copyright (C) 1999, 2000, 2001 David E. Nelson
+ *
+ * David E. Nelson (dnelson@jump.net)
+ *
+ * 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 the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */ 
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+
+// #define DEBUG
+
+/* Enable this to support the older ioctl interfaces scanners that
+ * a PV8630 Scanner-On-Chip.  The prefered method is the
+ * SCANNER_IOCTL_CTRLMSG ioctl.
+ */
+// #define PV8630 
+
+#define DRIVER_VERSION "0.4.6"
+#define DRIVER_DESC "USB Scanner Driver"
+
+#include <linux/usb.h>
+
+static __s32 vendor=-1, product=-1, read_timeout=0;
+
+MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
+MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+MODULE_PARM(read_timeout, "i");
+MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
+
+
+/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
+// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
+// #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
+
+static struct usb_device_id scanner_device_ids [] = {
+       /* Acer */
+       { USB_DEVICE(0x04a5, 0x2060) }, /* Prisa Acerscan 620U & 640U (!)*/
+       { USB_DEVICE(0x04a5, 0x2040) }, /* Prisa AcerScan 620U (!) */
+       { USB_DEVICE(0x04a5, 0x20c0) },  /* Prisa AcerScan 1240UT */
+       { USB_DEVICE(0x04a5, 0x2022) }, /* Vuego Scan Brisa 340U */
+       { USB_DEVICE(0x04a5, 0x1a20) }, /* Unknown - Oliver Schwartz */
+       { USB_DEVICE(0x04a5, 0x1a2a) }, /* Unknown - Oliver Schwartz */
+       { USB_DEVICE(0x04a5, 0x207e) }, /* Prisa 640BU */
+       { USB_DEVICE(0x04a5, 0x20be) }, /* Unknown - Oliver Schwartz */
+       { USB_DEVICE(0x04a5, 0x20c0) }, /* Unknown - Oliver Schwartz */
+       { USB_DEVICE(0x04a5, 0x20de) }, /* S2W 3300U */
+       { USB_DEVICE(0x04a5, 0x20b0) }, /* Unknown - Oliver Schwartz */
+       { USB_DEVICE(0x04a5, 0x20fe) }, /* Unknown - Oliver Schwartz */
+       /* Agfa */
+       { USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */
+       { USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */
+       { USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/
+       { USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */
+       { USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
+       { USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
+       { USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
+       { USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
+       /* Canon */
+       { USB_DEVICE(0x04a9, 0x2202) }, /* FB620U */
+       { USB_DEVICE(0x04a9, 0x220b) }, /* D646U */
+       { USB_DEVICE(0x04a9, 0x2207) }, /* 1220U */
+       /* Colorado -- See Primax/Colorado below */
+       /* Epson -- See Seiko/Epson below */
+       /* Genius */
+       { USB_DEVICE(0x0458, 0x2001) }, /* ColorPage-Vivid Pro */
+       { USB_DEVICE(0x0458, 0x2007) }, /* ColorPage HR6 V2 */
+       { USB_DEVICE(0x0458, 0x2008) }, /* Unknown */
+       { USB_DEVICE(0x0458, 0x2009) }, /* Unknown */
+       { USB_DEVICE(0x0458, 0x2013) }, /* Unknown */
+       { USB_DEVICE(0x0458, 0x2015) }, /* Unknown  */
+       { USB_DEVICE(0x0458, 0x2016) }, /* Unknown  */
+       /* Hewlett Packard */
+       { USB_DEVICE(0x03f0, 0x0205) }, /* 3300C */
+       { USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
+       { USB_DEVICE(0x03f0, 0x0101) }, /* 4100C */
+       { USB_DEVICE(0x03f0, 0x0105) }, /* 4200C */
+       { USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
+       { USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
+       { USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */
+       //      { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
+       { USB_DEVICE(0x03f0, 0x0201) }, /* 6200C */
+       { USB_DEVICE(0x03f0, 0x0601) }, /* 6300C */
+       { USB_DEVICE(0x03f0, 0x605) },  /* 2200C */
+       /* iVina */
+       { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
+       /* Lifetec */
+       { USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
+       /* Memorex */
+       { USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
+       /* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
+       //      { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */
+       //      { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */
+       //      { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */
+       //      { USB_DEVICE(0x05da, 0x009a) }, /* Phantom C6 */
+       //      { USB_DEVICE(0x05da, 0x00a3) }, /* ScanMaker V6USL */
+       //      { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */
+       //      { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */
+       /* Minolta */
+       //      { USB_DEVICE(0x0638,0x026a) }, /* Minolta Dimage Scan Dual II */
+       /* Mustek */
+       { USB_DEVICE(0x055f, 0x0001) }, /* 1200 CU */
+       { USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 */
+       { USB_DEVICE(0x055f, 0x0002) }, /* 600 CU */
+       { USB_DEVICE(0x055f, 0x0873) }, /* 600 USB */
+       { USB_DEVICE(0x055f, 0x0003) }, /* 1200 USB */
+       { USB_DEVICE(0x055f, 0x0006) }, /* 1200 UB */
+       { USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
+       { USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
+       { USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
+       /* Plustek */
+       { USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12 */
+       { USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro UT24 */
+       { USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x000F) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0010) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0015) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
+       { USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
+       /* Primax/Colorado */
+       { USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */
+       { USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */
+       { USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */
+       { USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */
+       { USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */
+       { USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */
+       { USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */
+       { USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
+       { USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */
+       // { USB_DEVICE(0x0461, 0x0360) },      /* Colorado USB 19200 - undetected endpoint */
+       { USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */
+       { USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */
+       /* Relisis */
+       // { USB_DEVICE(0x0475, 0x0103) },      /* Episode - undetected endpoint */
+       /* Seiko/Epson Corp. */
+       { USB_DEVICE(0x04b8, 0x0101) }, /* Perfection 636U and 636Photo */
+       { USB_DEVICE(0x04b8, 0x0103) }, /* Perfection 610 */
+       { USB_DEVICE(0x04b8, 0x0104) }, /* Perfection 1200U and 1200Photo*/
+       { USB_DEVICE(0x04b8, 0x0106) }, /* Stylus Scan 2500 */
+       { USB_DEVICE(0x04b8, 0x0107) }, /* Expression 1600 */
+       { USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
+       { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
+       { USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
+       { USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
+       { USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
+       { USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
+       /* Umax */
+       { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
+       { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
+       { USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */
+       { USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */
+       /* Visioneer */
+       { USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
+       { USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */
+       { USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */
+       { USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */
+       { USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */
+       { USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */
+       { }                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, scanner_device_ids);
+
+#define IS_EP_BULK(ep)  ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
+#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+#define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
+
+#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
+
+#ifdef DEBUG
+#define SCN_DEBUG(X) X
+#else
+#define SCN_DEBUG(X)
+#endif
+
+#define IBUF_SIZE 32768
+#define OBUF_SIZE 4096
+
+/* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */
+#define RD_NAK_TIMEOUT (10*HZ) /* Default number of X seconds to wait */
+#define RD_EXPIRE 12           /* Number of attempts to wait X seconds */
+
+
+/* FIXME: These are NOT registered ioctls()'s */
+#ifdef PV8630
+#define PV8630_IOCTL_INREQUEST 69
+#define PV8630_IOCTL_OUTREQUEST 70
+#endif /* PV8630 */
+
+
+/* read vendor and product IDs from the scanner */
+#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
+#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
+/* send/recv a control message to the scanner */
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest)
+
+
+#define SCN_MAX_MNR 16         /* We're allocated 16 minors */
+#define SCN_BASE_MNR 48                /* USB Scanners start at minor 48 */
+
+static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
+
+struct scn_usb_data {
+       struct usb_device *scn_dev;
+       devfs_handle_t devfs;   /* devfs device */
+       struct urb *scn_irq;
+       unsigned int ifnum;     /* Interface number of the USB device */
+       int scn_minor;          /* Scanner minor - used in disconnect() */
+       unsigned char button;   /* Front panel buffer */
+       char isopen;            /* Not zero if the device is open */
+       char present;           /* Not zero if device is present */
+       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 sem; /* lock to prevent concurrent reads or writes */
+       unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */
+};
+
+extern devfs_handle_t usb_devfs_handle;
+
+static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
+
+static struct usb_driver scanner_driver;
diff --git a/drivers/usb/net/Makefile.lib b/drivers/usb/net/Makefile.lib
deleted file mode 100644 (file)
index 891c918..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_USB_CATC)         += crc32.o
diff --git a/drivers/usb/scanner/Config.in b/drivers/usb/scanner/Config.in
deleted file mode 100644 (file)
index 8ae0266..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# USB Imageing devices configuration
-#
-comment 'USB Imaging devices'
-dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
-dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
-dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
-dep_tristate '  HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
-
-# Turn on CONFIG_USB_IMAGE if any of the drivers are compiled into the kernel to
-# make our Makefile logic a bit simpler
-if [ "$CONFIG_USB_DC2XX" = "y" -o "$CONFIG_USB_MDC800" = "y" ]; then
-   define_bool CONFIG_USB_IMAGE y
-fi
-if [ "$CONFIG_USB_SCANNER" = "y" -o "$CONFIG_USB_MICROTEK" = "y" -o "$CONFIG_USB_HPUSBSCSI" = "y" ]; then
-   define_bool CONFIG_USB_IMAGE y
-fi
-   
diff --git a/drivers/usb/scanner/Makefile b/drivers/usb/scanner/Makefile
deleted file mode 100644 (file)
index ee46e08..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Makefile for USB Image drivers
-#
-
-O_TARGET       := usb-image.o
-
-obj-$(CONFIG_USB_DC2XX)                += dc2xx.o
-obj-$(CONFIG_USB_MDC800)       += mdc800.o
-obj-$(CONFIG_USB_HPUSBSCSI)    += hpusbscsi.o
-obj-$(CONFIG_USB_MICROTEK)     += microtek.o
-obj-$(CONFIG_USB_SCANNER)      += scanner.o
-
-include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/scanner/dc2xx.c b/drivers/usb/scanner/dc2xx.c
deleted file mode 100644 (file)
index 08c7485..0000000
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.net>
- *
- * 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 the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
- * USB driver for Kodak DC-2XX series digital still cameras
- *
- * The protocol here is the same as the one going over a serial line, but
- * it uses USB for speed.  Set up /dev/kodak, get gphoto (www.gphoto.org),
- * and have fun!
- *
- * This should also work for a number of other digital (non-Kodak) cameras,
- * by adding the vendor and product IDs to the table below.  They'll need
- * to be the sort using USB just as a fast bulk data channel.
- */
-
-/*
- * HISTORY
- *
- * 26 August, 1999 -- first release (0.1), works with my DC-240.
- *     The DC-280 (2Mpixel) should also work, but isn't tested.
- *     If you use gphoto, make sure you have the USB updates.
- *     Lives in a 2.3.14 or so Linux kernel, in drivers/usb.
- * 31 August, 1999 -- minor update to recognize DC-260 and handle
- *     its endpoints being in a different order.  Note that as
- *     of gPhoto 0.36pre, the USB updates are integrated.
- * 12 Oct, 1999 -- handle DC-280 interface class (0xff not 0x0);
- *     added timeouts to bulk_msg calls.  Minor updates, docs.
- * 03 Nov, 1999 -- update for 2.3.25 kernel API changes.
- * 08 Jan, 2000 .. multiple camera support
- * 12 Aug, 2000 .. add some real locking, remove an Oops
- * 10 Oct, 2000 .. usb_device_id table created. 
- * 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter
- * 08 Apr, 2001 .. Identify version on module load. gb
- *
- * Thanks to:  the folk who've provided USB product IDs, sent in
- * patches, and shared their successes!
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/devfs_fs_kernel.h>
-
-#ifdef CONFIG_USB_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-#include <linux/usb.h>
-
-
-/* /dev/usb dir. */
-extern devfs_handle_t usb_devfs_handle;                        
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.0.0"
-#define DRIVER_AUTHOR "David Brownell, <dbrownell@users.sourceforge.net>"
-#define DRIVER_DESC "USB Camera Driver for Kodak DC-2xx series cameras"
-
-
-/* current USB framework handles max of 16 USB devices per driver */
-#define        MAX_CAMERAS             16
-
-/* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
-#define        USB_CAMERA_MINOR_BASE   80
-
-
-// XXX remove packet size limit, now that bulk transfers seem fixed
-
-/* Application protocol limit is 0x8002; USB has disliked that limit! */
-#define        MAX_PACKET_SIZE         0x2000          /* e.g. image downloading */
-
-#define        MAX_READ_RETRY          5               /* times to retry reads */
-#define        MAX_WRITE_RETRY         5               /* times to retry writes */
-#define        RETRY_TIMEOUT           (HZ)            /* sleep between retries */
-
-
-/* table of cameras that work through this driver */
-static struct usb_device_id camera_table [] = {
-       /* These have the same application level protocol */  
-       { USB_DEVICE(0x040a, 0x0120) },         // Kodak DC-240
-       { USB_DEVICE(0x040a, 0x0130) },         // Kodak DC-280
-       { USB_DEVICE(0x040a, 0x0131) },         // Kodak DC-5000
-       { USB_DEVICE(0x040a, 0x0132) },         // Kodak DC-3400
-
-       /* These have a different application level protocol which
-        * is part of the Flashpoint "DigitaOS".  That supports some
-        * non-camera devices, and some non-Kodak cameras.
-        * Use this driver to get USB and "OpenDis" to talk.
-        */  
-       { USB_DEVICE(0x040a, 0x0100) },         // Kodak DC-220
-       { USB_DEVICE(0x040a, 0x0110) },         // Kodak DC-260
-       { USB_DEVICE(0x040a, 0x0111) },         // Kodak DC-265
-       { USB_DEVICE(0x040a, 0x0112) },         // Kodak DC-290
-       { USB_DEVICE(0xf003, 0x6002) },         // HP PhotoSmart C500
-       { USB_DEVICE(0x03f0, 0x4102) },         // HP PhotoSmart C618
-       { USB_DEVICE(0x0a17, 0x1001) },         // Pentax EI-200
-
-       /* Other USB devices may well work here too, so long as they
-        * just stick to half duplex bulk packet exchanges.  That
-        * means, among other things, no iso or interrupt endpoints.
-        */
-
-       { }                                     /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, camera_table);
-
-
-struct camera_state {
-       struct usb_device       *dev;           /* USB device handle */
-       int                     inEP;           /* read endpoint */
-       int                     outEP;          /* write endpoint */
-       const struct usb_device_id      *info;  /* DC-240, etc */
-       int                     subminor;       /* which minor dev #? */
-       struct semaphore        sem;            /* locks this struct */
-
-       /* this is non-null iff the device is open */
-       char                    *buf;           /* buffer for I/O */
-
-       devfs_handle_t          devfs;          /* devfs device */
-
-       /* always valid */
-       wait_queue_head_t       wait;           /* for timed waits */
-};
-
-/* Support multiple cameras, possibly of different types.  */
-static struct camera_state *minor_data [MAX_CAMERAS];
-
-/* make this an rwlock if contention becomes an issue */
-static DECLARE_MUTEX (state_table_mutex);
-
-static ssize_t camera_read (struct file *file,
-       char *buf, size_t len, loff_t *ppos)
-{
-       struct camera_state     *camera;
-       int                     retries;
-       int                     retval = 0;
-
-       if (len > MAX_PACKET_SIZE)
-               return -EINVAL;
-
-       camera = (struct camera_state *) file->private_data;
-       down (&camera->sem);
-       if (!camera->dev) {
-               up (&camera->sem);
-               return -ENODEV;
-       }
-
-       /* Big reads are common, for image downloading.  Smaller ones
-        * are also common (even "directory listing" commands don't
-        * send very much data).  We preserve packet boundaries here,
-        * they matter in the application protocol.
-        */
-       for (retries = 0; retries < MAX_READ_RETRY; retries++) {
-               int                     count;
-
-               if (signal_pending (current)) {
-                       retval = -EINTR;
-                       break;
-               }
-
-               retval = usb_bulk_msg (camera->dev,
-                         usb_rcvbulkpipe (camera->dev, camera->inEP),
-                         camera->buf, len, &count, HZ*10);
-
-               dbg ("read (%Zd) - 0x%x %d", len, retval, count);
-
-               if (!retval) {
-                       if (copy_to_user (buf, camera->buf, count))
-                               retval = -EFAULT;
-                       else
-                               retval = count;
-                       break;
-               }
-               if (retval != -ETIMEDOUT)
-                       break;
-               interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT);
-
-               dbg ("read (%Zd) - retry", len);
-       }
-       up (&camera->sem);
-       return retval;
-}
-
-static ssize_t camera_write (struct file *file,
-       const char *buf, size_t len, loff_t *ppos)
-{
-       struct camera_state     *camera;
-       ssize_t                 bytes_written = 0;
-
-       if (len > MAX_PACKET_SIZE)
-               return -EINVAL;
-
-       camera = (struct camera_state *) file->private_data;
-       down (&camera->sem);
-       if (!camera->dev) {
-               up (&camera->sem);
-               return -ENODEV;
-       }
-       
-       /* most writes will be small: simple commands, sometimes with
-        * parameters.  putting images (like borders) into the camera
-        * would be the main use of big writes.
-        */
-       while (len > 0) {
-               char            *obuf = camera->buf;
-               int             maxretry = MAX_WRITE_RETRY;
-               unsigned long   copy_size, thistime;
-
-               /* it's not clear that retrying can do any good ... or that
-                * fragmenting application packets into N writes is correct.
-                */
-               thistime = copy_size = len;
-               if (copy_from_user (obuf, buf, copy_size)) {
-                       bytes_written = -EFAULT;
-                       break;
-               }
-               while (thistime) {
-                       int             result;
-                       int             count;
-
-                       if (signal_pending (current)) {
-                               if (!bytes_written)
-                                       bytes_written = -EINTR;
-                               goto done;
-                       }
-
-                       result = usb_bulk_msg (camera->dev,
-                                usb_sndbulkpipe (camera->dev, camera->outEP),
-                                obuf, thistime, &count, HZ*10);
-
-                       if (result)
-                               dbg ("write USB err - %d", result);
-
-                       if (count) {
-                               obuf += count;
-                               thistime -= count;
-                               maxretry = MAX_WRITE_RETRY;
-                               continue;
-                       } else if (!result)
-                               break;
-                               
-                       if (result == -ETIMEDOUT) {     /* NAK - delay a bit */
-                               if (!maxretry--) {
-                                       if (!bytes_written)
-                                               bytes_written = -ETIME;
-                                       goto done;
-                               }
-                                interruptible_sleep_on_timeout (&camera->wait,
-                                       RETRY_TIMEOUT);
-                               continue;
-                       } 
-                       if (!bytes_written)
-                               bytes_written = -EIO;
-                       goto done;
-               }
-               bytes_written += copy_size;
-               len -= copy_size;
-               buf += copy_size;
-       }
-done:
-       up (&camera->sem);
-       dbg ("wrote %Zd", bytes_written); 
-       return bytes_written;
-}
-
-static int camera_open (struct inode *inode, struct file *file)
-{
-       struct camera_state     *camera = NULL;
-       int                     subminor;
-       int                     value = 0;
-
-       down (&state_table_mutex);
-       subminor = minor (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
-       if (subminor < 0 || subminor >= MAX_CAMERAS
-                       || !(camera = minor_data [subminor])) {
-               up (&state_table_mutex);
-               return -ENODEV;
-       }
-       down (&camera->sem);
-       up (&state_table_mutex);
-
-       if (camera->buf) {
-               value = -EBUSY;
-               goto done;
-       }
-
-       if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) {
-               value = -ENOMEM;
-               goto done;
-       }
-
-       dbg ("open #%d", subminor); 
-
-       file->private_data = camera;
-done:
-       up (&camera->sem);
-       return value;
-}
-
-static int camera_release (struct inode *inode, struct file *file)
-{
-       struct camera_state     *camera;
-       int                     subminor;
-
-       camera = (struct camera_state *) file->private_data;
-       down (&state_table_mutex);
-       down (&camera->sem);
-
-       if (camera->buf) {
-               kfree (camera->buf);
-               camera->buf = 0;
-       }
-       subminor = camera->subminor;
-
-       /* If camera was unplugged with open file ... */
-       if (!camera->dev) {
-               minor_data [subminor] = NULL;
-               kfree (camera);
-       } else
-               up (&camera->sem);
-       
-       up (&state_table_mutex);
-
-       dbg ("close #%d", subminor); 
-
-       return 0;
-}
-
-       /* XXX should define some ioctls to expose camera type
-        * to applications ... what USB exposes should suffice.
-        * apps should be able to see the camera type.
-        */
-static /* const */ struct file_operations usb_camera_fops = {
-           /* Uses GCC initializer extension; simpler to maintain */
-       owner:          THIS_MODULE,
-       read:           camera_read,
-       write:          camera_write,
-       open:           camera_open,
-       release:        camera_release,
-};
-
-
-
-static void *
-camera_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *camera_info)
-{
-       int                             i;
-       struct usb_interface_descriptor *interface;
-       struct usb_endpoint_descriptor  *endpoint;
-       int                             direction, ep;
-       char name[8];
-       struct camera_state             *camera = NULL;
-
-
-       /* these have one config, one interface */
-       if (dev->descriptor.bNumConfigurations != 1
-                       || dev->config[0].bNumInterfaces != 1) {
-               dbg ("Bogus camera config info");
-               return NULL;
-       }
-
-       /* models differ in how they report themselves */
-       interface = &dev->actconfig->interface[ifnum].altsetting[0];
-       if ((interface->bInterfaceClass != USB_CLASS_PER_INTERFACE
-               && interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC)
-                       || interface->bInterfaceSubClass != 0
-                       || interface->bInterfaceProtocol != 0
-                       || interface->bNumEndpoints != 2
-                       ) {
-               dbg ("Bogus camera interface info");
-               return NULL;
-       }
-
-
-       /* select "subminor" number (part of a minor number) */
-       down (&state_table_mutex);
-       for (i = 0; i < MAX_CAMERAS; i++) {
-               if (!minor_data [i])
-                       break;
-       }
-       if (i >= MAX_CAMERAS) {
-               info ("Ignoring additional USB Camera");
-               goto bye;
-       }
-
-       /* allocate & init camera state */
-       camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL);
-       if (!camera) {
-               err ("no memory!");
-               goto bye;
-       }
-
-       init_MUTEX (&camera->sem);
-       camera->info = camera_info;
-       camera->subminor = i;
-       camera->buf = NULL;
-       init_waitqueue_head (&camera->wait);
-
-
-       /* get input and output endpoints (either order) */
-       endpoint = interface->endpoint;
-       camera->outEP = camera->inEP =  -1;
-
-       ep = endpoint [0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       direction = endpoint [0].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-       if (direction == USB_DIR_IN)
-               camera->inEP = ep;
-       else
-               camera->outEP = ep;
-
-       ep = endpoint [1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       direction = endpoint [1].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-       if (direction == USB_DIR_IN)
-               camera->inEP = ep;
-       else
-               camera->outEP = ep;
-
-       if (camera->outEP == -1 || camera->inEP == -1
-                       || endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK
-                       || endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK
-                       ) {
-               dbg ("Bogus endpoints");
-               goto error;
-       }
-
-       info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor,
-               USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor);
-
-       camera->dev = dev;
-       usb_inc_dev_use (dev);
-
-       /* If we have devfs, register the device */
-       sprintf(name, "dc2xx%d", camera->subminor);
-       camera->devfs = devfs_register(usb_devfs_handle, name,
-                                      DEVFS_FL_DEFAULT, USB_MAJOR,
-                                      USB_CAMERA_MINOR_BASE + camera->subminor,
-                                      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
-                                      S_IWGRP, &usb_camera_fops, NULL);
-
-       goto bye;
-
-error:
-       minor_data [camera->subminor] = NULL;
-       kfree (camera);
-       camera = NULL;
-bye:
-       up (&state_table_mutex);
-       return camera;
-}
-
-static void camera_disconnect(struct usb_device *dev, void *ptr)
-{
-       struct camera_state     *camera = (struct camera_state *) ptr;
-       int                     subminor = camera->subminor;
-
-       down (&state_table_mutex);
-       down (&camera->sem);
-
-       devfs_unregister(camera->devfs); 
-
-       /* If camera's not opened, we can clean up right away.
-        * Else apps see a disconnect on next I/O; the release cleans.
-        */
-       if (!camera->buf) {
-               minor_data [subminor] = NULL;
-               kfree (camera);
-               camera = NULL;
-       } else
-               camera->dev = NULL;
-
-       info ("USB Camera #%d disconnected", subminor);
-       usb_dec_dev_use (dev);
-
-       if (camera != NULL)
-               up (&camera->sem);
-       up (&state_table_mutex);
-}
-
-static /* const */ struct usb_driver camera_driver = {
-       name:           "dc2xx",
-
-       id_table:       camera_table,
-       probe:          camera_probe,
-       disconnect:     camera_disconnect,
-
-       fops:           &usb_camera_fops,
-       minor:          USB_CAMERA_MINOR_BASE
-};
-
-
-int __init usb_dc2xx_init(void)
-{
-       if (usb_register (&camera_driver) < 0)
-               return -1;
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-       return 0;
-}
-
-void __exit usb_dc2xx_cleanup(void)
-{
-       usb_deregister (&camera_driver);
-}
-
-module_init (usb_dc2xx_init);
-module_exit (usb_dc2xx_cleanup);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/scanner/hpusbscsi.c b/drivers/usb/scanner/hpusbscsi.c
deleted file mode 100644 (file)
index 4cbf59a..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/usb.h>
-#include <asm/atomic.h>
-#include <linux/blk.h>
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "../../scsi/sd.h"
-
-#include "hpusbscsi.h"
-
-#define DEBUG(x...) \
-       printk( KERN_DEBUG x )
-
-static char *states[]={"FREE", "BEGINNING", "WORKING", "ERROR", "WAIT", "PREMATURE"};
-
-#define TRACE_STATE printk(KERN_DEBUG"hpusbscsi->state = %s at line %d\n", states[hpusbscsi->state], __LINE__)
-
-/* global variables */
-
-struct list_head hpusbscsi_devices;
-//LIST_HEAD(hpusbscsi_devices);
-
-/* USB related parts */
-
-static void *
-hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
-                    const struct usb_device_id *id)
-{
-       struct hpusbscsi *new;
-       struct usb_interface_descriptor *altsetting =
-               &(dev->actconfig->interface[interface].altsetting[0]);
-
-       int i, result;
-
-       /* basic check */
-
-       if (altsetting->bNumEndpoints != 3) {
-               printk (KERN_ERR "Wrong number of endpoints\n");
-               return NULL;
-       }
-
-       /* descriptor allocation */
-
-       new =
-               (struct hpusbscsi *) kmalloc (sizeof (struct hpusbscsi),
-                                             GFP_KERNEL);
-       if (new == NULL)
-               return NULL;
-       DEBUG ("Allocated memory\n");
-       memset (new, 0, sizeof (struct hpusbscsi));
-       new->dataurb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!new->dataurb) {
-               kfree (new);
-               return NULL;
-       }
-       new->controlurb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!new->controlurb) {
-               usb_free_urb (new->dataurb);
-               kfree (new);
-               return NULL;
-       }
-       new->dev = dev;
-       init_waitqueue_head (&new->pending);
-       init_waitqueue_head (&new->deathrow);
-       INIT_LIST_HEAD (&new->lh);
-
-
-
-       /* finding endpoints */
-
-       for (i = 0; i < altsetting->bNumEndpoints; i++) {
-               if (
-                   (altsetting->endpoint[i].
-                    bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-                   USB_ENDPOINT_XFER_BULK) {
-                       if (altsetting->endpoint[i].
-                           bEndpointAddress & USB_DIR_IN) {
-                               new->ep_in =
-                                       altsetting->endpoint[i].
-                                       bEndpointAddress &
-                                       USB_ENDPOINT_NUMBER_MASK;
-                       } else {
-                               new->ep_out =
-                                       altsetting->endpoint[i].
-                                       bEndpointAddress &
-                                       USB_ENDPOINT_NUMBER_MASK;
-                       }
-               } else {
-                       new->ep_int =
-                               altsetting->endpoint[i].
-                               bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-                       new->interrupt_interval= altsetting->endpoint[i].bInterval;
-               }
-       }
-
-       /* USB initialisation magic for the simple case */
-
-       result = usb_set_interface (dev, altsetting->bInterfaceNumber, 0);
-
-       switch (result) {
-       case 0:         /* no error */
-               break;
-
-       case -EPIPE:
-               usb_clear_halt (dev, usb_sndctrlpipe (dev, 0));
-               break;
-
-       default:
-               printk (KERN_ERR "unknown error %d from usb_set_interface\n",
-                        result);
-               goto err_out;
-       }
-
-       /* making a template for the scsi layer to fake detection of a scsi device */
-
-       memcpy (&(new->ctempl), &hpusbscsi_scsi_host_template,
-               sizeof (hpusbscsi_scsi_host_template));
-       (struct hpusbscsi *) new->ctempl.proc_dir = new;
-       new->ctempl.module = THIS_MODULE;
-
-       if (scsi_register_host(&new->ctempl))
-               goto err_out;
-
-       new->sense_command[0] = REQUEST_SENSE;
-       new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
-
-       /* adding to list for module unload */
-       list_add (&hpusbscsi_devices, &new->lh);
-
-       return new;
-
-      err_out:
-       usb_free_urb (new->controlurb);
-       usb_free_urb (new->dataurb);
-       kfree (new);
-       return NULL;
-}
-
-static void
-hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
-{
-                 usb_unlink_urb((((struct hpusbscsi *) ptr)->controlurb));
-       ((struct hpusbscsi *) ptr)->dev = NULL;
-}
-
-static struct usb_device_id hpusbscsi_usb_ids[] = {
-       {USB_DEVICE (0x03f0, 0x0701)},  /* HP 53xx */
-       {USB_DEVICE (0x03f0, 0x0801)},  /* HP 7400 */
-       {USB_DEVICE (0x0638, 0x026a)},  /*Scan Dual II */
-       {}                      /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, hpusbscsi_usb_ids);
-MODULE_LICENSE("GPL");
-
-
-static struct usb_driver hpusbscsi_usb_driver = {
-       name:"hpusbscsi",
-       probe:hpusbscsi_usb_probe,
-       disconnect:hpusbscsi_usb_disconnect,
-       id_table:hpusbscsi_usb_ids,
-};
-
-/* module initialisation */
-
-int __init
-hpusbscsi_init (void)
-{
-       int result;
-
-       INIT_LIST_HEAD (&hpusbscsi_devices);
-       DEBUG ("Driver loaded\n");
-
-       if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) {
-               printk (KERN_ERR "hpusbscsi: driver registration failed\n");
-               return -1;
-       } else {
-               return 0;
-       }
-}
-
-void __exit
-hpusbscsi_exit (void)
-{
-       struct list_head *tmp;
-       struct list_head *old;
-       struct hpusbscsi * o;
-
-       for (tmp = hpusbscsi_devices.next; tmp != &hpusbscsi_devices;/*nothing */) {
-               old = tmp;
-               tmp = tmp->next;
-               o = (struct hpusbscsi *)old;
-               usb_unlink_urb(o->controlurb);
-               scsi_unregister_host(&o->ctempl);
-               usb_free_urb(o->controlurb);
-               usb_free_urb(o->dataurb);
-               kfree(old);
-       }
-
-       usb_deregister (&hpusbscsi_usb_driver);
-}
-
-module_init (hpusbscsi_init);
-module_exit (hpusbscsi_exit);
-
-/* interface to the scsi layer */
-
-static int
-hpusbscsi_scsi_detect (struct SHT *sht)
-{
-       /* Whole function stolen from usb-storage */
-
-       struct hpusbscsi *desc = (struct hpusbscsi *) sht->proc_dir;
-       /* What a hideous hack! */
-
-       char local_name[48];
-
-
-       /* set up the name of our subdirectory under /proc/scsi/ */
-       sprintf (local_name, "hpusbscsi-%d", desc->number);
-       sht->proc_name = kmalloc (strlen (local_name) + 1, GFP_KERNEL);
-       /* FIXME: where is this freed ? */
-
-       if (!sht->proc_name) {
-               return 0;
-       }
-
-       strcpy (sht->proc_name, local_name);
-
-       sht->proc_dir = NULL;
-
-       /* build and submit an interrupt URB for status byte handling */
-       FILL_INT_URB(desc->controlurb,
-                       desc->dev,
-                       usb_rcvintpipe(desc->dev,desc->ep_int),
-                       &desc->scsi_state_byte,
-                       1,
-                       control_interrupt_callback,
-                       desc,
-                       desc->interrupt_interval
-       );
-
-       if ( 0  >  usb_submit_urb(desc->controlurb, GFP_KERNEL)) {
-               kfree(sht->proc_name);
-               return 0;
-       }
-
-       /* In host->hostdata we store a pointer to desc */
-       desc->host = scsi_register (sht, sizeof (desc));
-       if (desc->host == NULL) {
-               kfree (sht->proc_name);
-               usb_unlink_urb(desc->controlurb);
-               return 0;
-       }
-       desc->host->hostdata[0] = (unsigned long) desc;
-
-
-       return 1;
-}
-
-static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
-{
-       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
-       usb_urb_callback usb_callback;
-       int res;
-
-       hpusbscsi->use_count++;
-
-       /* we don't answer for anything but our single device on any faked host controller */
-       if ( srb->device->lun || srb->device->id || srb->device->channel ) {
-               if (callback) {
-                       srb->result = DID_BAD_TARGET;
-                       callback(srb);
-               }
-                       goto out;
-       }
-
-       /* Now we need to decide which callback to give to the urb we send the command with */
-
-       if (!srb->bufflen) {
-               if (srb->cmnd[0] == REQUEST_SENSE){
-                       hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
-                       usb_callback = request_sense_callback;
-               } else {
-                       usb_callback = simple_command_callback;
-               }
-       } else {
-               if (likely(srb->use_sg)) {
-                       usb_callback = scatter_gather_callback;
-                       hpusbscsi->fragment = 0;
-               } else {
-                       usb_callback = simple_payload_callback;
-               }
-               /* Now we find out which direction data is to be transfered in */
-               hpusbscsi->current_data_pipe = DIRECTION_IS_IN(srb->cmnd[0]) ?
-                       usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in)
-               :
-                       usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out)
-               ;
-       }
-
-
-       TRACE_STATE;
-
-        /* We zero the sense buffer to avoid confusing user space */
-        memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
-       hpusbscsi->state = HP_STATE_BEGINNING;
-       TRACE_STATE;
-
-       /* We prepare the urb for writing out the scsi command */
-       FILL_BULK_URB(
-               hpusbscsi->dataurb,
-               hpusbscsi->dev,
-               usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
-               srb->cmnd,
-               srb->cmd_len,
-               usb_callback,
-               hpusbscsi
-       );
-       hpusbscsi->scallback = callback;
-       hpusbscsi->srb = srb;
-
-       res = usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC);
-       if (unlikely(res)) {
-               hpusbscsi->state = HP_STATE_FREE;
-               TRACE_STATE;
-               if (likely(callback != NULL)) {
-                       srb->result = DID_ERROR;
-                       callback(srb);
-               }
-       }
-
-out:
-       hpusbscsi->use_count--;
-       return 0;
-}
-
-static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb)
-{
-       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
-
-       printk(KERN_DEBUG"SCSI reset requested.\n");
-       //usb_reset_device(hpusbscsi->dev);
-       //printk(KERN_DEBUG"SCSI reset completed.\n");
-       hpusbscsi->state = HP_STATE_FREE;
-
-       return 0;
-}
-
-static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
-{
-       struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
-       printk(KERN_DEBUG"Requested is canceled.\n");
-
-       usb_unlink_urb(hpusbscsi->dataurb);
-       usb_unlink_urb(hpusbscsi->controlurb);
-       hpusbscsi->state = HP_STATE_FREE;
-
-       return SCSI_ABORT_PENDING;
-}
-
-/* usb interrupt handlers - they are all running IN INTERRUPT ! */
-
-static void handle_usb_error (struct hpusbscsi *hpusbscsi)
-{
-       if (likely(hpusbscsi->scallback != NULL)) {
-               hpusbscsi->srb->result = DID_ERROR;
-               hpusbscsi->scallback(hpusbscsi->srb);
-       }
-       hpusbscsi->state = HP_STATE_FREE;
-}
-
-static void  control_interrupt_callback (struct urb *u)
-{
-       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-       u8 scsi_state;
-
-DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
-       if(unlikely(u->status < 0)) {
-                if (likely(hpusbscsi->state != HP_STATE_FREE))
-                        handle_usb_error(hpusbscsi);
-               return;
-       }
-
-       scsi_state = hpusbscsi->scsi_state_byte;
-       if (hpusbscsi->state != HP_STATE_ERROR) {
-               hpusbscsi->srb->result &= SCSI_ERR_MASK;
-               hpusbscsi->srb->result |= scsi_state;
-       }
-
-       if (scsi_state == CHECK_CONDITION << 1) {
-               if (hpusbscsi->state == HP_STATE_WAIT) {
-                       issue_request_sense(hpusbscsi);
-               } else {
-                       /* we request sense after an eventual data transfer */
-                       hpusbscsi->state = HP_STATE_ERROR;
-               }
-       }
-
-       if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1 )
-               /* we do a callback to the scsi layer if and only if all data has been transfered */
-               hpusbscsi->scallback(hpusbscsi->srb);
-
-       TRACE_STATE;
-       switch (hpusbscsi->state) {
-       case HP_STATE_WAIT:
-               hpusbscsi->state = HP_STATE_FREE;
-       TRACE_STATE;
-               break;
-       case HP_STATE_WORKING:
-       case HP_STATE_BEGINNING:
-               hpusbscsi->state = HP_STATE_PREMATURE;
-       TRACE_STATE;
-               break;
-       case HP_STATE_ERROR:
-               break;
-       default:
-               printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
-       TRACE_STATE;
-               hpusbscsi->state = HP_STATE_FREE;
-       TRACE_STATE;
-               break;
-       }
-}
-
-static void simple_command_callback(struct urb *u)
-{
-       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-       if (unlikely(u->status<0)) {
-               handle_usb_error(hpusbscsi);
-               return;
-        }
-       TRACE_STATE;
-       if (hpusbscsi->state != HP_STATE_PREMATURE) {
-               TRACE_STATE;
-               hpusbscsi->state = HP_STATE_WAIT;
-       } else {
-               if (likely(hpusbscsi->scallback != NULL))
-                       hpusbscsi->scallback(hpusbscsi->srb);
-               hpusbscsi->state = HP_STATE_FREE;
-       TRACE_STATE;
-       }
-}
-
-static void scatter_gather_callback(struct urb *u)
-{
-       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-        struct scatterlist *sg = hpusbscsi->srb->buffer;
-        usb_urb_callback callback;
-        int res;
-
-        DEBUG("Going through scatter/gather\n");
-        if (unlikely(u->status < 0)) {
-                handle_usb_error(hpusbscsi);
-                return;
-        }
-
-        if (hpusbscsi->fragment + 1 != hpusbscsi->srb->use_sg)
-                callback = scatter_gather_callback;
-        else
-                callback = simple_done;
-
-       TRACE_STATE;
-        if (hpusbscsi->state != HP_STATE_PREMATURE)
-               hpusbscsi->state = HP_STATE_WORKING;
-       TRACE_STATE;
-
-        FILL_BULK_URB(
-                u,
-                hpusbscsi->dev,
-                hpusbscsi->current_data_pipe,
-                page_address(sg[hpusbscsi->fragment].page) +
-               sg[hpusbscsi->fragment].offset,
-                sg[hpusbscsi->fragment++].length,
-                callback,
-                hpusbscsi
-        );
-
-        res = usb_submit_urb(u, GFP_ATOMIC);
-        if (unlikely(res))
-                handle_usb_error(hpusbscsi);
-       TRACE_STATE;
-}
-
-static void simple_done (struct urb *u)
-{
-       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-
-        if (unlikely(u->status < 0)) {
-                handle_usb_error(hpusbscsi);
-                return;
-        }
-        DEBUG("Data transfer done\n");
-       TRACE_STATE;
-       if (hpusbscsi->state != HP_STATE_PREMATURE) {
-               if (unlikely(u->status < 0)) {
-                       handle_usb_error(hpusbscsi);
-               } else {
-                       if (hpusbscsi->state != HP_STATE_ERROR) {
-                               hpusbscsi->state = HP_STATE_WAIT;
-                       } else {
-                               issue_request_sense(hpusbscsi);
-                       }                       
-               }
-       } else {
-               if (likely(hpusbscsi->scallback != NULL))
-                       hpusbscsi->scallback(hpusbscsi->srb);
-               hpusbscsi->state = HP_STATE_FREE;
-       }
-}
-
-static void simple_payload_callback (struct urb *u)
-{
-       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-       int res;
-
-       if (unlikely(u->status<0)) {
-                handle_usb_error(hpusbscsi);
-               return;
-        }
-
-       FILL_BULK_URB(
-               u,
-               hpusbscsi->dev,
-               hpusbscsi->current_data_pipe,
-               hpusbscsi->srb->buffer,
-               hpusbscsi->srb->bufflen,
-               simple_done,
-               hpusbscsi
-       );
-
-       res = usb_submit_urb(u, GFP_ATOMIC);
-       if (unlikely(res)) {
-                handle_usb_error(hpusbscsi);
-               return;
-        }
-       TRACE_STATE;
-       if (hpusbscsi->state != HP_STATE_PREMATURE) {
-               hpusbscsi->state = HP_STATE_WORKING;
-       TRACE_STATE;
-       } 
-}
-
-static void request_sense_callback (struct urb *u)
-{
-       struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-
-       if (u->status<0) {
-                handle_usb_error(hpusbscsi);
-               return;
-        }
-
-       FILL_BULK_URB(
-               u,
-               hpusbscsi->dev,
-               hpusbscsi->current_data_pipe,
-               hpusbscsi->srb->sense_buffer,
-               SCSI_SENSE_BUFFERSIZE,
-               simple_done,
-               hpusbscsi
-       );
-
-       if (0 > usb_submit_urb(u, GFP_ATOMIC)) {
-               handle_usb_error(hpusbscsi);
-               return;
-       }
-       if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR)
-               hpusbscsi->state = HP_STATE_WORKING;
-}
-
-static void issue_request_sense (struct hpusbscsi *hpusbscsi)
-{
-       FILL_BULK_URB(
-               hpusbscsi->dataurb,
-               hpusbscsi->dev,
-               usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out),
-               &hpusbscsi->sense_command,
-               SENSE_COMMAND_SIZE,
-               request_sense_callback,
-               hpusbscsi
-       );
-
-       hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
-
-       if (0 > usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC)) {
-               handle_usb_error(hpusbscsi);
-       }
-}
-
diff --git a/drivers/usb/scanner/hpusbscsi.h b/drivers/usb/scanner/hpusbscsi.h
deleted file mode 100644 (file)
index 87d1d7e..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Header file for the hpusbscsi driver */
-/* (C) Copyright 2001 Oliver Neukum */
-/* sponsored by the Linux Usb Project */
-/* large parts based on or taken from code by John Fremlin and Matt Dharm */
-/* this file is licensed under the GPL */
-
-/* A big thanks to Jose for untiring testing */
-
-typedef void (*usb_urb_callback) (struct urb *);
-typedef void (*scsi_callback)(Scsi_Cmnd *);
-
-#define SENSE_COMMAND_SIZE 6
-#define HPUSBSCSI_SENSE_LENGTH 0x16
-
-struct hpusbscsi
-{
-        struct list_head lh;
-        struct usb_device *dev; /* NULL indicates unplugged device */
-        int ep_out;
-        int ep_in;
-        int ep_int;
-        int interrupt_interval;
-
-        struct Scsi_Host *host;
-        Scsi_Host_Template ctempl;
-        int number;
-       scsi_callback scallback;
-       Scsi_Cmnd *srb;
-       u8 sense_command[SENSE_COMMAND_SIZE];
-
-        int use_count;
-        wait_queue_head_t pending;
-        wait_queue_head_t deathrow;
-
-        struct urb *dataurb;
-        struct urb *controlurb;
-        int fragment;
-
-        int state;
-        int current_data_pipe;
-
-        u8 scsi_state_byte;
-};
-
-#define SCSI_ERR_MASK ~0x3fu
-
-static const unsigned char scsi_command_direction[256/8] = {
-       0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
-       0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-#define DIRECTION_IS_IN(x) ((scsi_command_direction[x>>3] >> (x & 7)) & 1)
-
-static int hpusbscsi_scsi_detect (struct SHT * sht);
-static void simple_command_callback(struct urb *u);
-static void scatter_gather_callback(struct urb *u);
-static void simple_payload_callback (struct urb *u);
-static void request_sense_callback (struct urb *u);
-static void control_interrupt_callback (struct urb *u);
-static void simple_done (struct urb *u);
-static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
-static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
-static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
-static void issue_request_sense (struct hpusbscsi *hpusbscsi);
-
-static Scsi_Host_Template hpusbscsi_scsi_host_template = {
-       name:           "hpusbscsi",
-       detect:         hpusbscsi_scsi_detect,
-//     release:        hpusbscsi_scsi_release,
-       queuecommand:   hpusbscsi_scsi_queuecommand,
-
-       eh_abort_handler:       hpusbscsi_scsi_abort,
-       eh_host_reset_handler:  hpusbscsi_scsi_host_reset,
-
-       sg_tablesize:           SG_ALL,
-       can_queue:              1,
-       this_id:                -1,
-       cmd_per_lun:            1,
-       present:                0,
-       unchecked_isa_dma:      FALSE,
-       use_clustering:         TRUE,
-       emulated:               TRUE
-};
-
-/* defines for internal driver state */
-#define HP_STATE_FREE                 0  /*ready for next request */
-#define HP_STATE_BEGINNING      1  /*command being transfered */
-#define HP_STATE_WORKING         2  /* data transfer stage */
-#define HP_STATE_ERROR             3  /* error has been reported */
-#define HP_STATE_WAIT                 4  /* waiting for status transfer */
-#define HP_STATE_PREMATURE              5 /* status prematurely reported */
-
-
-
diff --git a/drivers/usb/scanner/mdc800.c b/drivers/usb/scanner/mdc800.c
deleted file mode 100644 (file)
index d06d72c..0000000
+++ /dev/null
@@ -1,1029 +0,0 @@
-/*
- * copyright (C) 1999/2000 by Henning Zabel <henning@uni-paderborn.de>
- *
- * 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 the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-/*
- *     USB-Kernel Driver for the Mustek MDC800 Digital Camera
- *     (c) 1999/2000 Henning Zabel <henning@uni-paderborn.de>
- *
- *
- * The driver brings the USB functions of the MDC800 to Linux.
- * To use the Camera you must support the USB Protocoll of the camera
- * to the Kernel Node.
- * The Driver uses a misc device Node. Create it with :
- * mknod /dev/mustek c 180 32
- *
- * The driver supports only one camera.
- * 
- * Fix: mdc800 used sleep_on and slept with io_lock held.
- * Converted sleep_on to waitqueues with schedule_timeout and made io_lock
- * a semaphore from a spinlock.
- * by Oliver Neukum <520047054719-0001@t-online.de>
- * (02/12/2001)
- * 
- * Identify version on module load.
- * (08/04/2001) gb
- *
- * version 0.7.5
- * Fixed potential SMP races with Spinlocks.
- * Thanks to Oliver Neukum <oliver.neukum@lrz.uni-muenchen.de> who 
- * noticed the race conditions.
- * (30/10/2000)
- *
- * Fixed: Setting urb->dev before submitting urb.
- * by Greg KH <greg@kroah.com>
- * (13/10/2000)
- *
- * version 0.7.3
- * bugfix : The mdc800->state field gets set to READY after the
- * the diconnect function sets it to NOT_CONNECTED. This makes the
- * driver running like the camera is connected and causes some
- * hang ups.
- *
- * version 0.7.1
- * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
- * problems when compiled as Module.
- * (04/04/2000)
- *
- * The mdc800 driver gets assigned the USB Minor 32-47. The Registration
- * was updated to use these values.
- * (26/03/2000)
- *
- * The Init und Exit Module Function are updated.
- * (01/03/2000)
- *
- * version 0.7.0
- * Rewrite of the driver : The driver now uses URB's. The old stuff
- * has been removed.
- *
- * version 0.6.0
- * Rewrite of this driver: The Emulation of the rs232 protocoll
- * has been removed from the driver. A special executeCommand function
- * for this driver is included to gphoto.
- * The driver supports two kind of communication to bulk endpoints.
- * Either with the dev->bus->ops->bulk... or with callback function.
- * (09/11/1999)
- *
- * version 0.5.0:
- * first Version that gets a version number. Most of the needed
- * functions work.
- * (20/10/1999)
- */
-
-#include <linux/version.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-
-#include <linux/usb.h>
-#include <linux/fs.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.7.5 (30/10/2000)"
-#define DRIVER_AUTHOR "Henning Zabel <henning@uni-paderborn.de>"
-#define DRIVER_DESC "USB Driver for Mustek MDC800 Digital Camera"
-
-/* Vendor and Product Information */
-#define MDC800_VENDOR_ID       0x055f
-#define MDC800_PRODUCT_ID      0xa800
-
-/* Timeouts (msec) */
-#define TO_DOWNLOAD_GET_READY          1500
-#define TO_DOWNLOAD_GET_BUSY           1500
-#define TO_WRITE_GET_READY             1000
-#define TO_DEFAULT_COMMAND             5000
-#define TO_READ_FROM_IRQ               TO_DEFAULT_COMMAND
-#define TO_GET_READY                   TO_DEFAULT_COMMAND
-
-/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
-#define MDC800_DEVICE_MINOR_BASE 32
-
-
-/**************************************************************************
-       Data and structs
-***************************************************************************/
-
-
-typedef enum {
-       NOT_CONNECTED, READY, WORKING, DOWNLOAD
-} mdc800_state;
-
-
-/* Data for the driver */
-struct mdc800_data
-{
-       struct usb_device *     dev;                    // Device Data
-       mdc800_state            state;
-
-       unsigned int            endpoint [4];
-
-       struct urb *            irq_urb;
-       wait_queue_head_t       irq_wait;
-       int                     irq_woken;
-       char*                   irq_urb_buffer;
-
-       int                     camera_busy;          // is camera busy ?
-       int                     camera_request_ready; // Status to synchronize with irq
-       char                    camera_response [8];  // last Bytes send after busy
-
-       struct urb *            write_urb;
-       char*                   write_urb_buffer;
-       wait_queue_head_t       write_wait;
-       int                     written;
-
-
-       struct urb *            download_urb;
-       char*                   download_urb_buffer;
-       wait_queue_head_t       download_wait;
-       int                     downloaded;
-       int                     download_left;          // Bytes left to download ?
-
-
-       /* Device Data */
-       char                    out [64];       // Answer Buffer
-       int                     out_ptr;        // Index to the first not readen byte
-       int                     out_count;      // Bytes in the buffer
-
-       int                     open;           // Camera device open ?
-       struct semaphore        io_lock;        // IO -lock
-
-       char                    in [8];         // Command Input Buffer
-       int                     in_count;
-
-       int                     pic_index;      // Cache for the Imagesize (-1 for nothing cached )
-       int                     pic_len;
-};
-
-
-/* Specification of the Endpoints */
-static struct usb_endpoint_descriptor mdc800_ed [4] =
-{
-       { 0,0, 0x01, 0x02,  8, 0,0,0 },
-       { 0,0, 0x82, 0x03,  8, 0,0,0 },
-       { 0,0, 0x03, 0x02, 64, 0,0,0 },
-       { 0,0, 0x84, 0x02, 64, 0,0,0 }
-};
-
-
-/* The Variable used by the driver */
-static struct mdc800_data* mdc800=0;
-
-
-/***************************************************************************
-       The USB Part of the driver
-****************************************************************************/
-
-static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b)
-{
-       return (
-                  ( a->bEndpointAddress == b->bEndpointAddress )
-               && ( a->bmAttributes     == b->bmAttributes     )
-               && ( a->wMaxPacketSize   == b->wMaxPacketSize   )
-       );
-}
-
-
-/*
- * Checks wether the camera responds busy
- */
-static int mdc800_isBusy (char* ch)
-{
-       int i=0;
-       while (i<8)
-       {
-               if (ch [i] != (char)0x99)
-                       return 0;
-               i++;
-       }
-       return 1;
-}
-
-
-/*
- * Checks wether the Camera is ready
- */
-static int mdc800_isReady (char *ch)
-{
-       int i=0;
-       while (i<8)
-       {
-               if (ch [i] != (char)0xbb)
-                       return 0;
-               i++;
-       }
-       return 1;
-}
-
-
-
-/*
- * USB IRQ Handler for InputLine
- */
-static void mdc800_usb_irq (struct urb *urb)
-{
-       int data_received=0, wake_up;
-       unsigned char* b=urb->transfer_buffer;
-       struct mdc800_data* mdc800=urb->context;
-
-       if (urb->status >= 0)
-       {
-
-               //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
-
-               if (mdc800_isBusy (b))
-               {
-                       if (!mdc800->camera_busy)
-                       {
-                               mdc800->camera_busy=1;
-                               dbg ("gets busy");
-                       }
-               }
-               else
-               {
-                       if (mdc800->camera_busy && mdc800_isReady (b))
-                       {
-                               mdc800->camera_busy=0;
-                               dbg ("gets ready");
-                       }
-               }
-               if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
-               {
-                       /* Store Data in camera_answer field */
-                       dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
-
-                       memcpy (mdc800->camera_response,b,8);
-                       data_received=1;
-               }
-       }
-       wake_up= ( mdc800->camera_request_ready > 0 )
-               &&
-               (
-                       ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy))
-               ||
-                       ((mdc800->camera_request_ready == 2) && data_received)
-               ||
-                       ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
-               ||
-                       (urb->status < 0)
-               );
-
-       if (wake_up)
-       {
-               mdc800->camera_request_ready=0;
-               mdc800->irq_woken=1;
-               wake_up_interruptible (&mdc800->irq_wait);
-       }
-}
-
-
-/*
- * Waits a while until the irq responds that camera is ready
- *
- *  mode : 0: Wait for camera gets ready
- *         1: Wait for receiving data
- *         2: Wait for camera gets busy
- *
- * msec: Time to wait
- */
-static int mdc800_usb_waitForIRQ (int mode, int msec)
-{
-        DECLARE_WAITQUEUE(wait, current);
-
-       mdc800->camera_request_ready=1+mode;
-
-       add_wait_queue(&mdc800->irq_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       if (!mdc800->irq_woken)
-       {
-               schedule_timeout (msec*HZ/1000);
-       }
-        remove_wait_queue(&mdc800->irq_wait, &wait);
-       set_current_state(TASK_RUNNING);
-       mdc800->irq_woken = 0;
-
-       if (mdc800->camera_request_ready>0)
-       {
-               mdc800->camera_request_ready=0;
-               err ("timeout waiting for camera.");
-               return -1;
-       }
-       
-       if (mdc800->state == NOT_CONNECTED)
-       {
-               warn ("Camera gets disconnected during waiting for irq.");
-               mdc800->camera_request_ready=0;
-               return -2;
-       }
-       
-       return 0;
-}
-
-
-/*
- * The write_urb callback function
- */
-static void mdc800_usb_write_notify (struct urb *urb)
-{
-       struct mdc800_data* mdc800=urb->context;
-
-       if (urb->status != 0)
-       {
-               err ("writing command fails (status=%i)", urb->status);
-       }
-       else
-       {       
-               mdc800->state=READY;
-       }
-       mdc800->written = 1;
-       wake_up_interruptible (&mdc800->write_wait);
-}
-
-
-/*
- * The download_urb callback function
- */
-static void mdc800_usb_download_notify (struct urb *urb)
-{
-       struct mdc800_data* mdc800=urb->context;
-
-       if (urb->status == 0)
-       {
-               /* Fill output buffer with these data */
-               memcpy (mdc800->out,  urb->transfer_buffer, 64);
-               mdc800->out_count=64;
-               mdc800->out_ptr=0;
-               mdc800->download_left-=64;
-               if (mdc800->download_left == 0)
-               {
-                       mdc800->state=READY;
-               }
-       }
-       else
-       {
-               err ("request bytes fails (status:%i)", urb->status);
-       }
-       mdc800->downloaded = 1;
-       wake_up_interruptible (&mdc800->download_wait);
-}
-
-
-/***************************************************************************
-       Probing for the Camera
- ***************************************************************************/
-
-static struct usb_driver mdc800_usb_driver;
-
-/*
- * Callback to search the Mustek MDC800 on the USB Bus
- */
-static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum,
-                              const struct usb_device_id *id)
-{
-       int i,j;
-       struct usb_interface_descriptor *intf_desc;
-       int irq_interval=0;
-
-       dbg ("(mdc800_usb_probe) called.");
-
-
-       if (mdc800->dev != 0)
-       {
-               warn ("only one Mustek MDC800 is supported.");
-               return 0;
-       }
-
-       if (dev->descriptor.bNumConfigurations != 1)
-       {
-               err ("probe fails -> wrong Number of Configuration");
-               return 0;
-       }
-       intf_desc=&dev->actconfig->interface[ifnum].altsetting[0];
-
-       if (
-                       ( intf_desc->bInterfaceClass != 0xff )
-               ||      ( intf_desc->bInterfaceSubClass != 0 )
-               || ( intf_desc->bInterfaceProtocol != 0 )
-               || ( intf_desc->bNumEndpoints != 4)
-       )
-       {
-               err ("probe fails -> wrong Interface");
-               return 0;
-       }
-
-       /* Check the Endpoints */
-       for (i=0; i<4; i++)
-       {
-               mdc800->endpoint[i]=-1;
-               for (j=0; j<4; j++)
-               {
-                       if (mdc800_endpoint_equals (&intf_desc->endpoint [j],&mdc800_ed [i]))
-                       {
-                               mdc800->endpoint[i]=intf_desc->endpoint [j].bEndpointAddress ;
-                               if (i==1)
-                               {
-                                       irq_interval=intf_desc->endpoint [j].bInterval;
-                               }
-
-                               continue;
-                       }
-               }
-               if (mdc800->endpoint[i] == -1)
-               {
-                       err ("probe fails -> Wrong Endpoints.");
-                       return 0;
-               }
-       }
-
-
-       usb_driver_claim_interface (&mdc800_usb_driver, &dev->actconfig->interface[ifnum], mdc800);
-       if (usb_set_interface (dev, ifnum, 0) < 0)
-       {
-               err ("MDC800 Configuration fails.");
-               return 0;
-       }
-
-       info ("Found Mustek MDC800 on USB.");
-
-       down (&mdc800->io_lock);
-
-       mdc800->dev=dev;
-       mdc800->open=0;
-
-       /* Setup URB Structs */
-       FILL_INT_URB (
-               mdc800->irq_urb,
-               mdc800->dev,
-               usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]),
-               mdc800->irq_urb_buffer,
-               8,
-               mdc800_usb_irq,
-               mdc800,
-               irq_interval
-       );
-
-       FILL_BULK_URB (
-               mdc800->write_urb,
-               mdc800->dev,
-               usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]),
-               mdc800->write_urb_buffer,
-               8,
-               mdc800_usb_write_notify,
-               mdc800
-       );
-
-       FILL_BULK_URB (
-               mdc800->download_urb,
-               mdc800->dev,
-               usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]),
-               mdc800->download_urb_buffer,
-               64,
-               mdc800_usb_download_notify,
-               mdc800
-       );
-
-       mdc800->state=READY;
-
-       up (&mdc800->io_lock);
-       
-       return mdc800;
-}
-
-
-/*
- * Disconnect USB device (maybe the MDC800)
- */
-static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
-{
-       struct mdc800_data* mdc800=(struct mdc800_data*) ptr;
-
-       dbg ("(mdc800_usb_disconnect) called");
-
-       if (mdc800->state == NOT_CONNECTED)
-               return;
-       
-       mdc800->state=NOT_CONNECTED;
-
-       usb_unlink_urb (mdc800->irq_urb);
-       usb_unlink_urb (mdc800->write_urb);
-       usb_unlink_urb (mdc800->download_urb);
-
-       usb_driver_release_interface (&mdc800_usb_driver, &dev->actconfig->interface[1]);
-
-       mdc800->dev=0;
-       info ("Mustek MDC800 disconnected from USB.");
-}
-
-
-/***************************************************************************
-       The Misc device Part (file_operations)
-****************************************************************************/
-
-/*
- * This Function calc the Answersize for a command.
- */
-static int mdc800_getAnswerSize (char command)
-{
-       switch ((unsigned char) command)
-       {
-               case 0x2a:
-               case 0x49:
-               case 0x51:
-               case 0x0d:
-               case 0x20:
-               case 0x07:
-               case 0x01:
-               case 0x25:
-               case 0x00:
-                       return 8;
-
-               case 0x05:
-               case 0x3e:
-                       return mdc800->pic_len;
-
-               case 0x09:
-                       return 4096;
-
-               default:
-                       return 0;
-       }
-}
-
-
-/*
- * Init the device: (1) alloc mem (2) Increase MOD Count ..
- */
-static int mdc800_device_open (struct inode* inode, struct file *file)
-{
-       int retval=0;
-       int errn=0;
-
-       down (&mdc800->io_lock);
-       
-       if (mdc800->state == NOT_CONNECTED)
-       {
-               errn=-EBUSY;
-               goto error_out;
-       }
-       if (mdc800->open)
-       {
-               errn=-EBUSY;
-               goto error_out;
-       }
-
-       mdc800->in_count=0;
-       mdc800->out_count=0;
-       mdc800->out_ptr=0;
-       mdc800->pic_index=0;
-       mdc800->pic_len=-1;
-       mdc800->download_left=0;
-
-       mdc800->camera_busy=0;
-       mdc800->camera_request_ready=0;
-
-       retval=0;
-       mdc800->irq_urb->dev = mdc800->dev;
-       if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
-       {
-               err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
-               errn = -EIO;
-               goto error_out;
-       }
-
-       mdc800->open=1;
-       dbg ("Mustek MDC800 device opened.");
-
-error_out:
-       up (&mdc800->io_lock);
-       return errn;
-}
-
-
-/*
- * Close the Camera and release Memory
- */
-static int mdc800_device_release (struct inode* inode, struct file *file)
-{
-       int retval=0;
-       dbg ("Mustek MDC800 device closed.");
-
-       down (&mdc800->io_lock);
-       if (mdc800->open && (mdc800->state != NOT_CONNECTED))
-       {
-               usb_unlink_urb (mdc800->irq_urb);
-               usb_unlink_urb (mdc800->write_urb);
-               usb_unlink_urb (mdc800->download_urb);
-               mdc800->open=0;
-       }
-       else
-       {
-               retval=-EIO;
-       }
-
-       up(&mdc800->io_lock);
-       return retval;
-}
-
-
-/*
- * The Device read callback Function
- */
-static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
-{
-       int   left=len, sts=len; /* single transfer size */
-       char* ptr=buf;
-       DECLARE_WAITQUEUE(wait, current);
-
-       down (&mdc800->io_lock);
-       if (mdc800->state == NOT_CONNECTED)
-       {
-               up (&mdc800->io_lock);
-               return -EBUSY;
-       }
-       if (mdc800->state == WORKING)
-       {
-               warn ("Illegal State \"working\" reached during read ?!");
-               up (&mdc800->io_lock);
-               return -EBUSY;
-       }
-       if (!mdc800->open)
-       {
-               up (&mdc800->io_lock);
-               return -EBUSY;
-       }
-
-       while (left)
-       {
-               if (signal_pending (current)) 
-               {
-                       up (&mdc800->io_lock);
-                       return -EINTR;
-               }
-
-               sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
-
-               if (sts <= 0)
-               {
-                       /* Too less Data in buffer */
-                       if (mdc800->state == DOWNLOAD)
-                       {
-                               mdc800->out_count=0;
-                               mdc800->out_ptr=0;
-
-                               /* Download -> Request new bytes */
-                               mdc800->download_urb->dev = mdc800->dev;
-                               if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
-                               {
-                                       err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
-                                       up (&mdc800->io_lock);
-                                       return len-left;
-                               }
-                               add_wait_queue(&mdc800->download_wait, &wait);
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               if (!mdc800->downloaded)
-                               {
-                                       schedule_timeout (TO_DOWNLOAD_GET_READY*HZ/1000);
-                               }
-                               set_current_state(TASK_RUNNING);
-                               remove_wait_queue(&mdc800->download_wait, &wait);
-                               mdc800->downloaded = 0;
-                               if (mdc800->download_urb->status != 0)
-                               {
-                                       err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
-                                       up (&mdc800->io_lock);
-                                       return len-left;
-                               }
-                       }
-                       else
-                       {
-                               /* No more bytes -> that's an error*/
-                               up (&mdc800->io_lock);
-                               return -EIO;
-                       }
-               }
-               else
-               {
-                       /* memcpy Bytes */
-                       memcpy (ptr, &mdc800->out [mdc800->out_ptr], sts);
-                       ptr+=sts;
-                       left-=sts;
-                       mdc800->out_ptr+=sts;
-               }
-       }
-
-       up (&mdc800->io_lock);
-       return len-left;
-}
-
-
-/*
- * The Device write callback Function
- * If a 8Byte Command is received, it will be send to the camera.
- * After this the driver initiates the request for the answer or
- * just waits until the camera becomes ready.
- */
-static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
-{
-       int i=0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       down (&mdc800->io_lock);
-       if (mdc800->state != READY)
-       {
-               up (&mdc800->io_lock);
-               return -EBUSY;
-       }
-       if (!mdc800->open )
-       {
-               up (&mdc800->io_lock);
-               return -EBUSY;
-       }
-
-       while (i<len)
-       {
-               if (signal_pending (current)) 
-               {
-                       up (&mdc800->io_lock);
-                       return -EINTR;
-               }
-
-               /* check for command start */
-               if (buf [i] == (char) 0x55)
-               {
-                       mdc800->in_count=0;
-                       mdc800->out_count=0;
-                       mdc800->out_ptr=0;
-                       mdc800->download_left=0;
-               }
-
-               /* save command byte */
-               if (mdc800->in_count < 8)
-               {
-                       mdc800->in[mdc800->in_count]=buf[i];
-                       mdc800->in_count++;
-               }
-               else
-               {
-                       err ("Command is to long !\n");
-                       up (&mdc800->io_lock);
-                       return -EIO;
-               }
-
-               /* Command Buffer full ? -> send it to camera */
-               if (mdc800->in_count == 8)
-               {
-                       int answersize;
-
-                       if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
-                       {
-                               err ("Camera didn't get ready.\n");
-                               up (&mdc800->io_lock);
-                               return -EIO;
-                       }
-
-                       answersize=mdc800_getAnswerSize (mdc800->in[1]);
-
-                       mdc800->state=WORKING;
-                       memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
-                       mdc800->write_urb->dev = mdc800->dev;
-                       if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
-                       {
-                               err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
-                               up (&mdc800->io_lock);
-                               return -EIO;
-                       }
-                       add_wait_queue(&mdc800->write_wait, &wait);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (!mdc800->written)
-                       {
-                               schedule_timeout (TO_WRITE_GET_READY*HZ/1000);
-                       }
-                        set_current_state(TASK_RUNNING);
-                       remove_wait_queue(&mdc800->write_wait, &wait);
-                       mdc800->written = 0;
-                       if (mdc800->state == WORKING)
-                       {
-                               usb_unlink_urb (mdc800->write_urb);
-                               up (&mdc800->io_lock);
-                               return -EIO;
-                       }
-
-                       switch ((unsigned char) mdc800->in[1])
-                       {
-                               case 0x05: /* Download Image */
-                               case 0x3e: /* Take shot in Fine Mode (WCam Mode) */
-                                       if (mdc800->pic_len < 0)
-                                       {
-                                               err ("call 0x07 before 0x05,0x3e");
-                                               mdc800->state=READY;
-                                               up (&mdc800->io_lock);
-                                               return -EIO;
-                                       }
-                                       mdc800->pic_len=-1;
-
-                               case 0x09: /* Download Thumbnail */
-                                       mdc800->download_left=answersize+64;
-                                       mdc800->state=DOWNLOAD;
-                                       mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY);
-                                       break;
-
-
-                               default:
-                                       if (answersize)
-                                       {
-
-                                               if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
-                                               {
-                                                       err ("requesting answer from irq fails");
-                                                       up (&mdc800->io_lock);
-                                                       return -EIO;
-                                               }
-
-                                               /* Write dummy data, (this is ugly but part of the USB Protokoll */
-                                               /* if you use endpoint 1 as bulk and not as irq */
-                                               memcpy (mdc800->out, mdc800->camera_response,8);
-
-                                               /* This is the interpreted answer */
-                                               memcpy (&mdc800->out[8], mdc800->camera_response,8);
-
-                                               mdc800->out_ptr=0;
-                                               mdc800->out_count=16;
-
-                                               /* Cache the Imagesize, if command was getImageSize */
-                                               if (mdc800->in [1] == (char) 0x07)
-                                               {
-                                                       mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
-
-                                                       dbg ("cached imagesize = %i",mdc800->pic_len);
-                                               }
-
-                                       }
-                                       else
-                                       {
-                                               if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
-                                               {
-                                                       err ("Command Timeout.");
-                                                       up (&mdc800->io_lock);
-                                                       return -EIO;
-                                               }
-                                       }
-                                       mdc800->state=READY;
-                                       break;
-                       }
-               }
-               i++;
-       }
-       up (&mdc800->io_lock);
-       return i;
-}
-
-
-/***************************************************************************
-       Init and Cleanup this driver (Structs and types)
-****************************************************************************/
-
-/* File Operations of this drivers */
-static struct file_operations mdc800_device_ops =
-{
-       owner:          THIS_MODULE,
-       read:           mdc800_device_read,
-       write:          mdc800_device_write,
-       open:           mdc800_device_open,
-       release:        mdc800_device_release,
-};
-
-
-
-static struct usb_device_id mdc800_table [] = {
-       { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, mdc800_table);
-/*
- * USB Driver Struct for this device
- */
-static struct usb_driver mdc800_usb_driver =
-{
-       name:           "mdc800",
-       probe:          mdc800_usb_probe,
-       disconnect:     mdc800_usb_disconnect,
-       fops:           &mdc800_device_ops,
-       minor:          MDC800_DEVICE_MINOR_BASE,
-       id_table:       mdc800_table
-};
-
-
-
-/************************************************************************
-       Init and Cleanup this driver (Main Functions)
-*************************************************************************/
-
-#define try(A)           if ((A) == 0) goto cleanup_on_fail;
-#define try_free_mem(A)  if (A != 0) { kfree (A); A=0; }
-#define try_free_urb(A)  if (A != 0) { usb_free_urb (A); A=0; }
-
-int __init usb_mdc800_init (void)
-{
-       /* Allocate Memory */
-       try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
-
-       memset(mdc800, 0, sizeof(struct mdc800_data));
-       mdc800->dev=0;
-       mdc800->open=0;
-       mdc800->state=NOT_CONNECTED;
-       init_MUTEX (&mdc800->io_lock);
-
-       init_waitqueue_head (&mdc800->irq_wait);
-       init_waitqueue_head (&mdc800->write_wait);
-       init_waitqueue_head (&mdc800->download_wait);
-
-       mdc800->irq_woken = 0;
-       mdc800->downloaded = 0;
-       mdc800->written = 0;
-
-       try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
-       try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
-       try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL));
-
-       try (mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL));
-       try (mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL));
-       try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL));
-
-       /* Register the driver */
-       if (usb_register (&mdc800_usb_driver) < 0)
-               goto cleanup_on_fail;
-
-       info (DRIVER_VERSION ":" DRIVER_DESC);
-
-       return 0;
-
-       /* Clean driver up, when something fails */
-
-cleanup_on_fail:
-
-       if (mdc800 != 0)
-       {
-               err ("can't alloc memory!");
-
-               try_free_mem (mdc800->download_urb_buffer);
-               try_free_mem (mdc800->write_urb_buffer);
-               try_free_mem (mdc800->irq_urb_buffer);
-
-               try_free_urb (mdc800->write_urb);
-               try_free_urb (mdc800->download_urb);
-               try_free_urb (mdc800->irq_urb);
-
-               kfree (mdc800);
-       }
-       mdc800=0;
-       return -1;
-}
-
-
-void __exit usb_mdc800_cleanup (void)
-{
-       usb_deregister (&mdc800_usb_driver);
-
-       usb_free_urb (mdc800->irq_urb);
-       usb_free_urb (mdc800->download_urb);
-       usb_free_urb (mdc800->write_urb);
-
-       kfree (mdc800->irq_urb_buffer);
-       kfree (mdc800->write_urb_buffer);
-       kfree (mdc800->download_urb_buffer);
-
-       kfree (mdc800);
-       mdc800=0;
-}
-
-module_init (usb_mdc800_init);
-module_exit (usb_mdc800_cleanup);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/scanner/microtek.c b/drivers/usb/scanner/microtek.c
deleted file mode 100644 (file)
index 6b2591e..0000000
+++ /dev/null
@@ -1,1065 +0,0 @@
-/* Driver for Microtek Scanmaker X6 USB scanner, and possibly others.
- *
- * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
- * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
- *
- * Parts shamelessly stolen from usb-storage and copyright by their
- * authors. Thanks to Matt Dharm for giving us permission!
- *
- * This driver implements a SCSI host controller driver and a USB
- * device driver. To avoid confusion, all the USB related stuff is
- * prefixed by mts_usb_ and all the SCSI stuff by mts_scsi_.
- *
- * Microtek (www.microtek.com) did not release the specifications for
- * their USB protocol to us, so we had to reverse engineer them. We
- * don't know for which models they are valid.
- *
- * The X6 USB has three bulk endpoints, one output (0x1) down which
- * commands and outgoing data are sent, and two input: 0x82 from which
- * normal data is read from the scanner (in packets of maximum 32
- * bytes) and from which the status byte is read, and 0x83 from which
- * the results of a scan (or preview) are read in up to 64 * 1024 byte
- * chunks by the Windows driver. We don't know how much it is possible
- * to read at a time from 0x83.
- *
- * It seems possible to read (with URB transfers) everything from 0x82
- * in one go, without bothering to read in 32 byte chunks.
- *
- * There seems to be an optimisation of a further READ implicit if
- * you simply read from 0x83.
- *
- * Guessed protocol:
- *
- *     Send raw SCSI command to EP 0x1
- *
- *     If there is data to receive:
- *             If the command was READ datatype=image:
- *                     Read a lot of data from EP 0x83
- *             Else:
- *                     Read data from EP 0x82
- *     Else:
- *             If there is data to transmit:
- *                     Write it to EP 0x1
- *
- *     Read status byte from EP 0x82
- *
- * References:
- *
- * The SCSI command set for the scanner is available from
- *     ftp://ftp.microtek.com/microtek/devpack/
- *
- * Microtek NV sent us a more up to date version of the document. If
- * you want it, just send mail.
- *
- * Status:
- *
- *     Untested with multiple scanners.
- *     Untested on SMP.
- *     Untested on a bigendian machine.
- *
- * History:
- *
- *     20000417 starting history
- *     20000417 fixed load oops
- *     20000417 fixed unload oops
- *     20000419 fixed READ IMAGE detection
- *     20000424 started conversion to use URBs
- *     20000502 handled short transfers as errors
- *     20000513 rename and organisation of functions (john)
- *     20000513 added IDs for all products supported by Windows driver (john)
- *     20000514 Rewrote mts_scsi_queuecommand to use URBs (john)
- *     20000514 Version 0.0.8j
- *      20000514 Fix reporting of non-existant devices to SCSI layer (john)
- *     20000514 Added MTS_DEBUG_INT (john)
- *     20000514 Changed "usb-microtek" to "microtek" for consistency (john)
- *     20000514 Stupid bug fixes (john)
- *     20000514 Version 0.0.9j
- *     20000515 Put transfer context and URB in mts_desc (john)
- *     20000515 Added prelim turn off debugging support (john)
- *     20000515 Version 0.0.10j
- *      20000515 Fixed up URB allocation (clear URB on alloc) (john)
- *      20000515 Version 0.0.11j
- *     20000516 Removed unnecessary spinlock in mts_transfer_context (john)
- *     20000516 Removed unnecessary up on instance lock in mts_remove_nolock (john)
- *     20000516 Implemented (badly) scsi_abort (john)
- *     20000516 Version 0.0.12j
- *      20000517 Hopefully removed mts_remove_nolock quasideadlock (john)
- *      20000517 Added mts_debug_dump to print ll USB info (john)
- *     20000518 Tweaks and documentation updates (john)
- *     20000518 Version 0.0.13j
- *     20000518 Cleaned up abort handling (john)
- *     20000523 Removed scsi_command and various scsi_..._resets (john)
- *     20000523 Added unlink URB on scsi_abort, now OHCI supports it (john)
- *     20000523 Fixed last tiresome compile warning (john)
- *     20000523 Version 0.0.14j (though version 0.1 has come out?)
- *     20000602 Added primitive reset
- *     20000602 Version 0.2.0
- *     20000603 various cosmetic changes
- *     20000603 Version 0.2.1
- *     20000620 minor cosmetic changes
- *     20000620 Version 0.2.2
- *     20000822 Hopefully fixed deadlock in mts_remove_nolock()
- *     20000822 Fixed minor race in mts_transfer_cleanup()
- *     20000822 Fixed deadlock on submission error in queuecommand
- *     20000822 Version 0.2.3
- *     20000913 Reduced module size if debugging is off
- *     20000913 Version 0.2.4
- *      20010210 New abort logic
- *      20010210 Version 0.3.0
- *     20010217 Merged scatter/gather
- *     20010218 Version 0.4.0
- *     20010218 Cosmetic fixes
- *     20010218 Version 0.4.1
- *      20010306 Abort while using scatter/gather
- *      20010306 Version 0.4.2
- *      20010311 Remove all timeouts and tidy up generally (john)
- *     20010320 check return value of scsi_register()
- *     20010320 Version 0.4.3
- *     20010408 Identify version on module load.
- *     20011003 Fix multiple requests
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/usb.h>
-#include <linux/proc_fs.h>
-
-#include <asm/atomic.h>
-#include <linux/blk.h>
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "../../scsi/sd.h"
-
-#include "microtek.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.4.3"
-#define DRIVER_AUTHOR "John Fremlin <vii@penguinpowered.com>, Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>"
-#define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver"
-
-/* Should we do debugging? */
-
-//#define MTS_DO_DEBUG
-
-/* USB layer driver interface */
-
-static void *mts_usb_probe(struct usb_device *dev, unsigned int interface,
-                        const struct usb_device_id *id);
-static void mts_usb_disconnect(struct usb_device *dev, void *ptr);
-
-static struct usb_device_id mts_usb_ids [];
-
-static struct usb_driver mts_usb_driver = {
-       name:           "microtekX6",
-       probe:          mts_usb_probe,
-       disconnect:     mts_usb_disconnect,
-       id_table:       mts_usb_ids,
-};
-
-
-/* Internal driver stuff */
-
-#define MTS_VERSION    "0.4.3"
-#define MTS_NAME       "microtek usb (rev " MTS_VERSION "): "
-
-#define MTS_WARNING(x...) \
-       printk( KERN_WARNING MTS_NAME x )
-#define MTS_ERROR(x...) \
-       printk( KERN_ERR MTS_NAME x )
-#define MTS_INT_ERROR(x...) \
-       MTS_ERROR(x)
-#define MTS_MESSAGE(x...) \
-       printk( KERN_INFO MTS_NAME x )
-
-#if defined MTS_DO_DEBUG
-
-#define MTS_DEBUG(x...) \
-       printk( KERN_DEBUG MTS_NAME x )
-
-#define MTS_DEBUG_GOT_HERE() \
-       MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ )
-#define MTS_DEBUG_INT() \
-       do { MTS_DEBUG_GOT_HERE(); \
-            MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
-            MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
-             mts_debug_dump(context->instance);\
-          } while(0)
-#else
-
-#define MTS_NUL_STATEMENT do { } while(0)
-
-#define MTS_DEBUG(x...)        MTS_NUL_STATEMENT
-#define MTS_DEBUG_GOT_HERE() MTS_NUL_STATEMENT
-#define MTS_DEBUG_INT() MTS_NUL_STATEMENT
-
-#endif
-
-
-
-#define MTS_INT_INIT()\
-       struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context; \
-       MTS_DEBUG_INT();\
-
-#ifdef MTS_DO_DEBUG
-
-static inline void mts_debug_dump(struct mts_desc* desc) {
-       MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n",
-                 (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0],
-                 (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0]
-               );
-       MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n",
-                 usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
-                 usb_rcvbulkpipe(desc->usb_dev,desc->ep_response),
-                 usb_rcvbulkpipe(desc->usb_dev,desc->ep_image)
-               );
-}
-
-
-static inline void mts_show_command(Scsi_Cmnd *srb)
-{
-       char *what = NULL;
-
-       switch (srb->cmnd[0]) {
-       case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
-       case REZERO_UNIT: what = "REZERO_UNIT"; break;
-       case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
-       case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
-       case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
-       case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
-       case READ_6: what = "READ_6"; break;
-       case WRITE_6: what = "WRITE_6"; break;
-       case SEEK_6: what = "SEEK_6"; break;
-       case READ_REVERSE: what = "READ_REVERSE"; break;
-       case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
-       case SPACE: what = "SPACE"; break;
-       case INQUIRY: what = "INQUIRY"; break;
-       case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
-       case MODE_SELECT: what = "MODE_SELECT"; break;
-       case RESERVE: what = "RESERVE"; break;
-       case RELEASE: what = "RELEASE"; break;
-       case COPY: what = "COPY"; break;
-       case ERASE: what = "ERASE"; break;
-       case MODE_SENSE: what = "MODE_SENSE"; break;
-       case START_STOP: what = "START_STOP"; break;
-       case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
-       case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
-       case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
-       case SET_WINDOW: what = "SET_WINDOW"; break;
-       case READ_CAPACITY: what = "READ_CAPACITY"; break;
-       case READ_10: what = "READ_10"; break;
-       case WRITE_10: what = "WRITE_10"; break;
-       case SEEK_10: what = "SEEK_10"; break;
-       case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
-       case VERIFY: what = "VERIFY"; break;
-       case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
-       case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
-       case SEARCH_LOW: what = "SEARCH_LOW"; break;
-       case SET_LIMITS: what = "SET_LIMITS"; break;
-       case READ_POSITION: what = "READ_POSITION"; break;
-       case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
-       case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
-       case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
-       case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
-       case COMPARE: what = "COMPARE"; break;
-       case COPY_VERIFY: what = "COPY_VERIFY"; break;
-       case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
-       case READ_BUFFER: what = "READ_BUFFER"; break;
-       case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
-       case READ_LONG: what = "READ_LONG"; break;
-       case WRITE_LONG: what = "WRITE_LONG"; break;
-       case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
-       case WRITE_SAME: what = "WRITE_SAME"; break;
-       case READ_TOC: what = "READ_TOC"; break;
-       case LOG_SELECT: what = "LOG_SELECT"; break;
-       case LOG_SENSE: what = "LOG_SENSE"; break;
-       case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
-       case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
-       case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
-       case READ_12: what = "READ_12"; break;
-       case WRITE_12: what = "WRITE_12"; break;
-       case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
-       case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
-       case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
-       case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
-       case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
-       case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
-       case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
-       default:
-               MTS_DEBUG("can't decode command\n");
-               goto out;
-               break;
-       }
-       MTS_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len);
-
- out:
-       MTS_DEBUG( "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-              srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5],
-              srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
-}
-
-#else
-
-static inline void mts_show_command(Scsi_Cmnd * dummy)
-{
-}
-
-static inline void mts_debug_dump(struct mts_desc* dummy)
-{
-}
-
-#endif
-
-static inline void mts_urb_abort(struct mts_desc* desc) {
-       MTS_DEBUG_GOT_HERE();
-       mts_debug_dump(desc);
-
-       usb_unlink_urb( desc->urb );
-}
-
-static struct mts_desc * mts_list; /* list of active scanners */
-struct semaphore mts_list_semaphore;
-
-/* Internal list operations */
-
-static
-void mts_remove_nolock( struct mts_desc* to_remove )
-{
-       MTS_DEBUG( "removing 0x%x from list\n",
-                  (int)to_remove );
-
-       lock_kernel();
-       mts_urb_abort(to_remove);
-
-       MTS_DEBUG_GOT_HERE();
-
-       if ( to_remove != mts_list ) {
-               MTS_DEBUG_GOT_HERE();
-               if (to_remove->prev && to_remove->next)
-                       to_remove->prev->next = to_remove->next;
-       } else {
-               MTS_DEBUG_GOT_HERE();
-               mts_list = to_remove->next;
-               if (mts_list) {
-                       MTS_DEBUG_GOT_HERE();
-                       mts_list->prev = 0;
-               }
-       }
-
-       if ( to_remove->next ) {
-               MTS_DEBUG_GOT_HERE();
-               to_remove->next->prev = to_remove->prev;
-       }
-
-       MTS_DEBUG_GOT_HERE();
-       scsi_unregister_host(&to_remove->ctempl);
-       unlock_kernel();
-
-       usb_free_urb(to_remove->urb);
-       kfree( to_remove );
-}
-
-static
-void mts_add_nolock( struct mts_desc* to_add )
-{
-       MTS_DEBUG( "adding 0x%x to list\n", (int)to_add );
-
-       to_add->prev = 0;
-       to_add->next = mts_list;
-       if ( mts_list ) {
-               mts_list->prev = to_add;
-       }
-
-       mts_list = to_add;
-}
-
-
-
-
-/* SCSI driver interface */
-
-/* scsi related functions - dummies for now mostly */
-
-static int mts_scsi_release(struct Scsi_Host *psh)
-{
-       MTS_DEBUG_GOT_HERE();
-
-       return 0;
-}
-
-static int mts_scsi_abort (Scsi_Cmnd *srb)
-{
-       struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
-
-       MTS_DEBUG_GOT_HERE();
-
-       mts_urb_abort(desc);
-
-       return SCSI_ABORT_PENDING;
-}
-
-static int mts_scsi_host_reset (Scsi_Cmnd *srb)
-{
-       struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
-
-       MTS_DEBUG_GOT_HERE();
-       mts_debug_dump(desc);
-
-       usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */
-       return 0;  /* RANT why here 0 and not SUCCESS */
-}
-
-/* the core of the scsi part */
-
-/* faking a detection - which can't fail :-) */
-
-static int mts_scsi_detect (struct SHT * sht)
-{
-       /* Whole function stolen from usb-storage */
-
-       struct mts_desc * desc = (struct mts_desc *)sht->proc_dir;
-       /* What a hideous hack! */
-
-       char local_name[48];
-
-       MTS_DEBUG_GOT_HERE();
-
-       /* set up the name of our subdirectory under /proc/scsi/ */
-       sprintf(local_name, "microtek-%d", desc->host_number);
-       sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
-       /* FIXME: where is this freed ? */
-
-       if (!sht->proc_name) {
-               MTS_ERROR( "unable to allocate memory for proc interface!!\n" );
-               return 0;
-       }
-
-       strcpy(sht->proc_name, local_name);
-
-       sht->proc_dir = NULL;
-
-       /* In host->hostdata we store a pointer to desc */
-       desc->host = scsi_register(sht, sizeof(desc));
-       if (desc->host == NULL) {
-               MTS_ERROR("Cannot register due to low memory");
-               kfree(sht->proc_name);
-               return 0;
-       }
-       desc->host->hostdata[0] = (unsigned long)desc;
-/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */
-
-       return 1;
-}
-
-
-
-/* Main entrypoint: SCSI commands are dispatched to here */
-
-
-
-static
-int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
-
-static void mts_transfer_cleanup( struct urb *transfer );
-static void mts_do_sg(struct urb * transfer);
-
-
-inline static
-void mts_int_submit_urb (struct urb* transfer,
-                       int pipe,
-                       void* data,
-                       unsigned length,
-                       mts_usb_urb_callback callback )
-/* Interrupt context! */
-
-/* Holding transfer->context->lock! */
-{
-       int res;
-
-       MTS_INT_INIT();
-
-       FILL_BULK_URB(transfer,
-                     context->instance->usb_dev,
-                     pipe,
-                     data,
-                     length,
-                     callback,
-                     context
-               );
-
-       transfer->status = 0;
-
-       res = usb_submit_urb( transfer, GFP_ATOMIC );
-       if ( unlikely(res) ) {
-               MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
-               context->srb->result = DID_ERROR << 16;
-               mts_transfer_cleanup(transfer);
-       }
-       return;
-}
-
-
-static void mts_transfer_cleanup( struct urb *transfer )
-/* Interrupt context! */
-{
-       MTS_INT_INIT();
-
-       if ( likely(context->final_callback != NULL) )
-               context->final_callback(context->srb);
-
-}
-
-static void mts_transfer_done( struct urb *transfer )
-{
-       MTS_INT_INIT();
-
-       context->srb->result &= MTS_SCSI_ERR_MASK;
-       context->srb->result |= (unsigned)context->status<<1;
-
-       mts_transfer_cleanup(transfer);
-
-       return;
-}
-
-
-static void mts_get_status( struct urb *transfer )
-/* Interrupt context! */
-{
-       MTS_INT_INIT();
-
-       mts_int_submit_urb(transfer,
-                          usb_rcvbulkpipe(context->instance->usb_dev,
-                                          context->instance->ep_response),
-                          &context->status,
-                          1,
-                          mts_transfer_done );
-}
-
-static void mts_data_done( struct urb* transfer )
-/* Interrupt context! */
-{
-       MTS_INT_INIT();
-
-       if ( context->data_length != transfer->actual_length ) {
-               context->srb->resid = context->data_length - transfer->actual_length;
-       } else if ( unlikely(transfer->status) ) {
-               context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
-       }
-
-       mts_get_status(transfer);
-
-       return;
-}
-
-
-static void mts_command_done( struct urb *transfer )
-/* Interrupt context! */
-{
-       MTS_INT_INIT();
-
-       if ( unlikely(transfer->status) ) {
-               if (transfer->status == -ENOENT) {
-                       /* We are being killed */
-                       MTS_DEBUG_GOT_HERE();
-                       context->srb->result = DID_ABORT<<16;
-                } else {
-                       /* A genuine error has occured */
-                       MTS_DEBUG_GOT_HERE();
-
-                       context->srb->result = DID_ERROR<<16;
-                }
-               mts_transfer_cleanup(transfer);
-
-               return;
-       }
-
-       if ( context->data ) {
-               mts_int_submit_urb(transfer,
-                                  context->data_pipe,
-                                  context->data,
-                                  context->data_length,
-                                  context->srb->use_sg ? mts_do_sg : mts_data_done);
-       } else mts_get_status(transfer);
-
-       return;
-}
-
-static void mts_do_sg (struct urb* transfer)
-{
-       struct scatterlist * sg;
-       MTS_INT_INIT();
-       
-       MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
-
-       if (unlikely(transfer->status)) {
-                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
-               mts_transfer_cleanup(transfer);
-        }
-
-       sg = context->srb->buffer;
-       context->fragment++;
-       mts_int_submit_urb(transfer,
-                          context->data_pipe,
-                          page_address(sg[context->fragment].page) +
-                          sg[context->fragment].offset,
-                          sg[context->fragment].length,
-                          context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg);
-       return;
-}
-
-static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 };
-static const u8 mts_read_image_sig_len = 4;
-static const unsigned char mts_direction[256/8] = {
-       0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
-       0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-
-#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)
-
-static void
-mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
-{
-       int pipe;
-       struct scatterlist * sg;
-       
-       MTS_DEBUG_GOT_HERE();
-
-       desc->context.instance = desc;
-       desc->context.srb = srb;
-       desc->context.fragment = 0;
-
-       if (!srb->use_sg) {
-               if ( !srb->bufflen ){
-                       desc->context.data = 0;
-                       desc->context.data_length = 0;
-                       return;
-               } else {
-                       desc->context.data = srb->buffer;
-                       desc->context.data_length = srb->bufflen;
-                       MTS_DEBUG("length = %d or %d\n",
-                                 srb->request_bufflen, srb->bufflen);
-               }
-       } else {
-               MTS_DEBUG("Using scatter/gather\n");
-               sg = srb->buffer;
-               desc->context.data = page_address(sg[0].page) + sg[0].offset;
-               desc->context.data_length = sg[0].length;
-       }
-
-
-       /* can't rely on srb->sc_data_direction */
-
-       /* Brutally ripped from usb-storage */
-
-       if ( !memcmp( srb->cmnd, mts_read_image_sig, mts_read_image_sig_len )
-) {            pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_image);
-               MTS_DEBUG( "transfering from desc->ep_image == %d\n",
-                          (int)desc->ep_image );
-       } else if ( MTS_DIRECTION_IS_IN(srb->cmnd[0]) ) {
-                       pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_response);
-                       MTS_DEBUG( "transfering from desc->ep_response == %d\n",
-                                  (int)desc->ep_response);
-       } else {
-               MTS_DEBUG("transfering to desc->ep_out == %d\n",
-                         (int)desc->ep_out);
-               pipe = usb_sndbulkpipe(desc->usb_dev,desc->ep_out);
-       }
-       desc->context.data_pipe = pipe;
-}
-
-
-static
-int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
-{
-       struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
-       int err = 0;
-       int res;
-
-       MTS_DEBUG_GOT_HERE();
-       mts_show_command(srb);
-       mts_debug_dump(desc);
-
-       if ( srb->device->lun || srb->device->id || srb->device->channel ) {
-
-               MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel );
-
-               MTS_DEBUG("this device doesn't exist\n");
-
-               srb->result = DID_BAD_TARGET << 16;
-
-               if(likely(callback != NULL))
-                       callback(srb);
-
-               goto out;
-       }
-
-       
-       FILL_BULK_URB(desc->urb,
-                     desc->usb_dev,
-                     usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
-                     srb->cmnd,
-                     srb->cmd_len,
-                     mts_command_done,
-                     &desc->context
-                     );
-
-
-       mts_build_transfer_context( srb, desc );
-       desc->context.final_callback = callback;
-       
-       /* here we need ATOMIC as we are called with the iolock */
-       res=usb_submit_urb(desc->urb, GFP_ATOMIC);
-
-       if(unlikely(res)){
-               MTS_ERROR("error %d submitting URB\n",(int)res);
-               srb->result = DID_ERROR << 16;
-
-               if(likely(callback != NULL))
-                       callback(srb);
-
-       }
-
-out:
-       return err;
-}
-/*
- * this defines our 'host'
- */
-
-/* NOTE: This is taken from usb-storage, should be right. */
-
-
-static Scsi_Host_Template mts_scsi_host_template = {
-       name:           "microtekX6",
-       detect:         mts_scsi_detect,
-       release:        mts_scsi_release,
-       queuecommand:   mts_scsi_queuecommand,
-
-       eh_abort_handler:       mts_scsi_abort,
-       eh_host_reset_handler:  mts_scsi_host_reset,
-
-       sg_tablesize:           SG_ALL,
-       can_queue:              1,
-       this_id:                -1,
-       cmd_per_lun:            1,
-       present:                0,
-       unchecked_isa_dma:      FALSE,
-       use_clustering:         TRUE,
-       emulated:               TRUE
-};
-
-
-/* USB layer driver interface implementation */
-
-static void mts_usb_disconnect (struct usb_device *dev, void *ptr)
-{
-       struct mts_desc* to_remove = (struct mts_desc*)ptr;
-
-       MTS_DEBUG_GOT_HERE();
-
-       /* leave the list - lock it */
-       down(&mts_list_semaphore);
-
-       mts_remove_nolock(to_remove);
-
-       up(&mts_list_semaphore);
-}
-
-struct vendor_product
-{
-       char* name;
-       enum
-       {
-               mts_sup_unknown=0,
-               mts_sup_alpha,
-               mts_sup_full
-       }
-       support_status;
-} ;
-
-
-/* These are taken from the msmUSB.inf file on the Windows driver CD */
-const static struct vendor_product mts_supported_products[] =
-{
-       { "Phantom 336CX",      mts_sup_unknown},
-       { "Phantom 336CX",      mts_sup_unknown},
-       { "Scanmaker X6",       mts_sup_alpha},
-       { "Phantom C6",         mts_sup_unknown},
-       { "Phantom 336CX",      mts_sup_unknown},
-       { "ScanMaker V6USL",    mts_sup_unknown},
-       { "ScanMaker V6USL",    mts_sup_unknown},
-       { "Scanmaker V6UL",     mts_sup_unknown},
-       { "Scanmaker V6UPL",    mts_sup_alpha},
-};
-
-/* The entries of microtek_table must correspond, line-by-line to
-   the entries of mts_supported_products[]. */
-
-static struct usb_device_id mts_usb_ids [] =
-{
-       { USB_DEVICE(0x4ce, 0x0300) },
-       { USB_DEVICE(0x5da, 0x0094) },
-       { USB_DEVICE(0x5da, 0x0099) },
-       { USB_DEVICE(0x5da, 0x009a) },
-       { USB_DEVICE(0x5da, 0x00a0) },
-       { USB_DEVICE(0x5da, 0x00a3) },
-       { USB_DEVICE(0x5da, 0x80a3) },
-       { USB_DEVICE(0x5da, 0x80ac) },
-       { USB_DEVICE(0x5da, 0x00b6) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, mts_usb_ids);
-
-
-static void * mts_usb_probe (struct usb_device *dev, unsigned int interface,
-                            const struct usb_device_id *id)
-{
-       int i;
-       int result;
-       int ep_out = -1;
-       int ep_in_set[3]; /* this will break if we have more than three endpoints
-                          which is why we check */
-       int *ep_in_current = ep_in_set;
-
-       struct mts_desc * new_desc;
-       struct vendor_product const* p;
-
-       /* the altsettting 0 on the interface we're probing */
-       struct usb_interface_descriptor *altsetting;
-
-       MTS_DEBUG_GOT_HERE();
-       MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev );
-
-       MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n",
-                  (int)dev->descriptor.idProduct,
-                  (int)dev->descriptor.idVendor );
-
-       MTS_DEBUG_GOT_HERE();
-
-       p = &mts_supported_products[id - mts_usb_ids];
-
-       MTS_DEBUG_GOT_HERE();
-
-       MTS_DEBUG( "found model %s\n", p->name );
-       if ( p->support_status != mts_sup_full )
-               MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n",
-                            p->name );
-
-       /* the altsettting 0 on the interface we're probing */
-       altsetting =
-               &(dev->actconfig->interface[interface].altsetting[0]);
-
-
-       /* Check if the config is sane */
-
-       if ( altsetting->bNumEndpoints != MTS_EP_TOTAL ) {
-               MTS_WARNING( "expecting %d got %d endpoints! Bailing out.\n",
-                            (int)MTS_EP_TOTAL, (int)altsetting->bNumEndpoints );
-               return NULL;
-       }
-
-       for( i = 0; i < altsetting->bNumEndpoints; i++ ) {
-               if ((altsetting->endpoint[i].bmAttributes &
-                    USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
-
-                       MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n",
-                            (int)altsetting->endpoint[i].bEndpointAddress );
-               } else {
-                       if (altsetting->endpoint[i].bEndpointAddress &
-                           USB_DIR_IN)
-                               *ep_in_current++
-                                       = altsetting->endpoint[i].bEndpointAddress &
-                                       USB_ENDPOINT_NUMBER_MASK;
-                       else {
-                               if ( ep_out != -1 ) {
-                                       MTS_WARNING( "can only deal with one output endpoints. Bailing out." );
-                                       return NULL;
-                               }
-
-                               ep_out = altsetting->endpoint[i].bEndpointAddress &
-                                       USB_ENDPOINT_NUMBER_MASK;
-                       }
-               }
-
-       }
-
-
-       if ( ep_out == -1 ) {
-               MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
-               return NULL;
-       }
-
-
-       /* I don't understand the following fully (it's from usb-storage) -- John */
-
-       /* set the interface -- STALL is an acceptable response here */
-       result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
-
-       MTS_DEBUG("usb_set_interface returned %d.\n",result);
-       switch( result )
-       {
-       case 0: /* no error */
-               break;
-               
-       case -EPIPE:
-               usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
-               MTS_DEBUG( "clearing clearing stall on control interface\n" );
-               break;
-               
-       default:
-               MTS_DEBUG( "unknown error %d from usb_set_interface\n",
-                       (int)result );
-               return NULL;
-       }
-       
-       
-       /* allocating a new descriptor */
-       new_desc = (struct mts_desc *)kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
-       if (new_desc == NULL)
-       {
-               MTS_ERROR("couldn't allocate scanner desc, bailing out!\n");
-               return NULL;
-       }
-
-       memset( new_desc, 0, sizeof(*new_desc) );
-       new_desc->urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!new_desc->urb) {
-               kfree(new_desc);
-               return NULL;
-       }
-               
-       /* initialising that descriptor */
-       new_desc->usb_dev = dev;
-       new_desc->interface = interface;
-
-       init_MUTEX(&new_desc->lock);
-
-       if(mts_list){
-               new_desc->host_number = mts_list->host_number+1;
-       } else {
-               new_desc->host_number = 0;
-       }
-       
-       /* endpoints */
-       
-       new_desc->ep_out = ep_out;
-       new_desc->ep_response = ep_in_set[0];
-       new_desc->ep_image = ep_in_set[1];
-
-
-       if ( new_desc->ep_out != MTS_EP_OUT )
-               MTS_WARNING( "will this work? Command EP is not usually %d\n",
-                            (int)new_desc->ep_out );
-
-       if ( new_desc->ep_response != MTS_EP_RESPONSE )
-               MTS_WARNING( "will this work? Response EP is not usually %d\n",
-                            (int)new_desc->ep_response );
-
-       if ( new_desc->ep_image != MTS_EP_IMAGE )
-               MTS_WARNING( "will this work? Image data EP is not usually %d\n",
-                            (int)new_desc->ep_image );
-
-
-       /* Initialize the host template based on the default one */
-       memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template));
-       /* HACK from usb-storage - this is needed for scsi detection */
-       (struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */
-
-       MTS_DEBUG("registering SCSI module\n");
-
-       new_desc->ctempl.module = THIS_MODULE;
-       result = scsi_register_host(&new_desc->ctempl);
-       /* Will get hit back in microtek_detect by this func */
-       if ( result )
-       {
-               MTS_ERROR( "error %d from scsi_register_host! Help!\n",
-                          (int)result );
-
-               /* FIXME: need more cleanup? */
-               kfree( new_desc );
-               return NULL;
-       }
-       MTS_DEBUG_GOT_HERE();
-
-       /* FIXME: the bomb is armed, must the host be registered under lock ? */
-       /* join the list - lock it */
-       down(&mts_list_semaphore);
-
-       mts_add_nolock( new_desc );
-
-       up(&mts_list_semaphore);
-
-
-       MTS_DEBUG("completed probe and exiting happily\n");
-
-       return (void *)new_desc;
-}
-
-
-
-/* get us noticed by the rest of the kernel */
-
-int __init microtek_drv_init(void)
-{
-       int result;
-
-       MTS_DEBUG_GOT_HERE();
-       init_MUTEX(&mts_list_semaphore);
-
-       if ((result = usb_register(&mts_usb_driver)) < 0) {
-               MTS_DEBUG("usb_register returned %d\n", result );
-               return -1;
-       } else {
-               MTS_DEBUG("driver registered.\n");
-       }
-
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-
-       return 0;
-}
-
-void __exit microtek_drv_exit(void)
-{
-       struct mts_desc* next;
-
-       MTS_DEBUG_GOT_HERE();
-
-       usb_deregister(&mts_usb_driver);
-
-       down(&mts_list_semaphore);
-
-       while (mts_list) {
-               /* keep track of where the next one is */
-               next = mts_list->next;
-
-               mts_remove_nolock( mts_list );
-
-               /* advance the list pointer */
-               mts_list = next;
-       }
-
-       up(&mts_list_semaphore);
-}
-
-module_init(microtek_drv_init);
-module_exit(microtek_drv_exit);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
-
diff --git a/drivers/usb/scanner/microtek.h b/drivers/usb/scanner/microtek.h
deleted file mode 100644 (file)
index 7ab7cb3..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
- /*
- * Driver for Microtek Scanmaker X6 USB scanner and possibly others.
- * 
- * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
- * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
- *
- * See microtek.c for history
- *
- */
-
-typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *);
-typedef void (*mts_usb_urb_callback) (struct urb *);
-
-
-struct mts_transfer_context
-{
-       struct mts_desc* instance;
-       mts_scsi_cmnd_callback final_callback;
-       Scsi_Cmnd *srb;
-       
-       void* data;
-       unsigned data_length;
-       int data_pipe;
-       int fragment;
-
-       u8 status; /* status returned from ep_response after command completion */
-};
-
-
-struct mts_desc {
-       struct mts_desc *next;
-       struct mts_desc *prev;
-
-       struct usb_device *usb_dev;
-
-       int interface;
-
-       /* Endpoint addresses */
-       u8 ep_out;
-       u8 ep_response;
-       u8 ep_image;
-
-       struct Scsi_Host * host;
-       Scsi_Host_Template ctempl;
-       int host_number;
-
-       struct semaphore lock;
-
-       struct urb *urb;
-       struct mts_transfer_context context;
-};
-
-
-#define MTS_EP_OUT     0x1
-#define MTS_EP_RESPONSE        0x2
-#define MTS_EP_IMAGE   0x3
-#define MTS_EP_TOTAL   0x3
-
-#define MTS_SCSI_ERR_MASK ~0x3fu
-
diff --git a/drivers/usb/scanner/scanner.c b/drivers/usb/scanner/scanner.c
deleted file mode 100644 (file)
index 22eabc5..0000000
+++ /dev/null
@@ -1,1125 +0,0 @@
-/* -*- linux-c -*- */
-
-/* 
- * Driver for USB Scanners (linux-2.4.12)
- *
- * Copyright (C) 1999, 2000, 2001 David E. Nelson
- *
- * Portions may be copyright Brad Keryan and Michael Gee.
- *
- * David E. Nelson (dnelson@jump.net)
- * 
- * 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 the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Originally based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
- *
- * History
- *
- *  0.1  8/31/1999
- *
- *    Developed/tested using linux-2.3.15 with minor ohci.c changes to
- *    support short packes during bulk xfer mode.  Some testing was
- *    done with ohci-hcd but the performace was low.  Very limited
- *    testing was performed with uhci but I was unable to get it to
- *    work.  Initial relase to the linux-usb development effort.
- *
- *
- *  0.2  10/16/1999
- *
- *    - Device can't be opened unless a scanner is plugged into the USB.
- *    - Finally settled on a reasonable value for the I/O buffer's.
- *    - Cleaned up write_scanner()
- *    - Disabled read/write stats
- *    - A little more code cleanup
- *
- *
- *  0.3  10/18/1999
- *
- *    - Device registration changed to reflect new device
- *      allocation/registration for linux-2.3.22+.
- *    - Adopted David Brownell's <david-b@pacbell.net> technique for 
- *      assigning bulk endpoints.
- *    - Removed unnessesary #include's
- *    - Scanner model now reported via syslog INFO after being detected 
- *      *and* configured.
- *    - Added user specified vendor:product USB ID's which can be passed 
- *      as module parameters.
- *
- *
- *  0.3.1
- *
- *    - Applied patches for linux-2.3.25.
- *    - Error number reporting changed to reflect negative return codes.
- *
- *
- *  0.3.2
- *
- *    - Applied patches for linux-2.3.26 to scanner_init().
- *    - Debug read/write stats now report values as signed decimal.
- *
- *
- *  0.3.3
- *
- *    - Updated the bulk_msg() calls to usb usb_bulk_msg().
- *    - Added a small delay in the write_scanner() method to aid in
- *      avoiding NULL data reads on HP scanners.  We'll see how this works.
- *    - Return values from usb_bulk_msg() now ignore positive values for
- *      use with the ohci driver.
- *    - Added conditional debugging instead of commenting/uncommenting
- *      all over the place.
- *    - kfree()'d the pointer after using usb_string() as documented in
- *      linux-usb-api.txt.
- *    - Added usb_set_configuration().  It got lost in version 0.3 -- ack!
- *    - Added the HP 5200C USB Vendor/Product ID's.
- *
- *
- *  0.3.4  1/23/2000
- *
- *    - Added Greg K-H's <greg@kroah.com> patch for better handling of 
- *      Product/Vendor detection.
- *    - The driver now autoconfigures its endpoints including interrupt
- *      endpoints if one is detected.  The concept was originally based
- *      upon David Brownell's method.
- *    - Added some Seiko/Epson ID's. Thanks to Karl Heinz 
- *      Kremer <khk@khk.net>.
- *    - Added some preliminary ioctl() calls for the PV8630 which is used
- *      by the HP4200. The ioctl()'s still have to be registered. Thanks 
- *      to Adrian Perez Jorge <adrianpj@easynews.com>.
- *    - Moved/migrated stuff to scanner.h
- *    - Removed the usb_set_configuration() since this is handled by
- *      the usb_new_device() routine in usb.c.
- *    - Added the HP 3300C.  Thanks to Bruce Tenison.
- *    - Changed user specified vendor/product id so that root hub doesn't
- *      get falsely attached to. Thanks to Greg K-H.
- *    - Added some Mustek ID's. Thanks to Gernot Hoyler 
- *      <Dr.Hoyler@t-online.de>.
- *    - Modified the usb_string() reporting.  See kfree() comment above.
- *    - Added Umax Astra 2000U. Thanks to Doug Alcorn <doug@lathi.net>.
- *    - Updated the printk()'s to use the info/warn/dbg macros.
- *    - Updated usb_bulk_msg() argument types to fix gcc warnings.
- *
- *
- *  0.4  2/4/2000
- *
- *    - Removed usb_string() from probe_scanner since the core now does a
- *      good job of reporting what was connnected.  
- *    - Finally, simultaneous multiple device attachment!
- *    - Fixed some potential memory freeing issues should memory allocation
- *      fail in probe_scanner();
- *    - Some fixes to disconnect_scanner().
- *    - Added interrupt endpoint support.
- *    - Added Agfa SnapScan Touch. Thanks to Jan Van den Bergh
- *      <jan.vandenbergh@cs.kuleuven.ac.be>.
- *    - Added Umax 1220U ID's. Thanks to Maciek Klimkowski
- *      <mac@nexus.carleton.ca>.
- *    - Fixed bug in write_scanner(). The buffer was not being properly
- *      updated for writes larger than OBUF_SIZE. Thanks to Henrik 
- *      Johansson <henrikjo@post.utfors.se> for identifying it.
- *    - Added Microtek X6 ID's. Thanks to Oliver Neukum
- *      <Oliver.Neukum@lrz.uni-muenchen.de>.
- *
- * 
- *  0.4.1  2/15/2000
- *  
- *    - Fixed 'count' bug in read_scanner(). Thanks to Henrik
- *      Johansson <henrikjo@post.utfors.se> for identifying it.  Amazing
- *      it has worked this long.
- *    - Fixed '>=' bug in both read/write_scanner methods.
- *    - Cleaned up both read/write_scanner() methods so that they are 
- *      a little more readable.
- *    - Added a lot of Microtek ID's.  Thanks to Adrian Perez Jorge.
- *    - Adopted the __initcall().
- *    - Added #include <linux/init.h> to scanner.h for __initcall().
- *    - Added one liner in irq_scanner() to keep gcc from complaining 
- *      about an unused variable (data) if debugging was disabled
- *      in scanner.c.
- *    - Increased the timeout parameter in read_scanner() to 120 Secs.
- *
- *
- *  0.4.2  3/23/2000
- *
- *    - Added Umax 1236U ID.  Thanks to Philipp Baer <ph_baer@npw.net>.
- *    - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
- *      Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
- *    - Fixed error number reported for non-existant devices.  Thanks to
- *      Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
- *    - Added Acer Prisascan 620U ID's.  Thanks to Joao <joey@knoware.nl>.
- *    - Replaced __initcall() with module_init()/module_exit(). Updates
- *      from patch-2.3.48.
- *    - Replaced file_operations structure with new syntax.  Updates
- *      from patch-2.3.49.
- *    - Changed #include "usb.h" to #include <linux/usb.h>
- *    - Added #define SCN_IOCTL to exclude development areas 
- *      since 2.4.x is about to be released. This mainly affects the 
- *      ioctl() stuff.  See scanner.h for more details.
- *    - Changed the return value for signal_pending() from -ERESTARTSYS to
- *      -EINTR.
- *
- *
- * 0.4.3  4/30/2000
- *
- *    - Added Umax Astra 2200 ID.  Thanks to Flynn Marquardt 
- *      <flynn@isr.uni-stuttgart.de>.
- *    - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>.
- *    - Added access time update for the device file courtesy of Paul
- *      Mackerras <paulus@samba.org>.  This allows a user space daemon
- *      to turn the lamp off for a Umax 1220U scanner after a prescribed
- *      time.
- *    - Fixed HP S20 ID's.  Thanks to Ruud Linders <rlinders@xs4all.nl>.
- *    - Added Acer ScanPrisa 620U ID. Thanks to Oliver
- *      Schwartz <Oliver.Schwartz@gmx.de> via sane-devel mail list.
- *    - Fixed bug in read_scanner for copy_to_user() function.  The returned
- *      value should be 'partial' not 'this_read'.
- *    - Fixed bug in read_scanner. 'count' should be decremented 
- *      by 'this_read' and not by 'partial'.  This resulted in twice as many
- *      calls to read_scanner() for small amounts of data and possibly
- *      unexpected returns of '0'.  Thanks to Karl Heinz 
- *      Kremer <khk@khk.net> and Alain Knaff <Alain.Knaff@ltnb.lu>
- *      for discovering this.
- *    - Integrated Randy Dunlap's <randy.dunlap@intel.com> patch for a
- *      scanner lookup/ident table. Thanks Randy.
- *    - Documentation updates.
- *    - Added wait queues to read_scanner().
- *
- *
- * 0.4.3.1
- *
- *    - Fixed HP S20 ID's...again..sigh.  Thanks to Ruud
- *      Linders <rlinders@xs4all.nl>.
- *
- * 0.4.4
- *    - Added addtional Mustek ID's (BearPaw 1200, 600 CU, 1200 USB,
- *      and 1200 UB.  Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
- *    - Added the Vuego Scan Brisa 340U ID's.  Apparently this scanner is
- *      marketed by Acer Peripherals as a cheap 300 dpi model. Thanks to
- *      David Gundersen <gundersd@paradise.net.nz>.
- *    - Added the Epson Expression1600 ID's. Thanks to Karl Heinz
- *      Kremer <khk@khk.net>.
- *
- * 0.4.5  2/28/2001
- *    - Added Mustek ID's (BearPaw 2400, 1200 CU Plus, BearPaw 1200F).
- *      Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
- *    - Added read_timeout module parameter to override RD_NAK_TIMEOUT
- *      when read()'ing from devices.
- *    - Stalled pipes are now checked and cleared with
- *      usb_clear_halt() for the read_scanner() function. This should
- *      address the "funky result: -32" error messages.
- *    - Removed Microtek scanner ID's.  Microtek scanners are now
- *      supported via the drivers/usb/microtek.c driver.
- *    - Added scanner specific read timeout's.
- *    - Return status errors are NEGATIVE!!!  This should address the
- *      "funky result: -110" error messages.
- *    - Replaced USB_ST_TIMEOUT with ETIMEDOUT.
- *    - rd_nak was still defined in MODULE_PARM.  It's been updated with
- *      read_timeout.  Thanks to Mark W. Webb <markwebb@adelphia.net> for
- *      reporting this bug.
- *    - Added Epson Perfection 1640SU and 1640SU Photo.  Thanks to
- *      Jean-Luc <f5ibh@db0bm.ampr.org> and Manuel
- *      Pelayo <Manuel.Pelayo@sesips.org>. Reported to work fine by Manuel.
- *
- * 0.4.6  9/27/2001
- *    - Added IOCTL's to report back scanner USB ID's.  Thanks to
- *      Karl Heinz <khk@lynx.phpwebhosting.com>
- *    - Added Umax Astra 2100U ID's.  Thanks to Ron
- *      Wellsted <ron@wellsted.org.uk>.
- *      and Manuel Pelayo <Manuel.Pelayo@sesips.org>.
- *    - Added HP 3400 ID's. Thanks to Harald Hannelius <harald@iki.fi>
- *      and Bertrik Sikken <bertrik@zonnet.nl>.  Reported to work at
- *      htpp://home.zonnet.nl/bertrik/hp3300c/hp3300c.htm.
- *    - Added Minolta Dimage Scan Dual II ID's.  Thanks to Jose Paulo
- *      Moitinho de Almeida <moitinho@civil.ist.utl.pt>
- *    - Confirmed addition for SnapScan E20.  Thanks to Steffen Hübner
- *      <hueb_s@gmx.de>.
- *    - Added Lifetec LT9385 ID's.  Thanks to Van Bruwaene Kris
- *      <krvbr@yahoo.co.uk>
- *    - Added Agfa SnapScan e26 ID's.  Reported to work with SANE
- *      1.0.5.  Thanks to Falk Sauer <falk@mgnkatze.franken.de>.
- *    - Added HP 4300 ID's.  Thanks to Stefan Schlosser
- *      <castla@grmmbl.org>.
- *    - Added Relisis Episode ID's.  Thanks to Manfred
- *      Morgner <odb-devel@gmx.net>.
- *    - Added many Acer ID's. Thanks to Oliver
- *      Schwartz <Oliver.Schwartz@gmx.de>.
- *    - Added Snapscan e40 ID's.  Thanks to Oliver
- *      Schwartz <Oliver.Schwartz@gmx.de>.
- *    - Thanks to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
- *      for helping with races.
- *    - Added Epson Perfection 1650 ID's. Thanks to Karl Heinz
- *      Kremer <khk@khk.net>.
- *    - Added Epson Perfection 2450 ID's (aka GT-9700 for the Japanese
- *      market).  Thanks to Karl Heinz Kremer <khk@khk.net>.
- *    - Added Mustek 600 USB ID's.  Thanks to Marcus
- *      Alanen <maalanen@ra.abo.fi>.
- *    - Added Acer ScanPrisa 1240UT ID's.  Thanks to Morgan
- *      Collins <sirmorcant@morcant.org>.
- *    - Incorporated devfs patches!! Thanks to Tom Rini
- *      <trini@kernel.crashing.org>, Pavel Roskin <proski@gnu.org>,
- *      Greg KH <greg@kroah.com>, Yves Duret <yduret@mandrakesoft.com>,
- *      Flavio Stanchina <flavio.stanchina@tin.it>.
- *    - Removed Minolta ScanImage II.  This scanner uses USB SCSI.  Thanks
- *      to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> for pointing
- *      this out.
- *    - Added additional SMP locking.  Thanks to David Brownell and 
- *      Oliver Neukum for their help.
- *    - Added version reporting - reports for both module load and modinfo
- *    - Started path to hopefully straighten/clean out ioctl()'s.
- *    - Users are now notified to consult the Documentation/usb/scanner.txt
- *      for common error messages rather than the maintainer.
- *
- * 0.4.7  11/28/2001
- *    - Fixed typo in Documentation/scanner.txt.  Thanks to
- *      Karel <karel.vervaeke@pandora.be> for pointing it out.
- *    - Added ID's for a Memorex 6136u. Thanks to Álvaro Gaspar de
- *      Valenzuela" <agaspard@utsi.edu>.
- *    - Added ID's for Agfa e25.  Thanks to Heinrich 
- *      Rust <Heinrich.Rust@gmx.de>.  Also reported to work with
- *      Linux and SANE (?).
- *    - Added Canon FB620U, D646U, and 1220U ID's.  Thanks to Paul
- *      Rensing <Paul_Rensing@StanfordAlumni.org>.  For more info
- *      on Linux support for these models, contact 
- *      salvestrini@users.sourceforge.net.
- *    - Added Plustek OpticPro UT12, OpticPro U24, KYE/Genius
- *      ColorPage-HR6 V2 ID's in addition to many "Unknown" models
- *      under those vendors.  Thanks to
- *      Jaeger, Gerhard" <g.jaeger@earthling.net>.  These scanner are
- *      apparently based upon the LM983x IC's.
- *    - Applied Frank's patch that addressed some locking and module
- *      referencing counts.  Thanks to both
- *      Frank Zago <fzago@greshamstorage.com> and
- *      Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
- *
- * TODO
- *    - Performance
- *    - Select/poll methods
- *    - More testing
- *    - Proper registry/assignment for LM9830 ioctl's
- *
- *
- *  Thanks to:
- *
- *    - All the folks on the linux-usb list who put up with me. :)  This 
- *      has been a great learning experience for me.
- *    - To Linus Torvalds for this great OS.
- *    - The GNU folks.
- *    - The folks that forwarded Vendor:Product ID's to me.
- *    - Johannes Erdfelt for the loaning of a USB analyzer for tracking an
- *      issue with HP-4100 and uhci.
- *    - Adolfo Montero for his assistance.
- *    - All the folks who chimed in with reports and suggestions.
- *    - All the developers that are working on USB SANE backends or other
- *      applications to use USB scanners.
- *
- *  Performance:
- *
- *    System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner
- *            300 dpi scan of the entire bed
- *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec
- *       8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
-
-#include <asm/byteorder.h>
-
-/* 
- * Scanner definitions, macros, module info, 
- * debug/ioctl/data_dump enable, and other constants.
- */ 
-#include "scanner.h"
-
-static void
-irq_scanner(struct urb *urb)
-{
-
-/*
- * For the meantime, this is just a placeholder until I figure out what
- * all I want to do with it -- or somebody else for that matter.
- */
-
-       struct scn_usb_data *scn;
-       unsigned char *data;
-       scn = urb->context;
-
-       data = &scn->button;
-       data += 0;              /* Keep gcc from complaining about unused var */
-
-       if (urb->status) {
-               return;
-       }
-
-       dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
-
-       return;
-}
-
-static int
-open_scanner(struct inode * inode, struct file * file)
-{
-       struct scn_usb_data *scn;
-       struct usb_device *dev;
-
-       int scn_minor;
-
-       int err=0;
-
-       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]) {
-               up(&scn_mutex);
-               MOD_DEC_USE_COUNT;
-               err("open_scanner(%d): Unable to access minor data", scn_minor);
-               return -ENODEV;
-       }
-
-       scn = p_scn_table[scn_minor];
-
-       dev = scn->scn_dev;
-
-       down(&(scn->sem));      /* Now protect the scn_usb_data structure */ 
-
-       up(&scn_mutex); /* Now handled by the above */
-
-       if (!dev) {
-               err("open_scanner(%d): Scanner device not present", scn_minor);
-               err = -ENODEV;
-               goto out_error;
-       }
-
-       if (!scn->present) {
-               err("open_scanner(%d): Scanner is not present", scn_minor);
-               err = -ENODEV;
-               goto out_error;
-       }
-
-       if (scn->isopen) {
-               err("open_scanner(%d): Scanner device is already open", scn_minor);
-               err = -EBUSY;
-               goto out_error;
-       }
-
-       init_waitqueue_head(&scn->rd_wait_q);
-
-       scn->isopen = 1;
-
-       file->private_data = scn; /* Used by the read and write methods */
-
-
-out_error:
-
-       up(&(scn->sem)); /* Wake up any possible contending processes */
-
-       if (err)
-               MOD_DEC_USE_COUNT;
-
-       return err;
-}
-
-static int
-close_scanner(struct inode * inode, struct file * file)
-{
-       struct scn_usb_data *scn;
-
-       int 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;
-       }
-
-       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));
-
-       MOD_DEC_USE_COUNT;
-
-       return 0;
-}
-
-static ssize_t
-write_scanner(struct file * file, const char * buffer,
-              size_t count, loff_t *ppos)
-{
-       struct scn_usb_data *scn;
-       struct usb_device *dev;
-
-       ssize_t bytes_written = 0; /* Overall count of bytes written */
-       ssize_t ret = 0;
-
-       int scn_minor;
-
-       int this_write;         /* Number of bytes to write */
-       int partial;            /* Number of bytes successfully written */
-       int result = 0;
-
-       char *obuf;
-
-       scn = file->private_data;
-
-       down(&(scn->sem));
-
-       scn_minor = scn->scn_minor;
-
-       obuf = scn->obuf;
-
-       dev = scn->scn_dev;
-
-       file->f_dentry->d_inode->i_atime = CURRENT_TIME;
-
-       while (count > 0) {
-
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-
-               this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count;
-
-               if (copy_from_user(scn->obuf, buffer, this_write)) {
-                       ret = -EFAULT;
-                       break;
-               }
-
-               result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
-               dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
-
-               if (result == -ETIMEDOUT) {     /* NAK -- shouldn't happen */
-                       warn("write_scanner: NAK received.");
-                       ret = result;
-                       break;
-               } else if (result < 0) { /* We should not get any I/O errors */
-                       warn("write_scanner(%d): funky result: %d. Consult Documentataion/usb/scanner.txt.", scn_minor, result);
-                       ret = -EIO;
-                       break;
-               }
-
-#ifdef WR_DATA_DUMP
-               if (partial) {
-                       unsigned char cnt, cnt_max;
-                       cnt_max = (partial > 24) ? 24 : partial;
-                       printk(KERN_DEBUG "dump(%d): ", scn_minor);
-                       for (cnt=0; cnt < cnt_max; cnt++) {
-                               printk("%X ", obuf[cnt]);
-                       }
-                       printk("\n");
-               }
-#endif
-               if (partial != this_write) { /* Unable to write all contents of obuf */
-                       ret = -EIO;
-                       break;
-               }
-
-               if (partial) { /* Data written */
-                       buffer += partial;
-                       count -= partial;
-                       bytes_written += partial;
-               } else { /* No data written */
-                       ret = 0;
-                       break;
-               }
-       }
-       up(&(scn->sem));
-       mdelay(5);              /* This seems to help with SANE queries */
-       return ret ? ret : bytes_written;
-}
-
-static ssize_t
-read_scanner(struct file * file, char * buffer,
-             size_t count, loff_t *ppos)
-{
-       struct scn_usb_data *scn;
-       struct usb_device *dev;
-
-       ssize_t bytes_read;     /* Overall count of bytes_read */
-       ssize_t ret;
-
-       int scn_minor;
-       int partial;            /* Number of bytes successfully read */
-       int this_read;          /* Max number of bytes to read */
-       int result;
-       int rd_expire = RD_EXPIRE;
-
-       char *ibuf;
-
-       scn = file->private_data;
-
-       down(&(scn->sem));
-
-       scn_minor = scn->scn_minor;
-
-       ibuf = scn->ibuf;
-
-       dev = scn->scn_dev;
-
-       bytes_read = 0;
-       ret = 0;
-
-       file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
-                                                            atime of
-                                                            the device
-                                                            node */
-       while (count > 0) {
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-
-               this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
-
-               result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, scn->rd_nak_timeout);
-               dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
-
-/*
- * Scanners are sometimes inheriently slow since they are mechanical
- * in nature.  USB bulk reads tend to timeout while the scanner is
- * positioning, resetting, warming up the lamp, etc if the timeout is
- * set too low.  A very long timeout parameter for bulk reads was used
- * to overcome this limitation, but this sometimes resulted in folks
- * having to wait for the timeout to expire after pressing Ctrl-C from
- * an application. The user was sometimes left with the impression
- * that something had hung or crashed when in fact the USB read was
- * just waiting on data.  So, the below code retains the same long
- * timeout period, but splits it up into smaller parts so that
- * Ctrl-C's are acted upon in a reasonable amount of time.
- */
-
-               if (result == -ETIMEDOUT) { /* NAK */
-                       if (!partial) { /* No data */
-                               if (--rd_expire <= 0) { /* Give it up */
-                                       warn("read_scanner(%d): excessive NAK's received", scn_minor);
-                                       ret = result;
-                                       break;
-                               } else { /* Keep trying to read data */
-                                       interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout);
-                                       continue;
-                               }
-                       } else { /* Timeout w/ some data */
-                               goto data_recvd;
-                       }
-               }
-               
-               if (result == -EPIPE) { /* No hope */
-                       if(usb_clear_halt(dev, scn->bulk_in_ep)) {
-                               err("read_scanner(%d): Failure to clear endpoint halt condition (%Zd).", scn_minor, ret);
-                       }
-                       ret = result;
-                       break;
-               } else if ((result < 0) && (result != -EREMOTEIO)) {
-                       warn("read_scanner(%d): funky result:%d. Consult Documentation/usb/scanner.txt.", scn_minor, (int)result);
-                       ret = -EIO;
-                       break;
-               }
-
-       data_recvd:
-
-#ifdef RD_DATA_DUMP
-               if (partial) {
-                       unsigned char cnt, cnt_max;
-                       cnt_max = (partial > 24) ? 24 : partial;
-                       printk(KERN_DEBUG "dump(%d): ", scn_minor);
-                       for (cnt=0; cnt < cnt_max; cnt++) {
-                               printk("%X ", ibuf[cnt]);
-                       }
-                       printk("\n");
-               }
-#endif
-
-               if (partial) { /* Data returned */
-                       if (copy_to_user(buffer, ibuf, partial)) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       count -= this_read; /* Compensate for short reads */
-                       bytes_read += partial; /* Keep tally of what actually was read */
-                       buffer += partial;
-               } else {
-                       ret = 0;
-                       break;
-               }
-       }
-       up(&(scn->sem));
-       return ret ? ret : bytes_read;
-}
-
-static int
-ioctl_scanner(struct inode *inode, struct file *file,
-             unsigned int cmd, unsigned long arg)
-{
-       struct usb_device *dev;
-
-       int 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;
-
-       switch (cmd)
-       {
-       case SCANNER_IOCTL_VENDOR :
-               return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
-       case SCANNER_IOCTL_PRODUCT :
-               return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
-#ifdef PV8630
-       case PV8630_IOCTL_INREQUEST :
-       {
-               int result;
-
-               struct {
-                       __u8  data;
-                       __u8  request;
-                       __u16 value;
-                       __u16 index;
-               } args;
-
-               if (copy_from_user(&args, (void *)arg, sizeof(args)))
-                       return -EFAULT;
-
-               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                                        args.request, USB_TYPE_VENDOR|
-                                        USB_RECIP_DEVICE|USB_DIR_IN,
-                                        args.value, args.index, &args.data,
-                                        1, HZ*5);
-
-               dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
-
-               if (copy_to_user((void *)arg, &args, sizeof(args)))
-                       return -EFAULT;
-
-               dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);
-
-               return result;
-       }
-       case PV8630_IOCTL_OUTREQUEST :
-       {
-               int result;
-
-               struct {
-                       __u8  request;
-                       __u16 value;
-                       __u16 index;
-               } args;
-
-               if (copy_from_user(&args, (void *)arg, sizeof(args)))
-                       return -EFAULT;
-
-               dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
-
-               result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                                        args.request, USB_TYPE_VENDOR|
-                                        USB_RECIP_DEVICE|USB_DIR_OUT,
-                                        args.value, args.index, NULL,
-                                        0, HZ*5);
-
-               dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);
-
-               return result;
-       }
-#endif /* PV8630 */
-       case SCANNER_IOCTL_CTRLMSG:
-       {
-               struct ctrlmsg_ioctl {
-                       struct usb_ctrlrequest  req;
-                       void                    *data;
-               } cmsg;
-               int pipe, nb, ret;
-               unsigned char buf[64];
-               if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
-                       return -EFAULT;
-
-               nb = le16_to_cpup(&cmsg.req.wLength);
-
-               if (nb > sizeof(buf))
-                       return -EINVAL;
-
-               if ((cmsg.req.bRequestType & 0x80) == 0) {
-                       pipe = usb_sndctrlpipe(dev, 0);
-                       if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
-                               return -EFAULT;
-               } else {
-                       pipe = usb_rcvctrlpipe(dev, 0);
-               }
-
-               ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
-                                     cmsg.req.bRequestType,
-                                     le16_to_cpup(&cmsg.req.wValue),
-                                     le16_to_cpup(&cmsg.req.wIndex),
-                                     buf, nb, HZ);
-
-               if (ret < 0) {
-                       err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
-                       return -EIO;
-               }
-
-               if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
-                       return -EFAULT;
-
-               return 0;
-       }
-       default:
-               return -ENOTTY;
-       }
-       return 0;
-}
-
-static struct
-file_operations usb_scanner_fops = {
-       read:           read_scanner,
-       write:          write_scanner,
-       ioctl:          ioctl_scanner,
-       open:           open_scanner,
-       release:        close_scanner,
-};
-
-static void *
-probe_scanner(struct usb_device *dev, unsigned int ifnum,
-             const struct usb_device_id *id)
-{
-       struct scn_usb_data *scn;
-       struct usb_interface_descriptor *interface;
-       struct usb_endpoint_descriptor *endpoint;
-
-       int ep_cnt;
-       int ix;
-       int scn_minor;
-
-       char valid_device = 0;
-       char have_bulk_in, have_bulk_out, have_intr;
-       char name[10];
-
-       if (vendor != -1 && product != -1) {
-               info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
-       }
-
-       dbg("probe_scanner: USB dev address:%p", dev);
-       dbg("probe_scanner: ifnum:%u", ifnum);
-
-/*
- * 1. Check Vendor/Product
- * 2. Determine/Assign Bulk Endpoints
- * 3. Determine/Assign Intr Endpoint
- */
-
-/*
- * There doesn't seem to be an imaging class defined in the USB
- * Spec. (yet).  If there is, HP isn't following it and it doesn't
- * look like anybody else is either.  Therefore, we have to test the
- * Vendor and Product ID's to see what we have.  Also, other scanners
- * may be able to use this driver by specifying both vendor and
- * product ID's as options to the scanner module in conf.modules.
- *
- * NOTE: Just because a product is supported here does not mean that
- * applications exist that support the product.  It's in the hopes
- * that this will allow developers a means to produce applications
- * that will support USB products.
- *
- * Until we detect a device which is pleasing, we silently punt.
- */
-
-       for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct usb_device_id); ix++) {
-               if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
-                   (dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
-                       valid_device = 1;
-                       break;
-                }
-       }
-       if (dev->descriptor.idVendor == vendor &&   /* User specified */
-           dev->descriptor.idProduct == product) { /* User specified */
-               valid_device = 1;
-       }
-
-        if (!valid_device)
-                return NULL;    /* We didn't find anything pleasing */
-
-/*
- * After this point we can be a little noisy about what we are trying to
- *  configure.
- */
-
-       if (dev->descriptor.bNumConfigurations != 1) {
-               info("probe_scanner: Only one device configuration is supported.");
-               return NULL;
-       }
-
-       if (dev->config[0].bNumInterfaces != 1) {
-               info("probe_scanner: Only one device interface is supported.");
-               return NULL;
-       }
-
-       interface = dev->config[0].interface[ifnum].altsetting;
-       endpoint = interface[ifnum].endpoint;
-
-/*
- * Start checking for two bulk endpoints OR two bulk endpoints *and* one
- * interrupt endpoint. If we have an interrupt endpoint go ahead and
- * setup the handler. FIXME: This is a future enhancement...
- */
-
-       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.");
-               return NULL;
-       }
-
-       ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
-
-       while (ep_cnt < interface->bNumEndpoints) {
-
-               if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {
-                       ep_cnt++;
-                       have_bulk_in = ep_cnt;
-                       dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
-                       continue;
-               }
-
-               if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
-                       ep_cnt++;
-                       have_bulk_out = ep_cnt;
-                       dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
-                       continue;
-               }
-
-               if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {
-                       ep_cnt++;
-                       have_intr = ep_cnt;
-                       dbg("probe_scanner: intr_ep:%d", have_intr);
-                       continue;
-               }
-               info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
-               return NULL;    /* Shouldn't ever get here unless we have something weird */
-       }
-
-
-/*
- * Perform a quick check to make sure that everything worked as it
- * should have.
- */
-
-       switch(interface->bNumEndpoints) {
-       case 2:
-               if (!have_bulk_in || !have_bulk_out) {
-                       info("probe_scanner: Two bulk endpoints required.");
-                       return NULL;
-               }
-               break;
-       case 3:
-               if (!have_bulk_in || !have_bulk_out || !have_intr) {
-                       info("probe_scanner: Two bulk endpoints and one interrupt endpoint required.");
-                       return NULL;
-               }
-               break;
-       default:
-               info("probe_scanner: Endpoint determination failed --  consult Documentation/usb/scanner.txt");
-               return NULL;
-       }
-
-
-/*
- * Determine a minor number and initialize the structure associated
- * with it.  The problem with this is that we are counting on the fact
- * that the user will sequentially add device nodes for the scanner
- * devices.  */
-       
-       down(&scn_mutex);
-
-       for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
-               if (!p_scn_table[scn_minor])
-                       break;
-       }
-
-/* Check to make sure that the last slot isn't already taken */
-       if (p_scn_table[scn_minor]) {
-               err("probe_scanner: No more minor devices remaining.");
-               up(&scn_mutex);
-               return NULL;
-       }
-
-       dbg("probe_scanner: Allocated minor:%d", scn_minor);
-
-       if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
-               err("probe_scanner: Out of memory.");
-               up(&scn_mutex);
-               return NULL;
-       }
-       memset (scn, 0, sizeof(struct scn_usb_data));
-
-       scn->scn_irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!scn->scn_irq) {
-               kfree(scn);
-               up(&scn_mutex);
-               return NULL;
-       }
-
-       init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
-
-       dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
-
-/* Ok, if we detected an interrupt EP, setup a handler for it */
-       if (have_intr) {
-               dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
-               FILL_INT_URB(scn->scn_irq, dev,
-                            usb_rcvintpipe(dev, have_intr),
-                            &scn->button, 1, irq_scanner, scn,
-                            // endpoint[(int)have_intr].bInterval);
-                            250);
-
-               if (usb_submit_urb(scn->scn_irq, GFP_KERNEL)) {
-                       err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
-                       kfree(scn);
-                       up(&scn_mutex);
-                       return NULL;
-               }
-       }
-
-
-/* Ok, now initialize all the relevant values */
-       if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
-               err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
-               kfree(scn);
-               up(&scn_mutex);
-               return NULL;
-       }
-       dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);
-
-       if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
-               err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
-               kfree(scn->obuf);
-               kfree(scn);
-               up(&scn_mutex);
-               return NULL;
-       }
-       dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
-       
-
-       switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
-       case 0x04b8:            /* Seiko/Epson */
-               scn->rd_nak_timeout = HZ * 40;
-               break;
-       case 0x055f:            /* Mustek */
-       case 0x0400:            /* Another Mustek */
-       case 0x0ff5:            /* And yet another Mustek */
-               scn->rd_nak_timeout = HZ * 1;
-       default:
-               scn->rd_nak_timeout = RD_NAK_TIMEOUT;
-       }
-
-
-       if (read_timeout > 0) { /* User specified read timeout overrides everything */
-               info("probe_scanner: User specified USB read timeout - %d", read_timeout);
-               scn->rd_nak_timeout = read_timeout;
-       }
-
-
-       scn->bulk_in_ep = have_bulk_in;
-       scn->bulk_out_ep = have_bulk_out;
-       scn->intr_ep = have_intr;
-       scn->present = 1;
-       scn->scn_dev = dev;
-       scn->scn_minor = scn_minor;
-       scn->isopen = 0;
-
-       sprintf(name, "scanner%d", scn->scn_minor);
-       
-       scn->devfs = devfs_register(usb_devfs_handle, name,
-                                   DEVFS_FL_DEFAULT, USB_MAJOR,
-                                   SCN_BASE_MNR + scn->scn_minor,
-                                   S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
-                                   S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
-       if (scn->devfs == NULL)
-               dbg("scanner%d: device node registration failed", scn_minor);
-
-       p_scn_table[scn_minor] = scn;
-
-       up(&scn_mutex);
-
-       return scn;
-}
-
-static void
-disconnect_scanner(struct usb_device *dev, void *ptr)
-{
-       struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
-
-       down (&scn_mutex);
-       down (&(scn->sem));
-
-       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]);
-
-       kfree(scn->ibuf);
-       kfree(scn->obuf);
-
-       dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
-       devfs_unregister(scn->devfs);
-       p_scn_table[scn->scn_minor] = NULL;
-       usb_free_urb(scn->scn_irq);
-       up (&(scn->sem));
-       kfree (scn);
-       up (&scn_mutex);
-}
-
-static struct
-usb_driver scanner_driver = {
-       name:           "usbscanner",
-       probe:          probe_scanner,
-       disconnect:     disconnect_scanner,
-       fops:           &usb_scanner_fops,
-       minor:          SCN_BASE_MNR,
-       id_table:       NULL, /* This would be scanner_device_ids, but we
-                                need to check every USB device, in case
-                                we match a user defined vendor/product ID. */
-};
-
-void __exit
-usb_scanner_exit(void)
-{
-       usb_deregister(&scanner_driver);
-}
-
-int __init
-usb_scanner_init (void)
-{
-        if (usb_register(&scanner_driver) < 0)
-                return -1;
-
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-       return 0;
-}
-
-module_init(usb_scanner_init);
-module_exit(usb_scanner_exit);
diff --git a/drivers/usb/scanner/scanner.h b/drivers/usb/scanner/scanner.h
deleted file mode 100644 (file)
index be6c26a..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Driver for USB Scanners (linux-2.4.12)
- *
- * Copyright (C) 1999, 2000, 2001 David E. Nelson
- *
- * David E. Nelson (dnelson@jump.net)
- *
- * 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 the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */ 
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <asm/uaccess.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/ioctl.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
-
-// #define DEBUG
-
-/* Enable this to support the older ioctl interfaces scanners that
- * a PV8630 Scanner-On-Chip.  The prefered method is the
- * SCANNER_IOCTL_CTRLMSG ioctl.
- */
-// #define PV8630 
-
-#define DRIVER_VERSION "0.4.6"
-#define DRIVER_DESC "USB Scanner Driver"
-
-#include <linux/usb.h>
-
-static __s32 vendor=-1, product=-1, read_timeout=0;
-
-MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
-MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(vendor, "i");
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-MODULE_PARM(product, "i");
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-
-MODULE_PARM(read_timeout, "i");
-MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
-
-
-/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
-// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
-// #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
-
-static struct usb_device_id scanner_device_ids [] = {
-       /* Acer */
-       { USB_DEVICE(0x04a5, 0x2060) }, /* Prisa Acerscan 620U & 640U (!)*/
-       { USB_DEVICE(0x04a5, 0x2040) }, /* Prisa AcerScan 620U (!) */
-       { USB_DEVICE(0x04a5, 0x20c0) },  /* Prisa AcerScan 1240UT */
-       { USB_DEVICE(0x04a5, 0x2022) }, /* Vuego Scan Brisa 340U */
-       { USB_DEVICE(0x04a5, 0x1a20) }, /* Unknown - Oliver Schwartz */
-       { USB_DEVICE(0x04a5, 0x1a2a) }, /* Unknown - Oliver Schwartz */
-       { USB_DEVICE(0x04a5, 0x207e) }, /* Prisa 640BU */
-       { USB_DEVICE(0x04a5, 0x20be) }, /* Unknown - Oliver Schwartz */
-       { USB_DEVICE(0x04a5, 0x20c0) }, /* Unknown - Oliver Schwartz */
-       { USB_DEVICE(0x04a5, 0x20de) }, /* S2W 3300U */
-       { USB_DEVICE(0x04a5, 0x20b0) }, /* Unknown - Oliver Schwartz */
-       { USB_DEVICE(0x04a5, 0x20fe) }, /* Unknown - Oliver Schwartz */
-       /* Agfa */
-       { USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */
-       { USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */
-       { USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/
-       { USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */
-       { USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
-       { USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
-       { USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
-       { USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
-       /* Canon */
-       { USB_DEVICE(0x04a9, 0x2202) }, /* FB620U */
-       { USB_DEVICE(0x04a9, 0x220b) }, /* D646U */
-       { USB_DEVICE(0x04a9, 0x2207) }, /* 1220U */
-       /* Colorado -- See Primax/Colorado below */
-       /* Epson -- See Seiko/Epson below */
-       /* Genius */
-       { USB_DEVICE(0x0458, 0x2001) }, /* ColorPage-Vivid Pro */
-       { USB_DEVICE(0x0458, 0x2007) }, /* ColorPage HR6 V2 */
-       { USB_DEVICE(0x0458, 0x2008) }, /* Unknown */
-       { USB_DEVICE(0x0458, 0x2009) }, /* Unknown */
-       { USB_DEVICE(0x0458, 0x2013) }, /* Unknown */
-       { USB_DEVICE(0x0458, 0x2015) }, /* Unknown  */
-       { USB_DEVICE(0x0458, 0x2016) }, /* Unknown  */
-       /* Hewlett Packard */
-       { USB_DEVICE(0x03f0, 0x0205) }, /* 3300C */
-       { USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
-       { USB_DEVICE(0x03f0, 0x0101) }, /* 4100C */
-       { USB_DEVICE(0x03f0, 0x0105) }, /* 4200C */
-       { USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
-       { USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
-       { USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */
-       //      { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
-       { USB_DEVICE(0x03f0, 0x0201) }, /* 6200C */
-       { USB_DEVICE(0x03f0, 0x0601) }, /* 6300C */
-       { USB_DEVICE(0x03f0, 0x605) },  /* 2200C */
-       /* iVina */
-       { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
-       /* Lifetec */
-       { USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
-       /* Memorex */
-       { USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
-       /* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
-       //      { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */
-       //      { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */
-       //      { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */
-       //      { USB_DEVICE(0x05da, 0x009a) }, /* Phantom C6 */
-       //      { USB_DEVICE(0x05da, 0x00a3) }, /* ScanMaker V6USL */
-       //      { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */
-       //      { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */
-       /* Minolta */
-       //      { USB_DEVICE(0x0638,0x026a) }, /* Minolta Dimage Scan Dual II */
-       /* Mustek */
-       { USB_DEVICE(0x055f, 0x0001) }, /* 1200 CU */
-       { USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 */
-       { USB_DEVICE(0x055f, 0x0002) }, /* 600 CU */
-       { USB_DEVICE(0x055f, 0x0873) }, /* 600 USB */
-       { USB_DEVICE(0x055f, 0x0003) }, /* 1200 USB */
-       { USB_DEVICE(0x055f, 0x0006) }, /* 1200 UB */
-       { USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
-       { USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
-       { USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
-       /* Plustek */
-       { USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12 */
-       { USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro UT24 */
-       { USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x000F) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0010) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0015) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
-       { USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
-       /* Primax/Colorado */
-       { USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */
-       { USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */
-       { USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */
-       { USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */
-       { USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */
-       { USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */
-       { USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */
-       { USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
-       { USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */
-       // { USB_DEVICE(0x0461, 0x0360) },      /* Colorado USB 19200 - undetected endpoint */
-       { USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */
-       { USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */
-       /* Relisis */
-       // { USB_DEVICE(0x0475, 0x0103) },      /* Episode - undetected endpoint */
-       /* Seiko/Epson Corp. */
-       { USB_DEVICE(0x04b8, 0x0101) }, /* Perfection 636U and 636Photo */
-       { USB_DEVICE(0x04b8, 0x0103) }, /* Perfection 610 */
-       { USB_DEVICE(0x04b8, 0x0104) }, /* Perfection 1200U and 1200Photo*/
-       { USB_DEVICE(0x04b8, 0x0106) }, /* Stylus Scan 2500 */
-       { USB_DEVICE(0x04b8, 0x0107) }, /* Expression 1600 */
-       { USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
-       { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
-       { USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
-       { USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
-       { USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
-       { USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
-       /* Umax */
-       { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
-       { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
-       { USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */
-       { USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */
-       /* Visioneer */
-       { USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
-       { USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */
-       { USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */
-       { USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */
-       { USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */
-       { USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */
-       { }                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, scanner_device_ids);
-
-#define IS_EP_BULK(ep)  ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
-#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
-#define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
-
-#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
-
-#ifdef DEBUG
-#define SCN_DEBUG(X) X
-#else
-#define SCN_DEBUG(X)
-#endif
-
-#define IBUF_SIZE 32768
-#define OBUF_SIZE 4096
-
-/* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */
-#define RD_NAK_TIMEOUT (10*HZ) /* Default number of X seconds to wait */
-#define RD_EXPIRE 12           /* Number of attempts to wait X seconds */
-
-
-/* FIXME: These are NOT registered ioctls()'s */
-#ifdef PV8630
-#define PV8630_IOCTL_INREQUEST 69
-#define PV8630_IOCTL_OUTREQUEST 70
-#endif /* PV8630 */
-
-
-/* read vendor and product IDs from the scanner */
-#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
-#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
-/* send/recv a control message to the scanner */
-#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest)
-
-
-#define SCN_MAX_MNR 16         /* We're allocated 16 minors */
-#define SCN_BASE_MNR 48                /* USB Scanners start at minor 48 */
-
-static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
-
-struct scn_usb_data {
-       struct usb_device *scn_dev;
-       devfs_handle_t devfs;   /* devfs device */
-       struct urb *scn_irq;
-       unsigned int ifnum;     /* Interface number of the USB device */
-       int scn_minor;          /* Scanner minor - used in disconnect() */
-       unsigned char button;   /* Front panel buffer */
-       char isopen;            /* Not zero if the device is open */
-       char present;           /* Not zero if device is present */
-       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 sem; /* lock to prevent concurrent reads or writes */
-       unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */
-};
-
-extern devfs_handle_t usb_devfs_handle;
-
-static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
-
-static struct usb_driver scanner_driver;
index 349c9be41f25e910592d6216404c14ae5f1b0970..b5e669b2b4dc9547f9d8e0dba803b56761756b99 100644 (file)
@@ -28,7 +28,7 @@ subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate
 obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
 
 include $(TOPDIR)/drivers/net/Makefile.lib
-include $(TOPDIR)/drivers/usb/Makefile.lib
+include $(TOPDIR)/drivers/usb/class/Makefile.lib
 include $(TOPDIR)/fs/Makefile.lib
 
 include $(TOPDIR)/Rules.make