Hi all,

I've done the integration of the umax USB backend. I've tried to be as
less intrusive as possible. I don't expect to do more changes,
unless someone objects to the current code.

In the umax backend:
Most of the changes touching the SCSI code are the umax_scsi_* function
that replace the sanei_scsi_*. The code has been tested on the USB scanner
only. The SCSI part may have been broken (I can't check that).

In the sanei_usb code:
Added a sanei_usb_control_msg() function to send/received control
messages.

On linux, if you want to try it with a usb scanner, apply that patch to
the usb scanner driver before (or else bad things will happen):
 http://marc.theaimsgroup.com/?l=linux-usb-devel&m=100645814202605&q=p3

Regards,
  Frank.

diff -P -r -u sane-backends-1.0.6.orig/backend/dodebug 
sane-backends-1.0.6/backend/dodebug
--- sane-backends-1.0.6.orig/backend/dodebug    Wed Dec 31 18:00:00 1969
+++ sane-backends-1.0.6/backend/dodebug Wed Nov 21 16:26:23 2001
@@ -0,0 +1,4 @@
+setenv SANE_DEBUG_DLL 128
+setenv SANE_DEBUG_UMAX 128
+setenv SANE_DEBUG_SANEI_SCSI 128
+setenv SANE_DEBUG_SANEI_USB 128
diff -P -r -u sane-backends-1.0.6.orig/backend/umax-usb.c 
sane-backends-1.0.6/backend/umax-usb.c
--- sane-backends-1.0.6.orig/backend/umax-usb.c Wed Dec 31 18:00:00 1969
+++ sane-backends-1.0.6/backend/umax-usb.c      Thu Nov 22 22:31:37 2001
@@ -0,0 +1,425 @@
+/* ---------------------------------------------------------------------- */
+
+/* sane - Scanner Access Now Easy.
+
+   umax.c 
+
+   (C) 2001 Frank Zago
+   (C) 2000 Adrian Perez Jorge   (PV8630 code)
+
+   This file is part of the SANE package.
+
+   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., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, the authors of SANE give permission for
+   additional uses of the libraries contained in this release of SANE.
+
+   The exception is that, if you link a SANE library with other files
+   to produce an executable, this does not by itself cause the
+   resulting executable to be covered by the GNU General Public
+   License.  Your use of that executable is in no way restricted on
+   account of linking the SANE library code into it.
+
+   This exception does not, however, invalidate any other reasons why
+   the executable file might be covered by the GNU General Public
+   License.
+
+   If you submit changes to SANE to the maintainers to be included in
+   a subsequent release, you agree by submitting the changes that
+   those changes may be distributed with this exception intact.
+
+   If you write modifications of your own for SANE, it is your choice
+   whether to permit this exception to apply to your modifications.
+   If you do not wish that, delete this exception notice.
+
+   This file implements a SANE backend for UMAX USB flatbed scanners.  */
+
+
+/* ---------------------------------------------------------------------- */
+
+/* USB specific parts */
+
+/* 
+ * PV8630
+ *
+ * The following drives the PV 8630. The PowerVision 8630 is a USB to
+ * parallel converter.
+ * The defines comes from the sane 1220U backend. 
+ * Most function do not check for errors because I don't know how to recover from 
+these.
+ */
+
+/* request */
+#define PV8630_REQ_READBYTE         0x00
+#define PV8630_REQ_WRITEBYTE        0x01
+#define PV8630_REQ_EPPBULKREAD      0x02
+#define PV8630_REQ_EPPBULKWRITE     0x03
+#define PV8630_REQ_FLUSHBUFFER      0x04
+#define PV8630_REQ_ENABLEINTERRUPT  0x05
+#define PV8630_REQ_DISABLEINTERRUPT 0x06
+#define PV8630_REQ_READWORD         0x08
+#define PV8630_REQ_WRITEWORD        0x09
+
+/* index */
+#define PV8630_RDATA       0x00
+#define PV8630_REPPADDRESS 0x01
+#define PV8630_UNKNOWN    0x02
+#define PV8630_RMODE       0x03
+#define PV8630_RSTATUS     0x04
+
+/* Write one control byte */
+static void pv8630_write_byte(int fd, int value, int index)
+{
+       if (sanei_usb_control_msg(fd, 0x40, PV8630_REQ_WRITEBYTE, value, index, 0, 
+NULL) != SANE_STATUS_GOOD) {
+               DBG(DBG_error, "usb_control_msg PV8630_REQ_WRITEBYTE error\n");
+       }
+}
+
+/* Read one control byte */
+static void pv8630_read_byte(int fd, unsigned char *data, int index)
+{
+       if (sanei_usb_control_msg(fd, 0xc0, PV8630_REQ_READBYTE, 0, index, 1, data) != 
+SANE_STATUS_GOOD) {
+               DBG(DBG_error, "usb_control_msg PV8630_REQ_READBYTE error\n");
+       }
+}
+
+/* Flush the buffer. */
+static void pv8630_flush_buffer(int fd)
+{
+       if (sanei_usb_control_msg(fd, 0x40, PV8630_REQ_FLUSHBUFFER, 0, 0, 0, NULL) != 
+SANE_STATUS_GOOD) {
+               DBG(DBG_error, "usb_control_msg PV8630_REQ_FLUSHBUFFER error\n");
+       }
+}
+
+/* Prepare a bulk write. len is the size of the data going to be
+ * written by pv8630_bulkwrite(). */
+static void pv8630_prep_bulkwrite(int fd, size_t len)
+{
+       if (sanei_usb_control_msg(fd, 0x40, PV8630_REQ_EPPBULKWRITE, len & 0xffff, len 
+>> 16, 0, NULL) != SANE_STATUS_GOOD) {
+               DBG(DBG_error, "usb_control_msg PV8630_REQ_EPPBULKWRITE error\n");
+       }
+}
+
+/* Prepare a bulk read. len is the size of the data going to be
+ * read by pv8630_bulkread(). */
+static void pv8630_prep_bulkread(int fd, size_t len)
+{
+       if (sanei_usb_control_msg(fd, 0x40, PV8630_REQ_EPPBULKREAD, len & 0xffff, len 
+>> 16, 0, NULL) != SANE_STATUS_GOOD) {
+               DBG(DBG_error, "usb_control_msg PV8630_REQ_EPPBULKREAD error\n");
+       }
+}
+
+/* Do a bulk write. The length must have previously been sent via
+ * pv8630_prep_bulkwrite(). */
+static void pv8630_bulkwrite(int fd, const void *data, size_t *len)
+{
+       if (sanei_usb_write_bulk(fd, (char *)data, len) != SANE_STATUS_GOOD) {
+               DBG(DBG_error, "sanei_usb_write_bulk error\n");
+       }
+}
+
+/* Do a bulk read. The length must have previously been sent via
+ * pv8630_prep_bulkread(). */
+static size_t pv8630_bulkread(int fd, void *data, size_t *len)
+{
+       if (sanei_usb_read_bulk(fd, data, len) != SANE_STATUS_GOOD) {
+               DBG(DBG_error, "sanei_usb_read_bulk error\n");
+       }
+
+       return(SANE_STATUS_GOOD);
+}
+
+/* Wait for the status register to present a given status. */
+static SANE_Status pv8630_status_wait(int fd, unsigned char status)
+{
+       unsigned char s;
+       int i;
+
+       for (i=0; i<1000; i++) {
+               pv8630_read_byte(fd, &s, PV8630_RSTATUS);
+               if (s == status) {
+                       return(SANE_STATUS_GOOD);
+               }
+               usleep(100000);
+       }
+       DBG(DBG_error, "status never ok\n");
+
+       return(SANE_STATUS_IO_ERROR);
+}
+
+/* Apparently this will recover from some errors. */
+static void pv8630_mini_init_scanner(int fd)
+{
+       DBG(DBG_info, "mini_init_scanner\n");
+
+       /* Init the device (?) */
+       pv8630_write_byte(fd, 0x04, PV8630_UNKNOWN);
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+
+       pv8630_status_wait(fd, 0xd0);
+}
+
+/* Length of the CDB given the SCSI command. The last two might not be
+   correct (vendor reserved). */
+static u_char cdb_sizes[8] = {
+    6, 10, 10, 6, 16, 12, 0, 0
+};
+#define CDB_SIZE(opcode)       cdb_sizes[(((opcode) >> 5) & 7)]
+
+/* Sends a CDB to the scanner. Also sends the parameters and receives
+ * the data, if necessary. When this function returns with a
+ * SANE_STATUS_GOOD, the SCSI command has been completed. 
+ *
+ * Note: I don't know about deferred commands.
+ */
+static SANE_Status sanei_umaxusb_cmd(int fd, const void *src, size_t src_size, void 
+*dst, size_t * dst_size)
+{
+       unsigned char result;
+       size_t cmd_size = CDB_SIZE (*(char *) src);
+       size_t param_size = src_size - cmd_size;
+       char * param_ptr = ((char *) src) + cmd_size;
+       size_t tmp_len;
+       
+       DBG(DBG_info, "Sending SCSI cmd 0x%02x cdb len %d, param len %d, result len 
+%d\n", ((unsigned char *)src)[0], cmd_size, param_size, dst_size? *dst_size:0);
+
+       /* This looks like some kinf of pre-initialization. */
+       pv8630_write_byte(fd, 0x0c, PV8630_UNKNOWN);
+       pv8630_status_wait(fd, 0xf0);
+       pv8630_write_byte(fd, 0x04, PV8630_UNKNOWN);
+
+       /* Send the CDB and check it's been received OK. */
+       pv8630_write_byte(fd, 0x16, PV8630_RMODE);
+       pv8630_flush_buffer(fd);
+       pv8630_prep_bulkwrite(fd, cmd_size);
+       
+       tmp_len = cmd_size;
+       pv8630_bulkwrite(fd, src, &tmp_len);
+       pv8630_status_wait(fd, 0xf8);
+
+       pv8630_flush_buffer(fd);
+       pv8630_prep_bulkread(fd, 1);
+
+       result = 0xA5;                          /* to be sure */
+       tmp_len = 1;
+       pv8630_bulkread(fd, &result, &tmp_len);
+       if (result != 0) {
+               DBG(DBG_info, "error in pv8630_bulkread (got %02x)\n", result);
+               if (result == 8) {
+                       pv8630_mini_init_scanner(fd);
+               }
+               return(SANE_STATUS_IO_ERROR);
+       }
+       
+       /* Send the parameters and check they've been received OK. */
+       if (param_size) {
+               pv8630_flush_buffer(fd);
+               pv8630_prep_bulkwrite(fd, param_size);
+               
+               tmp_len = param_size;
+               pv8630_bulkwrite(fd, param_ptr, &tmp_len);
+               pv8630_status_wait(fd, 0xf8);
+               
+               pv8630_flush_buffer(fd);
+               pv8630_prep_bulkread(fd, 1);
+               
+               result = 0xA5;                          /* to be sure */
+               tmp_len = 1;
+               pv8630_bulkread(fd, &result, &tmp_len);
+               if (result != 0) {
+                       DBG(DBG_info, "error in pv8630_bulkread (got %02x)\n", 
+result);
+                       if (result == 8) {
+                               pv8630_mini_init_scanner(fd);
+                       }
+                       return(SANE_STATUS_IO_ERROR);
+               }
+       }
+
+       /* If the SCSI command expect a return, get it. */
+       if (dst_size != NULL && *dst_size != 0 && dst != NULL) {
+               pv8630_flush_buffer(fd);
+               pv8630_prep_bulkread(fd, *dst_size);
+               pv8630_bulkread(fd, dst, dst_size);
+
+               DBG(DBG_info, "  SCSI cmd returned %d bytes\n", *dst_size);
+
+               pv8630_status_wait(fd, 0xf8);
+
+               pv8630_flush_buffer(fd);
+               pv8630_prep_bulkread(fd, 1);
+
+               result = 0x5A;                  /* just to be sure */
+               tmp_len = 1;
+               pv8630_bulkread(fd, &result, &tmp_len);
+               if (result != 0) {
+                       DBG(DBG_info, "error in pv8630_bulkread (got %02x)\n", 
+result);
+                       if (result == 8) {
+                               pv8630_mini_init_scanner(fd);
+                       }
+                       return(SANE_STATUS_IO_ERROR);
+               }
+       }
+
+       pv8630_write_byte(fd, 0x04, PV8630_UNKNOWN);
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+       pv8630_status_wait(fd, 0xd0);
+
+       DBG(DBG_info, "  SCSI command successfully executed\n");
+ 
+       return(SANE_STATUS_GOOD);
+}
+
+/* Initialize the PowerVision 8630. */
+static SANE_Status pv8630_init_umaxusb_scanner(int fd)
+{
+       DBG(DBG_info, "Initializing the PV8630\n");
+
+       /* Init the device */
+       pv8630_write_byte(fd, 0x04, PV8630_UNKNOWN);
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+
+       pv8630_status_wait(fd, 0xd0);
+
+       pv8630_write_byte(fd, 0x0c, PV8630_UNKNOWN);
+       pv8630_status_wait(fd, 0xf0);
+
+       pv8630_write_byte(fd, 0x04, PV8630_UNKNOWN);
+       pv8630_status_wait(fd, 0xf0);
+
+       pv8630_write_byte(fd, 0x0c, PV8630_UNKNOWN);
+       pv8630_status_wait(fd, 0xf0);
+       pv8630_status_wait(fd, 0xf8);
+
+       pv8630_write_byte(fd, 0x04, PV8630_UNKNOWN);
+
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+       pv8630_write_byte(fd, 0x02, PV8630_RMODE);
+       pv8630_status_wait(fd, 0xd0);
+
+       pv8630_write_byte(fd, 0x0c, PV8630_UNKNOWN);
+       pv8630_status_wait(fd, 0xf0);
+
+       pv8630_write_byte(fd, 0x04, PV8630_UNKNOWN);
+
+       pv8630_write_byte(fd, 0x16, PV8630_RMODE);
+
+       DBG(DBG_info, "PV8630 initialized\n");
+       
+       return(SANE_STATUS_GOOD);
+}
+
+/* End of the PV8630 code */
+
+/* 
+ * SCSI functions for the emulation.
+ *
+ * The following functions emulate their sanei_scsi_counterpart.
+ *
+ */
+
+
+/* 
+ * sanei_umaxusb_req_wait() and sanei_umaxusb_req_enter()
+ *
+ * I don't know if it is possible to queue the reads to the
+ * scanner. So The queing is disabled. The performance does not seems
+ * to be bad anyway.
+ */
+
+static void *umaxusb_req_buffer; /* keep the buffer ptr as an ID */
+
+static SANE_Status sanei_umaxusb_req_enter (int fd,
+                                                                                      
+ const void *src, size_t src_size,
+                                                                                      
+ void *dst, size_t * dst_size, void **idp)
+{
+       umaxusb_req_buffer = *idp = dst;
+       return(sanei_umaxusb_cmd(fd, src, src_size, dst, dst_size));
+}
+
+static SANE_Status
+sanei_umaxusb_req_wait (void *id)
+{
+       if (id != umaxusb_req_buffer) {
+               DBG(DBG_info, "sanei_umaxusb_req_wait: AIE, invalid id\n");
+               return(SANE_STATUS_IO_ERROR);
+       }
+       return(SANE_STATUS_GOOD);
+}
+
+/* Open the device. 
+ */
+SANE_Status
+sanei_umaxusb_open (const char *dev, int *fdp,
+                                       SANEI_SCSI_Sense_Handler handler, void 
+*handler_arg)
+{
+       *fdp = open (dev, O_RDWR | O_EXCL);
+       if (*fdp == -1) {
+               SANE_Status status = SANE_STATUS_INVAL;
+
+               if (errno == EACCES)
+                       status = SANE_STATUS_ACCESS_DENIED;
+               
+               DBG (1, "sanei_umaxusb_open: open of `%s' failed: %s\n",
+                        dev, strerror (errno));
+               return status;
+    } else {
+               SANE_Word vendor;
+               SANE_Word product;
+
+               /* We have openned the device. Check that it is a USB scanner. */
+               if (sanei_usb_get_vendor_product (*fdp, &vendor, &product) != 
+SANE_STATUS_GOOD) {
+                       /* This is not a USB scanner, or SANE or the OS doesn't 
+support it. */
+                       close(*fdp);
+                       *fdp = -1;
+                       return SANE_STATUS_UNSUPPORTED;
+               }
+
+               /* So it's a scanner. Does this backend support it?
+                * Only the UMAX 2200 USB is currently supported. */
+               if (vendor != 0x1606 && product != 0x0230) {
+                       close(*fdp);
+                       *fdp = -1;
+                       return SANE_STATUS_UNSUPPORTED;
+               }
+               
+               /* It's a good scanner. Initialize it.  
+                *
+                * Note: pv8630_init_umaxusb_scanner() is for the UMAX
+                * 2200. Other UMAX scanner might need a different
+                * initialization routine. */
+
+               pv8630_init_umaxusb_scanner(*fdp); 
+       }
+       
+       return(SANE_STATUS_GOOD);
+}
+
+/* sanei_umaxusb_open_extended() is just a passthrough for sanei_umaxusb_open(). */
+SANE_Status
+sanei_umaxusb_open_extended (const char *dev, int *fdp,
+                                       SANEI_SCSI_Sense_Handler handler, void 
+*handler_arg, int *buffersize)
+{
+       return(sanei_umaxusb_open(dev, fdp, handler, handler_arg));
+}
+
+/* Close the scanner. */
+void
+sanei_umaxusb_close (int fd)
+{
+       close(fd);
+}
+
diff -P -r -u sane-backends-1.0.6.orig/backend/umax.c 
sane-backends-1.0.6/backend/umax.c
--- sane-backends-1.0.6.orig/backend/umax.c     Sat Oct 27 06:57:45 2001
+++ sane-backends-1.0.6/backend/umax.c  Thu Nov 22 22:42:24 2001
@@ -129,12 +129,14 @@
 #include "sane/saneopts.h"
 #include "sane/sanei_scsi.h"
 #include "sane/sanei_debug.h"
+#include "sane/sanei_usb.h"
 
 #include <math.h>
 #include <string.h>
 
 #include "umax-scsidef.h"
 #include "umax-scanner.c"
+#include "umax-usb.c"
 
 #include "umax.h"
 #include "sane/sanei_backend.h"
@@ -1218,6 +1220,104 @@
 }
 
 
+/* ------------- Switches between the SCSI and USB commands 
+-------------------------------- */
+
+static SANE_Status
+umax_scsi_cmd (Umax_Device *dev, const void *src, size_t src_size,
+                          void *dst, size_t * dst_size)
+{
+       switch (dev->connection_type) {
+       case SANE_UMAX_SCSI:
+               return sanei_scsi_cmd(dev->sfd, src, src_size, dst, dst_size);
+               break;
+       case SANE_UMAX_USB:
+               return sanei_umaxusb_cmd(dev->sfd, src, src_size, dst, dst_size);
+               break;
+       default:
+               return(SANE_STATUS_INVAL);
+       }
+}
+
+static SANE_Status
+umax_scsi_open_extended (const char *devicename, Umax_Device *dev,
+                         SANEI_SCSI_Sense_Handler handler,
+                         void *handler_arg, int *buffersize)
+{
+       switch (dev->connection_type) {
+       case SANE_UMAX_SCSI:
+               return sanei_scsi_open_extended(devicename, &dev->sfd, handler, 
+handler_arg, buffersize);
+               break;
+       case SANE_UMAX_USB:
+               return sanei_umaxusb_open_extended(devicename, &dev->sfd, handler, 
+handler_arg, buffersize);
+               break;
+       default:
+               return(SANE_STATUS_INVAL);
+       }
+}
+
+static SANE_Status
+umax_scsi_open (const char *devicename, Umax_Device *dev,
+                                SANEI_SCSI_Sense_Handler handler, void *handler_arg)
+{
+       switch (dev->connection_type) {
+       case SANE_UMAX_SCSI:
+               return sanei_scsi_open(devicename, &dev->sfd, handler, handler_arg);
+               break;
+       case SANE_UMAX_USB:
+               return sanei_umaxusb_open(devicename, &dev->sfd, handler, 
+handler_arg);
+               break;
+       default:
+               return(SANE_STATUS_INVAL);
+       }
+}
+
+static void
+umax_scsi_close (Umax_Device *dev)
+{
+       switch (dev->connection_type) {
+       case SANE_UMAX_SCSI:
+               sanei_scsi_close(dev->sfd);
+               dev->sfd=-1;
+               break;
+       case SANE_UMAX_USB:
+               sanei_umaxusb_close(dev->sfd);
+               dev->sfd=-1;
+               break;
+       }       
+}
+
+static SANE_Status
+umax_scsi_req_enter (Umax_Device *dev,
+                      const void *src, size_t src_size,
+                                         void *dst, size_t * dst_size, void **idp)
+{
+       switch (dev->connection_type) {
+       case SANE_UMAX_SCSI:
+               return sanei_scsi_req_enter (dev->sfd, src, src_size, dst, dst_size, 
+idp);
+               break;
+       case SANE_UMAX_USB:
+               return sanei_umaxusb_req_enter (dev->sfd, src, src_size, dst, 
+dst_size, idp);
+               break;
+       default:
+               return(SANE_STATUS_INVAL);
+       }
+}
+
+static SANE_Status
+umax_scsi_req_wait (Umax_Device *dev, void *id)
+{
+       switch (dev->connection_type) {
+       case SANE_UMAX_SCSI:
+               return sanei_scsi_req_wait(id);
+               break;
+       case SANE_UMAX_USB:
+               return sanei_umaxusb_req_wait(id);
+               break;
+       default:
+               return(SANE_STATUS_INVAL);
+       }
+}
+
 /* ------------------------------------------------------------ UMAX SCSI GET LAMP 
STATUS ------------------ */
 
 
@@ -1228,7 +1328,7 @@
 
   DBG(DBG_proc, "umax_scsi_get_lamp_status\n");
 
-  status = sanei_scsi_cmd(dev->sfd, get_lamp_status.cmd, get_lamp_status.size, 
dev->buffer[0], &size);
+  status = umax_scsi_cmd(dev, get_lamp_status.cmd, get_lamp_status.size, 
+dev->buffer[0], &size);
   if (status)
   {
     DBG(DBG_error, "umax_scsi_get_lamp_status: command returned status %s\n", 
sane_strstatus(status));
@@ -1253,7 +1353,7 @@
   DBG(DBG_info, "lamp_status=%d\n", lamp_on);
 
   set_lamp_status_lamp_on(set_lamp_status.cmd, lamp_on);
-  status = sanei_scsi_cmd(dev->sfd, set_lamp_status.cmd, set_lamp_status.size, NULL, 
NULL);
+  status = umax_scsi_cmd(dev, set_lamp_status.cmd, set_lamp_status.size, NULL, NULL);
 
   if (status)
   {
@@ -1273,7 +1373,7 @@
 
   DBG(DBG_proc, "umax_set_lamp_status\n");
 
-  if ( sanei_scsi_open(scanner->device->sane.name, &(scanner->device->sfd), 
sense_handler,
+  if ( umax_scsi_open(scanner->device->sane.name, scanner->device, sense_handler,
                        scanner->device) != SANE_STATUS_GOOD )
   {
      DBG(DBG_error, "ERROR: umax_set_lamp_status: open of %s failed:\n", 
scanner->device->sane.name);
@@ -1287,8 +1387,7 @@
     status = umax_scsi_set_lamp_status(scanner->device, lamp_on);
   }
 
-  sanei_scsi_close(scanner->device->sfd);
-  scanner->device->sfd = -1;
+  umax_scsi_close(scanner->device);
 
  return status;
 }
@@ -1303,7 +1402,7 @@
 
   DBG(DBG_proc, "get_data_buffer_status\n");
   set_GDBS_wait(get_data_buffer_status.cmd,1);                                     /* 
wait for scanned data */
-  status = sanei_scsi_cmd(dev->sfd, get_data_buffer_status.cmd, 
get_data_buffer_status.size, NULL, NULL);
+  status = umax_scsi_cmd(dev, get_data_buffer_status.cmd, 
+get_data_buffer_status.size, NULL, NULL);
   if (status)
   {
     DBG(DBG_error, "umax_get_data_buffer_status: command returned status %s\n", 
sane_strstatus(status));
@@ -1324,7 +1423,7 @@
 
   DBG(DBG_proc, "do_request_sense\n");
   set_RS_allocation_length(request_sense.cmd, rs_return_block_size); 
-  status = sanei_scsi_cmd(dev->sfd, request_sense.cmd, request_sense.size, 
dev->buffer[0], &size);
+  status = umax_scsi_cmd(dev, request_sense.cmd, request_sense.size, dev->buffer[0], 
+&size);
   if (status)
   {
     DBG(DBG_error, "umax_do_request_sense: command returned status %s\n", 
sane_strstatus(status));
@@ -1350,7 +1449,7 @@
       return -1;
     }
                                                                                       
   /* test unit ready */
-    status = sanei_scsi_cmd(dev->sfd, test_unit_ready.cmd, test_unit_ready.size, 
NULL, NULL);
+    status = umax_scsi_cmd(dev, test_unit_ready.cmd, test_unit_ready.size, NULL, 
+NULL);
     cnt++;
 
     if (status)
@@ -1382,7 +1481,7 @@
   DBG(DBG_proc, "grab_scanner\n");
 
   WAIT_SCANNER;                                                                       
    /* wait for scanner ready */
-  status = sanei_scsi_cmd(dev->sfd, reserve_unit.cmd, reserve_unit.size, NULL, NULL);
+  status = umax_scsi_cmd(dev, reserve_unit.cmd, reserve_unit.size, NULL, NULL);
 
   if (status)
   {
@@ -1409,7 +1508,7 @@
                                         ( (dev->inquiry_fb_length * 
dev->y_coordinate_base) );
 
   DBG(DBG_info2, "trying to reposition scanner ...\n");
-  status = sanei_scsi_cmd(dev->sfd, object_position.cmd, object_position.size, NULL, 
NULL);
+  status = umax_scsi_cmd(dev, object_position.cmd, object_position.size, NULL, NULL);
   if (status)
   {
     DBG(DBG_error, "umax_reposition_scanner: command returned status %s\n", 
sane_strstatus(status));
@@ -1444,7 +1543,7 @@
  int status;
 
   DBG(DBG_info2, "trying to release scanner ...\n");
-  status = sanei_scsi_cmd(dev->sfd, release_unit.cmd, release_unit.size, NULL, NULL);
+  status = umax_scsi_cmd(dev, release_unit.cmd, release_unit.size, NULL, NULL);
   if (status)
   {
     DBG(DBG_error, "umax_give_scanner: command returned status %s\n", 
sane_strstatus(status));
@@ -1503,7 +1602,7 @@
       memcpy(dest, data, 1024);                                                       
         /* copy data */
 
       set_S_xfer_length(dev->buffer[0], 1026);                                        
        /* set length */
-      status = sanei_scsi_cmd(dev->sfd, dev->buffer[0], send.size + 1026, NULL, 
NULL);
+      status = umax_scsi_cmd(dev, dev->buffer[0], send.size + 1026, NULL, NULL);
       if (status)
       {
         DBG(DBG_error, "umax_send_gamma_data(DCF=0, one color): command returned 
status %s\n", sane_strstatus(status));
@@ -1529,7 +1628,7 @@
       memcpy(dest, data, 1024);                                                       
            /* copy blue data */
 
       set_S_xfer_length(dev->buffer[0], 3076);                                        
        /* set length */
-      status = sanei_scsi_cmd(dev->sfd, dev->buffer[0], send.size + 3076, NULL, 
NULL);
+      status = umax_scsi_cmd(dev, dev->buffer[0], send.size + 3076, NULL, NULL);
       if (status)
       {
         DBG(DBG_error, "umax_send_gamma_data(DCF=0, RGB): command returned status 
%s\n", sane_strstatus(status));
@@ -1552,7 +1651,7 @@
     memcpy(dest, data, 256);                                                          
         /* copy data */
 
     set_S_xfer_length(dev->buffer[0], 258);                                           
        /* set length */
-    status = sanei_scsi_cmd(dev->sfd, dev->buffer[0], send.size + 258, NULL, NULL);
+    status = umax_scsi_cmd(dev, dev->buffer[0], send.size + 258, NULL, NULL);
     if (status)
     {
       DBG(DBG_error, "umax_send_gamma_data(DCF=1): command returned status %s\n", 
sane_strstatus(status));
@@ -1617,7 +1716,7 @@
       set_S_xfer_length(dev->buffer[0], color*length+gamma_DCF2.size);                
        /* set length */
       memcpy(dest, data, color*length);                                               
                 /* copy data */
 
-      status = sanei_scsi_cmd(dev->sfd, dev->buffer[0], send.size+gamma_DCF2.size + 
length * color, NULL, NULL);
+      status = umax_scsi_cmd(dev, dev->buffer[0], send.size+gamma_DCF2.size + length 
+* color, NULL, NULL);
       if (status)
       {
         DBG(DBG_error, "umax_send_gamma_data(DCF=2): command returned status %s\n", 
sane_strstatus(status));
@@ -1650,7 +1749,7 @@
   dest=dev->buffer[0] + send.size;
   memcpy(dest, data, size);                                                           
         /* copy data */
 
-  status = sanei_scsi_cmd(dev->sfd, dev->buffer[0], send.size + size, NULL, NULL);
+  status = umax_scsi_cmd(dev, dev->buffer[0], send.size + size, NULL, NULL);
   if (status)
   {
     DBG(DBG_error, "umax_send_data: command returned status %s\n", 
sane_strstatus(status));
@@ -1702,7 +1801,7 @@
   set_R_xfer_length(sread.cmd, length);                                               
                /* set length */
   set_R_datatype_code(sread.cmd, R_datatype_imagedata);                               
              /* set datatype */
 
-  status = sanei_scsi_req_enter(dev->sfd, sread.cmd, sread.size, dev->buffer[bufnr], 
&length, &(dev->queue_id[bufnr]));
+  status = umax_scsi_req_enter(dev, sread.cmd, sread.size, dev->buffer[bufnr], 
+&length, &(dev->queue_id[bufnr]));
   if (status)
   {
     DBG(DBG_error, "umax_queue_read_image_data_req: command returned status %s\n", 
sane_strstatus(status));
@@ -1725,7 +1824,7 @@
 
   DBG(DBG_proc, "umax_wait_queued_image_data for buffer[%d] (id=%p)\n", bufnr, 
dev->queue_id[bufnr]);
 
-  status = sanei_scsi_req_wait(dev->queue_id[bufnr]);
+  status = umax_scsi_req_wait(dev, dev->queue_id[bufnr]);
   if (status)
   {
     DBG(DBG_error, "umax_wait_queued_image_data: wait returned status %s\n", 
sane_strstatus(status));
@@ -1746,7 +1845,7 @@
   set_R_xfer_length(sread.cmd, length);                                               
                /* set length */
   set_R_datatype_code(sread.cmd, datatype);                                           
      /* set datatype */
 
-  status = sanei_scsi_cmd(dev->sfd, sread.cmd, sread.size, dev->buffer[0], &length);
+  status = umax_scsi_cmd(dev, sread.cmd, sread.size, dev->buffer[0], &length);
   if (status)
   {
     DBG(DBG_error, "umax_read_data: command returned status %s\n", 
sane_strstatus(status));
@@ -2041,7 +2140,7 @@
 
   set_SW_xferlen(dev->buffer[0], (window_parameter_data_block.size + 
(window_descriptor_block.size * num_dblocks)));
 
-  status = sanei_scsi_cmd(dev->sfd, dev->buffer[0], set_window.size + 
window_parameter_data_block.size +
+  status = umax_scsi_cmd(dev, dev->buffer[0], set_window.size + 
+window_parameter_data_block.size +
                                               (window_descriptor_block.size * 
num_dblocks), NULL, NULL);
   if (status)
   {
@@ -2070,7 +2169,7 @@
   size = 5;
 
   set_inquiry_return_size(inquiry.cmd, size);  /* first get only 5 bytes to get size 
of inquiry_return_block */
-  status = sanei_scsi_cmd(dev->sfd, inquiry.cmd, inquiry.size, dev->buffer[0], 
&size);
+  status = umax_scsi_cmd(dev, inquiry.cmd, inquiry.size, dev->buffer[0], &size);
   if (status)
   {
     DBG(DBG_error, "umax_do_inquiry: command returned status %s\n", 
sane_strstatus(status));
@@ -2079,7 +2178,7 @@
   size = get_inquiry_additional_length(dev->buffer[0]) + 5;
 
   set_inquiry_return_size(inquiry.cmd, size);                          /* then get 
inquiry with actual size */
-  status = sanei_scsi_cmd(dev->sfd, inquiry.cmd, inquiry.size, dev->buffer[0], 
&size);
+  status = umax_scsi_cmd(dev, inquiry.cmd, inquiry.size, dev->buffer[0], &size);
   if (status)
   {
     DBG(DBG_error, "umax_do_inquiry: command returned status %s\n", 
sane_strstatus(status));
@@ -2128,7 +2227,7 @@
 
   DBG(DBG_info,"starting scan\n");
 
-  status = sanei_scsi_cmd(dev->sfd, scan.cmd, scan.size + size, NULL, NULL);
+  status = umax_scsi_cmd(dev, scan.cmd, scan.size + size, NULL, NULL);
   if (status)
   {
     DBG(DBG_error, "umax_start_scan: command returned status %s\n", 
sane_strstatus(status));
@@ -2394,7 +2493,7 @@
   memset(dev->buffer[0], '\0', 256);                                                  
      /* clear buffer */
 
   set_inquiry_return_size(inquiry.cmd, size);
-  status = sanei_scsi_cmd(dev->sfd, inquiry.cmd, inquiry.size, dev->buffer[0], 
&size);
+  status = umax_scsi_cmd(dev, inquiry.cmd, inquiry.size, dev->buffer[0], &size);
   if (status)
   {
     DBG(DBG_error, "umax_do_new_inquiry: command returned status %s\n", 
sane_strstatus(status));
@@ -4052,11 +4151,14 @@
   DBG(DBG_proc,"init\n");
 
   dev->devicename                        = NULL;
-  dev->sfd                               = -1;
   dev->pixelbuffer                       = NULL;
 
   /* config file or predefined settings */
-  dev->request_scsi_maxqueue    = umax_scsi_maxqueue;
+  if (dev->connection_type == SANE_UMAX_SCSI) {
+         dev->request_scsi_maxqueue    = umax_scsi_maxqueue;
+  } else {
+         dev->request_scsi_maxqueue    = 1;      
+  }
   dev->request_preview_lines    = umax_preview_lines;
   dev->request_scan_lines       = umax_scan_lines;
   dev->handle_bad_sense_error   = umax_handle_bad_sense_error;
@@ -4234,12 +4336,11 @@
     }
   }
 
-  if (scanner->device->sfd >= 0)
+  if (scanner->device->sfd != -1)
   {
     umax_give_scanner(scanner->device); /* reposition and release scanner */
     DBG(DBG_sane_info,"closing scannerdevice filedescriptor\n");
-    sanei_scsi_close(scanner->device->sfd);
-    scanner->device->sfd = -1;
+    umax_scsi_close(scanner->device);
   }
 
   scanner->device->three_pass_color = 1; /* reset color in color scanning */
@@ -4254,7 +4355,6 @@
 static SANE_Status attach_scanner(const char *devicename, Umax_Device **devp)
 {
  Umax_Device *dev;
- int sfd;
  int i;
 
   DBG(DBG_sane_proc,"attach_scanner: %s\n", devicename);
@@ -4280,10 +4380,17 @@
 
   DBG(DBG_info, "attach_scanner: opening %s\n", devicename);
 
+  /* First, try to open the device as an USB device. If it fails, try
+   * the SCSI method. */
+  dev->bufsize = 16384; /* 16KB */
+  if (sanei_umaxusb_open (devicename, &dev->sfd, sense_handler, dev) == 
+SANE_STATUS_GOOD) {
+         dev->connection_type = SANE_UMAX_USB;
+  } else {
+
 #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
   dev->bufsize = 16384; /* 16KB */
 
-  if (sanei_scsi_open_extended(devicename, &sfd, sense_handler, dev, (int *) 
&dev->bufsize) != 0)
+  if (sanei_scsi_open_extended(devicename, &dev->sfd, sense_handler, dev, (int *) 
+&dev->bufsize) != 0)
   {
     DBG(DBG_error, "ERROR: attach_scanner: opening %s failed\n", devicename);
     free(dev);
@@ -4293,7 +4400,7 @@
   if (dev->bufsize < 4096) /* < 4KB */
   {
     DBG(DBG_error, "ERROR: attach_scanner: sanei_scsi_open_extended returned too 
small scsi buffer\n");
-    sanei_scsi_close(sfd);
+    umax_scsi_close(dev);
     free(dev);
     return SANE_STATUS_NO_MEM;
   }
@@ -4302,13 +4409,15 @@
 #else
   dev->bufsize = sanei_scsi_max_request_size;
 
-  if (sanei_scsi_open(devicename, &sfd, sense_handler, dev) != 0)
+  if (sanei_scsi_open(devicename, dev, sense_handler, dev) != 0)
   {
     DBG(DBG_error, "ERROR: attach_scanner: open failed\n");
     free(dev);
     return SANE_STATUS_INVAL;
   }
 #endif
+         dev->connection_type = SANE_UMAX_SCSI;
+  }
 
   DBG(DBG_info, "attach_scanner: allocating SCSI buffer[0]\n");
   dev->buffer[0] = malloc(dev->bufsize);                                              
                 /* allocate buffer */
@@ -4321,7 +4430,7 @@
   if (!dev->buffer[0]) /* malloc failed */
   {
     DBG(DBG_error, "ERROR: attach scanner: could not allocate buffer[0]\n");
-    sanei_scsi_close(sfd);
+    umax_scsi_close(dev);
     free(dev);
     return SANE_STATUS_NO_MEM;
   }
@@ -4332,13 +4441,11 @@
   umax_initialize_values(dev);                                                        
                    /* reset values */
 
   dev->devicename = strdup(devicename);
-  dev->sfd        = sfd;
 
   if (umax_identify_scanner(dev) != 0)
   {
     DBG(DBG_error, "ERROR: attach_scanner: scanner-identification failed\n");
-    sanei_scsi_close(dev->sfd);
-    dev->sfd=-1;
+    umax_scsi_close(dev);
     free(dev->buffer[0]);
     free(dev);
     return SANE_STATUS_INVAL;
@@ -4365,8 +4472,7 @@
   DBG(DBG_inquiry,"==================== end of inquiry ====================\n");
   DBG(DBG_inquiry,"\n");
 
-  sanei_scsi_close(dev->sfd);
-  dev->sfd=-1;
+  umax_scsi_close(dev);
 
   dev->sane.name   = dev->devicename;
   dev->sane.vendor = dev->vendor;
@@ -4421,7 +4527,7 @@
   {
     *devp = dev;
   }
-
+  DBG(DBG_info, " NAMES %s %s\n", dev->sane.name, dev->devicename);
  return SANE_STATUS_GOOD;
 }
 
@@ -5398,7 +5504,7 @@
     value = strtol(value_str, &end_ptr, 10);
     if (end_ptr == value_str || errno) 
     {
-      DBG(DBG_error, "ERROR: inavlid value \"%s\" for option %s in %s\n", value_str, 
test_name, UMAX_CONFIG_FILE);
+      DBG(DBG_error, "ERROR: invalid value \"%s\" for option %s in %s\n", value_str, 
+test_name, UMAX_CONFIG_FILE);
     }
     else
     {
@@ -5451,11 +5557,15 @@
 
   frontend_authorize_callback = authorize; /* store frontend authorize callback */
 
+  sanei_usb_init ();
+
   fp = sanei_config_open(UMAX_CONFIG_FILE);
   if (!fp) 
   {
-    attach_scanner("/dev/scanner", 0);                                      /* no 
config-file: /dev/scanner */
-    return SANE_STATUS_GOOD;
+         /* no config-file: try /dev/scanner and /dev/usbscanner. */
+         attach_scanner("/dev/scanner", 0);
+         attach_scanner("/dev/usbscanner", 0);
+         return SANE_STATUS_GOOD;
   }
 
   DBG(DBG_info, "reading configure file %s\n", UMAX_CONFIG_FILE);
@@ -5492,6 +5602,34 @@
       }
       continue;
     }
+       else if (strncmp(config_line, "usb", 3) == 0) {
+         const char *usb_device_name;
+         char *vendor, *product;
+      SANE_Word vendorID = 0, productID = 0;
+         const char *name;
+
+         name = sanei_config_skip_whitespace(config_line+3);
+         
+      if (*name) {
+                 name = sanei_config_get_string (name, &vendor);
+                 if (vendor) {
+                         vendorID = strtol (vendor, 0, 0);
+                         free (vendor);
+                 }
+                 name = sanei_config_skip_whitespace (name);
+         }
+
+      name = sanei_config_skip_whitespace (name);
+      if (*name) {
+                 name = sanei_config_get_string (name, &product);
+                 if (product) {
+                         productID = strtol (product, 0, 0);
+                         free (product);
+                 }
+         }
+
+      sanei_usb_find_devices (vendorID, productID, attach_one);
+  }
 
     len = strlen (config_line);
 
@@ -5625,7 +5763,6 @@
   memset(scanner, 0, sizeof (*scanner));
 
   scanner->device      = dev;
-  scanner->device->sfd = -1;
 
   if (scanner->device->inquiry_GIB & 32)
   {
@@ -6666,7 +6803,7 @@
 
   mode = scanner->val[OPT_MODE].s;
 
-  if (scanner->device->sfd < 0)   /* first call, don`t run this routine again on 
multi frame or multi image scan */
+  if (scanner->device->sfd == -1)   /* first call, don`t run this routine again on 
+multi frame or multi image scan */
   {
     umax_initialize_values(scanner->device);                                          
                     /* reset values */
 
@@ -6684,8 +6821,7 @@
       else
       {
         DBG(DBG_error,"ERROR: Transparency Adapter not available\n");
-        sanei_scsi_close(scanner->device->sfd);
-        scanner->device->sfd=-1;
+        umax_scsi_close(scanner->device);
        return SANE_STATUS_INVAL;
       }
     }
@@ -6702,8 +6838,7 @@
         else
         {
           DBG(DBG_error,"ERROR: Automatic Document Feeder not available\n");
-         sanei_scsi_close(scanner->device->sfd);
-         scanner->device->sfd=-1;
+         umax_scsi_close(scanner->device);
          return SANE_STATUS_INVAL;
         }
       }
@@ -7057,7 +7192,7 @@
         scsi_bufsize = scanner->device->scsi_buffer_size_max;
       }
 
-      if (sanei_scsi_open_extended(scanner->device->sane.name, 
&(scanner->device->sfd), sense_handler,
+      if (umax_scsi_open_extended(scanner->device->sane.name, scanner->device, 
+sense_handler,
                                    scanner->device, (int *) &scsi_bufsize) != 0)
       {
         DBG(DBG_error, "ERROR: sane_start: open failed\n");
@@ -7067,12 +7202,12 @@
 
       if (scsi_bufsize < scanner->device->scsi_buffer_size_min) /* minimum size must 
be available */
       {
-        DBG(DBG_error, "ERROR: sane_start: sanei_scsi_open_extended returned too 
small scsi buffer\n");
-        sanei_scsi_close((scanner->device->sfd));
+        DBG(DBG_error, "ERROR: sane_start: umax_scsi_open_extended returned too small 
+scsi buffer\n");
+        umax_scsi_close((scanner->device));
         scanner->scanning = SANE_FALSE;
         return SANE_STATUS_NO_MEM;
       }
-      DBG(DBG_info, "sane_start: sanei_scsi_open_extended returned scsi buffer size = 
%d\n", scsi_bufsize);
+      DBG(DBG_info, "sane_start: umax_scsi_open_extended returned scsi buffer size = 
+%d\n", scsi_bufsize);
 
       if (scsi_bufsize < scanner->device->width_in_pixels) /* print warning when 
buffer is smaller than one scanline */
       {
@@ -7097,7 +7232,7 @@
         if (!scanner->device->buffer[0]) /* malloc failed */
         {
           DBG(DBG_error, "ERROR: sane_start: could not allocate buffer[0]\n");
-          sanei_scsi_close(scanner->device->sfd);
+          umax_scsi_close(scanner->device);
           scanner->device->bufsize = 0;
           scanner->scanning = SANE_FALSE;
          return SANE_STATUS_NO_MEM;
@@ -7105,7 +7240,7 @@
       }
     }
 #else
-    if ( sanei_scsi_open(scanner->device->sane.name, &(scanner->device->sfd), 
sense_handler,
+    if ( umax_scsi_open(scanner->device->sane.name, scanner->device, sense_handler,
                          scanner->device) != SANE_STATUS_GOOD )
     {
       scanner->scanning = SANE_FALSE;
@@ -7120,8 +7255,7 @@
     /* grab scanner */
     if (umax_grab_scanner(scanner->device))
     {
-      sanei_scsi_close(scanner->device->sfd);
-      scanner->device->sfd=-1;
+      umax_scsi_close(scanner->device);
       scanner->scanning = SANE_FALSE;
       DBG(DBG_warning,"WARNING: unable to reserve scanner: device busy\n");
      return SANE_STATUS_DEVICE_BUSY;
@@ -7304,8 +7438,7 @@
 #endif
     scanner->scanning = SANE_FALSE;
     umax_give_scanner(scanner->device); /* reposition and release scanner */
-    sanei_scsi_close(scanner->device->sfd);
-    scanner->device->sfd=-1;
+    umax_scsi_close(scanner->device);
    return SANE_STATUS_IO_ERROR;
   }
 
diff -P -r -u sane-backends-1.0.6.orig/backend/umax.conf 
sane-backends-1.0.6/backend/umax.conf
--- sane-backends-1.0.6.orig/backend/umax.conf  Sat Jun 23 20:02:26 2001
+++ sane-backends-1.0.6/backend/umax.conf       Thu Nov 22 22:15:46 2001
@@ -23,6 +23,8 @@
 scsi EPSON Perfection600
 scsi ESCORT "Galleria 600S"
 
+usb 0x1606 0x0230
+
 #
 # device list for non-linux-systems:
 /dev/scanner
diff -P -r -u sane-backends-1.0.6.orig/backend/umax.h 
sane-backends-1.0.6/backend/umax.h
--- sane-backends-1.0.6.orig/backend/umax.h     Sun Jun 17 17:49:17 2001
+++ sane-backends-1.0.6/backend/umax.h  Thu Nov 22 22:46:23 2001
@@ -54,6 +54,7 @@
 # include "sane/sanei_ipc.h"
 #endif
 
+#include <usb.h>
 
 /* 
---------------------------------------------------------------------------------------------------------
 */
 /* COMPILER OPTIONS: */
@@ -191,13 +192,18 @@
 
 /* LIST OF AVAILABLE SCANNERS, THE VALUES LISTED HERE ARE THE SAME FOR DIFFERENT 
APPLICATIONS
    THAT USE THE SAME DEVICE */
-   
+
 /* Umax_Device contains values relevant for the device that are not intersting for 
the sane interface */
 
 typedef struct Umax_Device
 {
   struct Umax_Device   *next;
   SANE_Device          sane;
+
+  int connection_type;
+#define SANE_UMAX_SCSI 1
+#define SANE_UMAX_USB 2
+
   SANE_Range           x_dpi_range;
   SANE_Range           y_dpi_range;
   SANE_Range           x_range;
Binary files sane-backends-1.0.6.orig/core and sane-backends-1.0.6/core differ
diff -P -r -u sane-backends-1.0.6.orig/include/Makefile 
sane-backends-1.0.6/include/Makefile
--- sane-backends-1.0.6.orig/include/Makefile   Wed Dec 31 18:00:00 1969
+++ sane-backends-1.0.6/include/Makefile        Wed Nov 21 15:41:45 2001
@@ -0,0 +1,8 @@
+# Generated automatically from Makefile.in by configure.
+# This is just a dummy to ensure that the include directory gets created
+# in a shadow-build.
+
+all:
+
+distclean:
+       rm -f Makefile
diff -P -r -u sane-backends-1.0.6.orig/include/sane/sanei_usb.h 
sane-backends-1.0.6/include/sane/sanei_usb.h
--- sane-backends-1.0.6.orig/include/sane/sanei_usb.h   Wed Sep  5 14:48:32 2001
+++ sane-backends-1.0.6/include/sane/sanei_usb.h        Wed Nov 21 16:00:31 2001
@@ -25,21 +25,21 @@
 #include "../include/sane/sane.h"
 
 /* Initialize sanei_usb. Call this before any other sanei_usb function */
-void
+extern void
 sanei_usb_init (void);
 
 /* Get the vendor and product numbers for a given file descriptor. Currently,
    only scanners supported by the Linux USB scanner module can be found. Linux
    version must be 2.4.8 or higher. Returns SANE_STATUS_GOOD if the ids have
    been found, otherwise SANE_STATUS_UNSUPPORTED. */
-SANE_Status
+extern SANE_Status
 sanei_usb_get_vendor_product (SANE_Int fd, SANE_Word * vendor,
                              SANE_Word * product);
 
 /* Find device names for given vendor and product ids. Above mentioned 
    limitations apply. The function attach is called for every device which
    has been found.*/
-SANE_Status
+extern SANE_Status
 sanei_usb_find_devices (SANE_Int vendor, SANE_Int product,
                        SANE_Status (*attach) (SANE_String_Const devname));
 
@@ -47,11 +47,11 @@
    success, SANE_STATUS_GOOD is returned. If the file couldn't be accessed
    due to permissions, SANE_STATUS_ACCESS_DENIED is returned. For every
    other error, the return value is SANE_STATUS_INVAL. */
-SANE_Status
+extern SANE_Status
 sanei_usb_open (SANE_String_Const devname, SANE_Int *fd);
 
 /* Close an USB device represented by its file desciptor. */
-void
+extern void
 sanei_usb_close (SANE_Int fd);
 
 /* Initiate a bulk transfer read of up to zize bytes from the device to
@@ -59,7 +59,7 @@
    read. Returns SANE_STATUS_GOOD on succes, SANE_STATUS_EOF if zero bytes
    have been read, SANE_STATUS_IO_ERROR if an error occured during the read,
    and SANE_STATUS_INVAL on every other error. */
-SANE_Status
+extern SANE_Status
 sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size);
 
 /* Initiate a bulk transfer write of up to size bytes from buffer to the
@@ -67,7 +67,7 @@
    written. Returns SANE_STATUS_GOOD on succes, SANE_STATUS_IO_ERROR if an
    error occured during the read, and SANE_STATUS_INVAL on every other
    error. */
-SANE_Status
+extern SANE_Status
 sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size);
 
 /* A convenience function to support expanding device name patterns
@@ -84,4 +84,19 @@
 extern void 
 sanei_usb_attach_matching_devices (const char *name,
                                   SANE_Status (*attach) (const char *dev));
+
+/* Sends/Receives a control message to/from the USB device.
+   data is the buffer to send/receive the data. len is the length of
+   that data, or the length of the data to receive.
+
+   The function returns 
+     SANE_STATUS_IO_ERROR on error, 
+     SANE_STATUS_GOOD on success,
+        SANE_STATUS_UNSUPPORTED if the feature is not supported by the
+                                OS or SANE.
+*/
+
+extern SANE_Status
+sanei_usb_control_msg( int fd, int rtype, int req, int value, int index, int len, 
+void *data );
+
 #endif /* sanei_usb_h */
diff -P -r -u sane-backends-1.0.6.orig/sanei/sanei_usb.c 
sane-backends-1.0.6/sanei/sanei_usb.c
--- sane-backends-1.0.6.orig/sanei/sanei_usb.c  Fri Oct 26 16:24:49 2001
+++ sane-backends-1.0.6/sanei/sanei_usb.c       Thu Nov 22 22:25:03 2001
@@ -58,6 +58,31 @@
 #include "../include/sane/sanei_usb.h"
 #include "../include/sane/sanei_config.h"
 
+#if defined (__linux__)
+/* From /usr/src/linux/driver/usb/scanner.h */
+#define IOCTL_SCANNER_VENDOR _IOR('U', 0x20, int)
+#define IOCTL_SCANNER_PRODUCT _IOR('U', 0x21, int)
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest )
+  /* Older (unofficial) IOCTL numbers for Linux < v2.4.13 */
+#define IOCTL_SCANNER_VENDOR_OLD _IOR('u', 0xa0, int)
+#define IOCTL_SCANNER_PRODUCT_OLD _IOR('u', 0xa1, int)
+
+/* From /usr/src/linux/include/linux/usb.h */ 
+typedef struct {
+    unsigned char requesttype;
+    unsigned char request;
+    unsigned short value;
+    unsigned short index;
+    unsigned short length;
+} devrequest __attribute__ ((packed));
+
+/* From /usr/src/linux/driver/usb/scanner.h */
+struct ctrlmsg_ioctl {
+       devrequest  req;
+       void        *data;
+} cmsg;
+
+#endif /* __linux__ */
 
 void
 sanei_usb_init (void)
@@ -114,11 +139,6 @@
   SANE_Word vendorID, productID;
 
 #if defined (__linux__)
-#define IOCTL_SCANNER_VENDOR _IOR('U', 0x20, int)
-#define IOCTL_SCANNER_PRODUCT _IOR('U', 0x21, int)
-  /* Older (unofficial) IOCTL numbers for Linux < v2.4.13 */
-#define IOCTL_SCANNER_VENDOR_OLD _IOR('u', 0xa0, int)
-#define IOCTL_SCANNER_PRODUCT_OLD _IOR('u', 0xa1, int)
   /* read the vendor and product IDs via the IOCTLs */
   if (ioctl (fd, IOCTL_SCANNER_VENDOR , &vendorID) == -1)
     {
@@ -309,3 +329,39 @@
   *size = write_size;
   return SANE_STATUS_GOOD;
 }
+
+#if defined(__linux__)
+
+/* Send/receive a control message to/from the USB device. */
+SANE_Status
+sanei_usb_control_msg( int fd, int rtype, int req, int value, int index, int len, 
+void *data ) {
+       struct ctrlmsg_ioctl c;
+
+       c.req.requesttype = rtype;
+       c.req.request = req;
+       c.req.value = value;
+       c.req.index = index;
+       c.req.length = len;
+       c.data = data;
+
+       DBG(5, "control_msg: rtype = 0x%02x, req = %d, value = %d, index = %d, len = 
+%d\n",
+               rtype, req, value, index, len );
+
+       if( ioctl(fd, SCANNER_IOCTL_CTRLMSG, &c) < 0 ) {
+               DBG(5, "control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n", 
+strerror(errno));
+               return SANE_STATUS_IO_ERROR;
+       }
+       return SANE_STATUS_GOOD;
+}
+
+#else
+
+UMAX_Status
+sanei_usb_control_msg( int fd, int rtype, int req, int value, int index, int len, 
+void *data ) {
+       DBG (DBG_error, "control_msg: not supported on that OS\n");
+       return SANE_STATUS_UNSUPPORTED;
+}
+#endif /* __linux__ */
+
+
+

Reply via email to