summaryrefslogtreecommitdiff
path: root/tools/sane-find-scanner.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/sane-find-scanner.c')
-rw-r--r--tools/sane-find-scanner.c2100
1 files changed, 2100 insertions, 0 deletions
diff --git a/tools/sane-find-scanner.c b/tools/sane-find-scanner.c
new file mode 100644
index 0000000..dbfd0da
--- /dev/null
+++ b/tools/sane-find-scanner.c
@@ -0,0 +1,2100 @@
+/* sane-find-scanner.c
+
+ Copyright (C) 1997-2013 Oliver Rauch, Henning Meier-Geinitz, and others.
+
+ 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.
+
+ */
+
+#include "../include/sane/config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+
+#if defined (HAVE_DDK_NTDDSCSI_H) || defined (HAVE_NTDDSCSI_H)
+# define WIN32_SCSI
+# include <windows.h>
+# if defined (HAVE_DDK_NTDDSCSI_H)
+# include <ddk/scsi.h>
+# include <ddk/ntddscsi.h>
+# elif defined (HAVE_NTDDSCSI_H)
+# include <ntddscsi.h>
+# endif
+#endif
+
+#include "../include/sane/sanei.h"
+#include "../include/sane/sanei_scsi.h"
+#include "../include/sane/sanei_pa4s2.h"
+#include "../include/sane/sanei_config.h"
+
+#ifdef HAVE_LIBUSB
+#ifdef HAVE_LUSB0_USB_H
+#include <lusb0_usb.h>
+#else
+#include <usb.h>
+#endif
+extern char * check_usb_chip (struct usb_device *dev, int verbosity, SANE_Bool from_file);
+#endif
+
+#ifdef HAVE_LIBUSB_1_0
+#include <libusb.h>
+extern char * check_usb_chip (int verbosity,
+ struct libusb_device_descriptor desc,
+ libusb_device_handle *hdl,
+ struct libusb_config_descriptor *config0);
+#endif
+
+#include "../include/sane/sanei_usb.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+static const char *prog_name;
+static int verbose = 1;
+static SANE_Bool force = SANE_FALSE;
+static SANE_Bool device_found = SANE_FALSE;
+static SANE_Bool libusb_device_found = SANE_FALSE;
+static SANE_Bool unknown_found = SANE_FALSE;
+
+#ifdef HAVE_LIBUSB_1_0
+libusb_context *sfs_usb_ctx;
+#endif
+
+typedef struct
+{
+ unsigned char *cmd;
+ size_t size;
+}
+scsiblk;
+
+#define INQUIRY 0x12
+#define set_inquiry_return_size(icb,val) icb[0x04]=val
+#define IN_periph_devtype_cpu 0x03
+#define IN_periph_devtype_scanner 0x06
+#define get_scsi_inquiry_vendor(in, buf) strncpy(buf, in + 0x08, 0x08)
+#define get_scsi_inquiry_product(in, buf) strncpy(buf, in + 0x10, 0x010)
+#define get_scsi_inquiry_version(in, buf) strncpy(buf, in + 0x20, 0x04)
+#define get_scsi_inquiry_periph_devtype(in) (in[0] & 0x1f)
+#define get_scsi_inquiry_additional_length(in) in[0x04]
+#define set_scsi_inquiry_length(out,n) out[0x04]=n-5
+
+static unsigned char inquiryC[] = {
+ INQUIRY, 0x00, 0x00, 0x00, 0xff, 0x00
+};
+static scsiblk inquiry = {
+ inquiryC, sizeof (inquiryC)
+};
+
+static void
+usage (char *msg)
+{
+ fprintf (stderr, "Usage: %s [-hvqf] [devname ...]\n", prog_name);
+ fprintf (stderr, "\t-h: print this help message\n");
+ fprintf (stderr, "\t-v: be more verbose (can be used multiple times)\n");
+ fprintf (stderr, "\t-q: be quiet (print only devices, no comments)\n");
+ fprintf (stderr, "\t-f: force opening devname as SCSI even if it looks "
+ "like USB\n");
+ fprintf (stderr, "\t-p: enable scanning for parallel port devices\n");
+#ifdef HAVE_LIBUSB
+ fprintf (stderr, "\t-F file: try to detect chipset from given "
+ "/proc/bus/usb/devices file\n");
+#endif
+ if (msg)
+ fprintf (stderr, "\t%s\n", msg);
+}
+
+/* if SCSI generic is optional on your OS, and there is a software test
+ which will determine if it is included, add it here. If you are sure
+ that SCSI generic was found, return 1. If SCSI generic is always
+ available in your OS, return 1 */
+
+static int
+check_sg (void)
+{
+#if defined(__linux__)
+ /* Assumption: /proc/devices lines are shorter than 256 characters */
+ char line[256], driver[256] = "";
+ FILE *stream;
+
+ stream = fopen ("/proc/devices", "r");
+ /* Likely reason for failure, no /proc => probably no SG either */
+ if (stream == NULL)
+ return 0;
+
+ while (fgets (line, sizeof (line) - 1, stream))
+ {
+ if (sscanf (line, " %*d %s\n", driver) > 0 && !strcmp (driver, "sg"))
+ break;
+ }
+ fclose (stream);
+
+ if (strcmp (driver, "sg"))
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+#endif
+ return 1; /* Give up, and assume yes to avoid false negatives */
+}
+
+/* Display a buffer in the log. Display by lines of 16 bytes. */
+static void
+hexdump (const char *comment, unsigned char *buf, const int length)
+{
+ int i;
+ char line[128];
+ char *ptr;
+ char asc_buf[17];
+ char *asc_ptr;
+
+ printf (" %s\n", comment);
+
+ i = 0;
+ goto start;
+
+ do
+ {
+ if (i < length)
+ {
+ ptr += sprintf (ptr, " %2.2x", *buf);
+
+ if (*buf >= 32 && *buf <= 127)
+ {
+ asc_ptr += sprintf (asc_ptr, "%c", *buf);
+ }
+ else
+ {
+ asc_ptr += sprintf (asc_ptr, ".");
+ }
+ }
+ else
+ {
+ /* After the length; do nothing. */
+ ptr += sprintf (ptr, " ");
+ }
+
+ i++;
+ buf++;
+
+ if ((i % 16) == 0)
+ {
+ /* It's a new line */
+ printf (" %s %s\n", line, asc_buf);
+
+ start:
+ ptr = line;
+ *ptr = '\0';
+ asc_ptr = asc_buf;
+ *asc_ptr = '\0';
+
+ ptr += sprintf (ptr, " %3.3d:", i);
+ }
+
+ }
+ while (i < ((length + 15) & ~15));
+}
+
+static SANE_Status
+scanner_do_scsi_inquiry (unsigned char *buffer, int sfd)
+{
+ size_t size;
+ SANE_Status status;
+
+ memset (buffer, '\0', 256); /* clear buffer */
+
+ size = 5; /* first get only 5 bytes to get size of
+ inquiry_return_block */
+ set_inquiry_return_size (inquiry.cmd, size);
+ status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
+
+ if (status != SANE_STATUS_GOOD)
+ return (status);
+
+ size = get_scsi_inquiry_additional_length (buffer) + 5;
+
+ /* then get inquiry with actual size */
+ set_inquiry_return_size (inquiry.cmd, size);
+ status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
+
+ return (status);
+}
+
+static void
+scanner_identify_scsi_scanner (unsigned char *buffer, int sfd,
+ char *devicename)
+{
+ unsigned char vendor[9];
+ unsigned char product[17];
+ unsigned char version[5];
+ unsigned char *pp;
+ unsigned int devtype;
+ SANE_Status status;
+ static char *devtypes[] = {
+ "disk", "tape", "printer", "processor", "CD-writer",
+ "CD-drive", "scanner", "optical-drive", "jukebox",
+ "communicator"
+ };
+ status = scanner_do_scsi_inquiry (buffer, sfd);
+ if (status != SANE_STATUS_GOOD)
+ {
+ if (verbose > 1)
+ printf ("inquiry for device %s failed (%s)\n",
+ devicename, sane_strstatus (status));
+ return;
+ }
+
+ if (verbose > 2)
+ hexdump ("Inquiry for device:", buffer,
+ get_scsi_inquiry_additional_length (buffer) + 5);
+
+ devtype = get_scsi_inquiry_periph_devtype (buffer);
+ if (verbose <= 1 && devtype != IN_periph_devtype_scanner
+ /* old HP scanners use the CPU id ... */
+ && devtype != IN_periph_devtype_cpu)
+ return; /* no, continue searching */
+
+ get_scsi_inquiry_vendor ((char *) buffer, (char *) vendor);
+ get_scsi_inquiry_product ((char *) buffer, (char *) product);
+ get_scsi_inquiry_version ((char *) buffer, (char *) version);
+
+ pp = &vendor[7];
+ vendor[8] = '\0';
+ while (pp >= vendor && (*pp == ' ' || *pp >= 127))
+ *pp-- = '\0';
+
+ pp = &product[15];
+ product[16] = '\0';
+ while (pp >= product && (*pp == ' ' || *pp >= 127))
+ *pp-- = '\0';
+
+ pp = &version[3];
+ version[4] = '\0';
+ while (pp >= version && (*pp == ' ' || *(pp - 1) >= 127))
+ *pp-- = '\0';
+
+ device_found = SANE_TRUE;
+ printf ("found SCSI %s \"%s %s %s\" at %s\n",
+ devtype < NELEMS (devtypes) ? devtypes[devtype] : "unknown device",
+ vendor, product, version, devicename);
+ return;
+}
+
+static void
+check_scsi_file (char *file_name)
+{
+ int result;
+ int sfd;
+ unsigned char buffer[16384];
+
+ if (strstr (file_name, "usb")
+ || strstr (file_name, "uscanner") || strstr (file_name, "ugen"))
+ {
+ if (force)
+ {
+ if (verbose > 1)
+ printf ("checking %s even though it looks like a USB device...",
+ file_name);
+ }
+ else
+ {
+ if (verbose > 1)
+ printf ("ignored %s (not a SCSI device)\n", file_name);
+ return;
+ }
+ }
+ else if (verbose > 1)
+ printf ("checking %s...", file_name);
+
+ result = sanei_scsi_open (file_name, &sfd, NULL, NULL);
+
+ if (verbose > 1)
+ {
+ if (result != 0)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ else
+ printf (" open ok\n");
+ }
+
+ if (result == SANE_STATUS_GOOD)
+ {
+ scanner_identify_scsi_scanner (buffer, sfd, file_name);
+ sanei_scsi_close (sfd);
+ }
+ return;
+}
+
+static void
+check_usb_file (char *file_name)
+{
+ SANE_Status result;
+ SANE_Word vendor, product;
+ SANE_Int fd;
+
+ if (!strstr (file_name, "usb")
+ && !strstr (file_name, "uscanner") && !strstr (file_name, "ugen"))
+ {
+ if (force)
+ {
+ if (verbose > 1)
+ printf ("checking %s even though doesn't look like a "
+ "USB device...", file_name);
+ }
+ else
+ {
+ if (verbose > 1)
+ printf ("ignored %s (not a USB device)\n", file_name);
+ return;
+ }
+ }
+ else if (verbose > 1)
+ printf ("checking %s...", file_name);
+
+ result = sanei_usb_open (file_name, &fd);
+
+ if (result != SANE_STATUS_GOOD)
+ {
+ if (verbose > 1)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ }
+ else
+ {
+ result = sanei_usb_get_vendor_product (fd, &vendor, &product);
+ if (result == SANE_STATUS_GOOD)
+ {
+ if (verbose > 1)
+ printf (" open ok, vendor and product ids were identified\n");
+ printf ("found USB scanner (vendor=0x%04x, "
+ "product=0x%04x) at %s\n", vendor, product, file_name);
+ }
+ else
+ {
+ if (verbose > 1)
+ printf (" open ok, but vendor and product could NOT be "
+ "identified\n");
+ printf ("found USB scanner (UNKNOWN vendor and product) "
+ "at device %s\n", file_name);
+ unknown_found = SANE_TRUE;
+ }
+ device_found = SANE_TRUE;
+ sanei_usb_close (fd);
+ }
+}
+
+#ifdef HAVE_LIBUSB
+
+static char *
+get_libusb_string_descriptor (struct usb_device *dev, int index)
+{
+ usb_dev_handle *handle;
+ char *buffer, short_buffer[2];
+ struct usb_string_descriptor *sd;
+ int size = 2;
+ int i;
+
+ if (!index)
+ return 0;
+
+ handle = usb_open (dev);
+ if (!handle)
+ return 0;
+
+ sd = (struct usb_string_descriptor *) short_buffer;
+
+ if (usb_control_msg (handle,
+ USB_ENDPOINT_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE,
+ USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) + index, 0, short_buffer,
+ size, 1000) < 0)
+ {
+ usb_close (handle);
+ return 0;
+ }
+
+ if (sd->bLength < 2
+ || sd->bDescriptorType != USB_DT_STRING)
+ {
+ usb_close (handle);
+ return 0;
+ }
+
+ size = sd->bLength;
+
+ buffer = calloc (1, size + 1);
+ if (!buffer)
+ return 0;
+
+ sd = (struct usb_string_descriptor *) buffer;
+
+ if (usb_control_msg (handle,
+ USB_ENDPOINT_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE,
+ USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) + index, 0, buffer,
+ size, 1000) < 0)
+ {
+ usb_close (handle);
+ free (buffer);
+ return 0;
+ }
+
+ if (sd->bLength < 2 || sd->bLength > size
+ || sd->bDescriptorType != USB_DT_STRING)
+ {
+ usb_close (handle);
+ free (buffer);
+ return 0;
+ }
+ size = sd->bLength - 2;
+ for (i = 0; i < (size / 2); i++)
+ buffer[i] = buffer[2 + 2 * i];
+ buffer[i] = 0;
+
+ usb_close (handle);
+ return buffer;
+}
+
+static char *
+get_libusb_vendor (struct usb_device *dev)
+{
+ return get_libusb_string_descriptor (dev, dev->descriptor.iManufacturer);
+}
+
+static char *
+get_libusb_product (struct usb_device *dev)
+{
+ return get_libusb_string_descriptor (dev, dev->descriptor.iProduct);
+}
+
+static void
+check_libusb_device (struct usb_device *dev, SANE_Bool from_file)
+{
+ int is_scanner = 0;
+ char *vendor;
+ char *product;
+ int interface_nr;
+
+ if (!dev->config)
+ {
+ if (verbose > 1)
+ printf ("device 0x%04x/0x%04x is not configured\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ return;
+ }
+
+ vendor = get_libusb_vendor (dev);
+ product = get_libusb_product (dev);
+
+ if (verbose > 2)
+ {
+ /* print everything we know about the device */
+ char *buf;
+ int config_nr;
+ struct usb_device_descriptor *d = &dev->descriptor;
+
+ printf ("\n");
+ printf ("<device descriptor of 0x%04x/0x%04x at %s:%s",
+ d->idVendor, d->idProduct, dev->bus->dirname, dev->filename);
+ if (vendor || product)
+ {
+ printf (" (%s%s%s)", vendor ? vendor : "",
+ (vendor && product) ? " " : "", product ? product : "");
+ }
+ printf (">\n");
+ printf ("bLength %d\n", d->bLength);
+ printf ("bDescriptorType %d\n", d->bDescriptorType);
+ printf ("bcdUSB %d.%d%d\n", d->bcdUSB >> 8,
+ (d->bcdUSB >> 4) & 15, d->bcdUSB & 15);
+ printf ("bDeviceClass %d\n", d->bDeviceClass);
+ printf ("bDeviceSubClass %d\n", d->bDeviceSubClass);
+ printf ("bDeviceProtocol %d\n", d->bDeviceProtocol);
+ printf ("bMaxPacketSize0 %d\n", d->bMaxPacketSize0);
+ printf ("idVendor 0x%04X\n", d->idVendor);
+ printf ("idProduct 0x%04X\n", d->idProduct);
+ printf ("bcdDevice %d.%d%d\n", d->bcdDevice >> 8,
+ (d->bcdDevice >> 4) & 15, d->bcdDevice & 15);
+ printf ("iManufacturer %d (%s)\n", d->iManufacturer,
+ (vendor) ? vendor : "");
+ printf ("iProduct %d (%s)\n", d->iProduct,
+ (product) ? product : "");
+
+ buf = get_libusb_string_descriptor (dev, d->iSerialNumber);
+ printf ("iSerialNumber %d (%s)\n", d->iSerialNumber,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+ printf ("bNumConfigurations %d\n", d->bNumConfigurations);
+
+ for (config_nr = 0; config_nr < d->bNumConfigurations; config_nr++)
+ {
+ struct usb_config_descriptor *c = &dev->config[config_nr];
+ int interface_nr;
+
+ printf (" <configuration %d>\n", config_nr);
+ printf (" bLength %d\n", c->bLength);
+ printf (" bDescriptorType %d\n", c->bDescriptorType);
+ printf (" wTotalLength %d\n", c->wTotalLength);
+ printf (" bNumInterfaces %d\n", c->bNumInterfaces);
+ printf (" bConfigurationValue %d\n", c->bConfigurationValue);
+ buf = get_libusb_string_descriptor (dev, c->iConfiguration);
+ printf (" iConfiguration %d (%s)\n", c->iConfiguration,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+ printf (" bmAttributes %d (%s%s)\n", c->bmAttributes,
+ c->bmAttributes & 64 ? "Self-powered" : "",
+ c->bmAttributes & 32 ? "Remote Wakeup" : "");
+ printf (" MaxPower %d mA\n", c->MaxPower * 2);
+
+ for (interface_nr = 0; interface_nr < c->bNumInterfaces;
+ interface_nr++)
+ {
+ struct usb_interface *interface = &c->interface[interface_nr];
+ int alt_setting_nr;
+
+ printf (" <interface %d>\n", interface_nr);
+ for (alt_setting_nr = 0;
+ alt_setting_nr < interface->num_altsetting;
+ alt_setting_nr++)
+ {
+ struct usb_interface_descriptor *i
+ = &interface->altsetting[alt_setting_nr];
+ int ep_nr;
+ printf (" <altsetting %d>\n", alt_setting_nr);
+ printf (" bLength %d\n", i->bLength);
+ printf (" bDescriptorType %d\n", i->bDescriptorType);
+ printf (" bInterfaceNumber %d\n", i->bInterfaceNumber);
+ printf (" bAlternateSetting %d\n", i->bAlternateSetting);
+ printf (" bNumEndpoints %d\n", i->bNumEndpoints);
+ printf (" bInterfaceClass %d\n", i->bInterfaceClass);
+ printf (" bInterfaceSubClass %d\n",
+ i->bInterfaceSubClass);
+ printf (" bInterfaceProtocol %d\n",
+ i->bInterfaceProtocol);
+ buf = get_libusb_string_descriptor (dev, i->iInterface);
+ printf (" iInterface %d (%s)\n", i->iInterface,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+
+ for (ep_nr = 0; ep_nr < i->bNumEndpoints; ep_nr++)
+ {
+ struct usb_endpoint_descriptor *e = &i->endpoint[ep_nr];
+ char *ep_type;
+
+ switch (e->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+ {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ ep_type = "control";
+ break;
+ case USB_ENDPOINT_TYPE_ISOCHRONOUS:
+ ep_type = "isochronous";
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ ep_type = "bulk";
+ break;
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ ep_type = "interrupt";
+ break;
+ default:
+ ep_type = "unknown";
+ break;
+ }
+ printf (" <endpoint %d>\n", ep_nr);
+ printf (" bLength %d\n", e->bLength);
+ printf (" bDescriptorType %d\n",
+ e->bDescriptorType);
+ printf (" bEndpointAddress 0x%02X (%s 0x%02X)\n",
+ e->bEndpointAddress,
+ e->bEndpointAddress & USB_ENDPOINT_DIR_MASK ?
+ "in" : "out",
+ e->
+ bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
+ printf (" bmAttributes %d (%s)\n",
+ e->bmAttributes, ep_type);
+ printf (" wMaxPacketSize %d\n",
+ e->wMaxPacketSize);
+ printf (" bInterval %d ms\n", e->bInterval);
+ printf (" bRefresh %d\n", e->bRefresh);
+ printf (" bSynchAddress %d\n", e->bSynchAddress);
+ }
+ }
+ }
+ }
+
+ }
+
+ /* Some heuristics, which device may be a scanner */
+ if (dev->descriptor.idVendor == 0) /* hub */
+ --is_scanner;
+ if (dev->descriptor.idProduct == 0) /* hub */
+ --is_scanner;
+
+ for (interface_nr = 0; interface_nr < dev->config[0].bNumInterfaces && is_scanner <= 0; interface_nr++)
+ {
+ switch (dev->descriptor.bDeviceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ ++is_scanner;
+ break;
+ case USB_CLASS_PER_INTERFACE:
+ if (dev->config[0].interface[interface_nr].num_altsetting == 0 ||
+ !dev->config[0].interface[interface_nr].altsetting)
+ break;
+ switch (dev->config[0].interface[interface_nr].altsetting[0].bInterfaceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ case USB_CLASS_PER_INTERFACE:
+ case 16: /* data? */
+ ++is_scanner;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (is_scanner > 0)
+ {
+ char * chipset = check_usb_chip (dev, verbose, from_file);
+
+ printf ("found USB scanner (vendor=0x%04x", dev->descriptor.idVendor);
+ if (vendor)
+ printf (" [%s]", vendor);
+ printf (", product=0x%04x", dev->descriptor.idProduct);
+ if (product)
+ printf (" [%s]", product);
+ if (chipset)
+ printf (", chip=%s", chipset);
+ if (from_file)
+ printf (")\n");
+ else
+ printf (") at libusb:%s:%s\n", dev->bus->dirname, dev->filename);
+
+ libusb_device_found = SANE_TRUE;
+ device_found = SANE_TRUE;
+ }
+
+ if (vendor)
+ free (vendor);
+
+ if (product)
+ free (product);
+}
+#endif /* HAVE_LIBUSB */
+
+
+#ifdef HAVE_LIBUSB_1_0
+static char *
+sfs_libusb_strerror (int errcode)
+{
+ /* Error codes & descriptions from the libusb-1.0 documentation */
+
+ switch (errcode)
+ {
+ case LIBUSB_SUCCESS:
+ return "Success (no error)";
+
+ case LIBUSB_ERROR_IO:
+ return "Input/output error";
+
+ case LIBUSB_ERROR_INVALID_PARAM:
+ return "Invalid parameter";
+
+ case LIBUSB_ERROR_ACCESS:
+ return "Access denied (insufficient permissions)";
+
+ case LIBUSB_ERROR_NO_DEVICE:
+ return "No such device (it may have been disconnected)";
+
+ case LIBUSB_ERROR_NOT_FOUND:
+ return "Entity not found";
+
+ case LIBUSB_ERROR_BUSY:
+ return "Resource busy";
+
+ case LIBUSB_ERROR_TIMEOUT:
+ return "Operation timed out";
+
+ case LIBUSB_ERROR_OVERFLOW:
+ return "Overflow";
+
+ case LIBUSB_ERROR_PIPE:
+ return "Pipe error";
+
+ case LIBUSB_ERROR_INTERRUPTED:
+ return "System call interrupted (perhaps due to signal)";
+
+ case LIBUSB_ERROR_NO_MEM:
+ return "Insufficient memory";
+
+ case LIBUSB_ERROR_NOT_SUPPORTED:
+ return "Operation not supported or unimplemented on this platform";
+
+ case LIBUSB_ERROR_OTHER:
+ return "Other error";
+
+ default:
+ return "Unknown libusb-1.0 error code";
+ }
+
+ return "Unknown libusb-1.0 error code";
+}
+
+static char *
+get_libusb_string_descriptor (libusb_device_handle *hdl, int index)
+{
+ unsigned char *buffer, short_buffer[2];
+ int size;
+ int ret;
+ int i;
+
+ if (!index)
+ return NULL;
+
+ ret = libusb_get_descriptor (hdl, LIBUSB_DT_STRING, index,
+ short_buffer, sizeof (short_buffer));
+ if (ret < 0)
+ {
+ printf ("could not fetch string descriptor: %s\n",
+ sfs_libusb_strerror (ret));
+ return NULL;
+ }
+
+ if ((short_buffer[0] < 2) /* descriptor length */
+ || (short_buffer[1] != LIBUSB_DT_STRING)) /* descriptor type */
+ return NULL;
+
+ size = short_buffer[0];
+
+ buffer = calloc (1, size + 1);
+ if (!buffer)
+ return NULL;
+
+ ret = libusb_get_descriptor (hdl, LIBUSB_DT_STRING, index,
+ buffer, size);
+ if (ret < 0)
+ {
+ printf ("could not fetch string descriptor (again): %s\n",
+ sfs_libusb_strerror (ret));
+ free (buffer);
+ return NULL;
+ }
+
+ if ((buffer[0] < 2) || (buffer[0] > size) /* descriptor length */
+ || (buffer[1] != LIBUSB_DT_STRING)) /* descriptor type */
+ {
+ free (buffer);
+ return NULL;
+ }
+
+ size = buffer[0] - 2;
+ for (i = 0; i < (size / 2); i++)
+ buffer[i] = buffer[2 + 2 * i];
+ buffer[i] = '\0';
+
+ return (char *) buffer;
+}
+
+static void
+check_libusb_device (libusb_device *dev, SANE_Bool from_file)
+{
+ libusb_device_handle *hdl;
+ struct libusb_device_descriptor desc;
+ struct libusb_config_descriptor *config0;
+
+ int is_scanner = 0;
+ char *vendor;
+ char *product;
+ unsigned short vid, pid;
+ unsigned char busno, address;
+ int config;
+ int intf;
+ int ret;
+
+ busno = libusb_get_bus_number (dev);
+ address = libusb_get_device_address (dev);
+
+ ret = libusb_get_device_descriptor (dev, &desc);
+ if (ret < 0)
+ {
+ printf ("could not get device descriptor for device at %03d:%03d: %s\n",
+ busno, address, sfs_libusb_strerror (ret));
+ return;
+ }
+
+ vid = desc.idVendor;
+ pid = desc.idProduct;
+
+ ret = libusb_open (dev, &hdl);
+ if (ret < 0)
+ {
+ printf ("could not open USB device 0x%04x/0x%04x at %03d:%03d: %s\n",
+ vid, pid, busno, address, sfs_libusb_strerror (ret));
+ return;
+ }
+
+ ret = libusb_get_configuration (hdl, &config);
+ if (ret < 0)
+ {
+ printf ("could not get configuration for device 0x%04x/0x%04x at %03d:%03d: %s\n",
+ vid, pid, busno, address, sfs_libusb_strerror (ret));
+ libusb_close (hdl);
+ return;
+ }
+
+ if (config == 0)
+ {
+ if (verbose > 1)
+ printf ("device 0x%04x/0x%04x at %03d:%03d is not configured\n",
+ vid, pid, busno, address);
+ libusb_close (hdl);
+ return;
+ }
+
+ vendor = get_libusb_string_descriptor (hdl, desc.iManufacturer);
+ product = get_libusb_string_descriptor (hdl, desc.iProduct);
+
+ if (verbose > 2)
+ {
+ /* print everything we know about the device */
+ char *buf;
+ int config_nr;
+
+ printf ("\n");
+ printf ("<device descriptor of 0x%04x/0x%04x at %03d:%03d",
+ vid, pid, busno, address);
+ if (vendor || product)
+ {
+ printf (" (%s%s%s)", (vendor) ? vendor : "",
+ (vendor && product) ? " " : "", (product) ? product : "");
+ }
+ printf (">\n");
+ printf ("bLength %d\n", desc.bLength);
+ printf ("bDescriptorType %d\n", desc.bDescriptorType);
+ printf ("bcdUSB %d.%d%d\n", desc.bcdUSB >> 8,
+ (desc.bcdUSB >> 4) & 15, desc.bcdUSB & 15);
+ printf ("bDeviceClass %d\n", desc.bDeviceClass);
+ printf ("bDeviceSubClass %d\n", desc.bDeviceSubClass);
+ printf ("bDeviceProtocol %d\n", desc.bDeviceProtocol);
+ printf ("bMaxPacketSize0 %d\n", desc.bMaxPacketSize0);
+ printf ("idVendor 0x%04X\n", desc.idVendor);
+ printf ("idProduct 0x%04X\n", desc.idProduct);
+ printf ("bcdDevice %d.%d%d\n", desc.bcdDevice >> 8,
+ (desc.bcdDevice >> 4) & 15, desc.bcdDevice & 15);
+ printf ("iManufacturer %d (%s)\n", desc.iManufacturer,
+ (vendor) ? vendor : "");
+ printf ("iProduct %d (%s)\n", desc.iProduct,
+ (product) ? product : "");
+ buf = get_libusb_string_descriptor (hdl, desc.iSerialNumber);
+ printf ("iSerialNumber %d (%s)\n", desc.iSerialNumber,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+ printf ("bNumConfigurations %d\n", desc.bNumConfigurations);
+
+ for (config_nr = 0; config_nr < desc.bNumConfigurations; config_nr++)
+ {
+ struct libusb_config_descriptor *c;
+
+ ret = libusb_get_config_descriptor (dev, config_nr, &c);
+ if (ret < 0)
+ {
+ printf ("could not get configuration descriptor %d: %s\n",
+ config_nr, sfs_libusb_strerror (ret));
+ continue;
+ }
+
+ printf (" <configuration %d>\n", config_nr);
+ printf (" bLength %d\n", c->bLength);
+ printf (" bDescriptorType %d\n", c->bDescriptorType);
+ printf (" wTotalLength %d\n", c->wTotalLength);
+ printf (" bNumInterfaces %d\n", c->bNumInterfaces);
+ printf (" bConfigurationValue %d\n", c->bConfigurationValue);
+
+ buf = get_libusb_string_descriptor (hdl, c->iConfiguration);
+ printf (" iConfiguration %d (%s)\n", c->iConfiguration,
+ (buf) ? buf : "");
+ free (buf);
+
+ printf (" bmAttributes %d (%s%s)\n", c->bmAttributes,
+ c->bmAttributes & 64 ? "Self-powered" : "",
+ c->bmAttributes & 32 ? "Remote Wakeup" : "");
+ printf (" MaxPower %d mA\n", c->MaxPower * 2);
+
+ for (intf = 0; intf < c->bNumInterfaces; intf++)
+ {
+ const struct libusb_interface *interface;
+ int alt_setting_nr;
+
+ interface = &c->interface[intf];
+
+ printf (" <interface %d>\n", intf);
+ for (alt_setting_nr = 0;
+ alt_setting_nr < interface->num_altsetting;
+ alt_setting_nr++)
+ {
+ const struct libusb_interface_descriptor *i;
+ int ep_nr;
+
+ i = &interface->altsetting[alt_setting_nr];
+
+ printf (" <altsetting %d>\n", alt_setting_nr);
+ printf (" bLength %d\n", i->bLength);
+ printf (" bDescriptorType %d\n", i->bDescriptorType);
+ printf (" bInterfaceNumber %d\n", i->bInterfaceNumber);
+ printf (" bAlternateSetting %d\n", i->bAlternateSetting);
+ printf (" bNumEndpoints %d\n", i->bNumEndpoints);
+ printf (" bInterfaceClass %d\n", i->bInterfaceClass);
+ printf (" bInterfaceSubClass %d\n",
+ i->bInterfaceSubClass);
+ printf (" bInterfaceProtocol %d\n",
+ i->bInterfaceProtocol);
+
+ buf = NULL;
+ buf = get_libusb_string_descriptor (hdl, i->iInterface);
+ printf (" iInterface %d (%s)\n", i->iInterface,
+ (buf) ? buf : "");
+ free (buf);
+ for (ep_nr = 0; ep_nr < i->bNumEndpoints; ep_nr++)
+ {
+ const struct libusb_endpoint_descriptor *e;
+ char *ep_type;
+
+ e = &i->endpoint[ep_nr];
+
+ switch (e->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+ {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ ep_type = "control";
+ break;
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ ep_type = "isochronous";
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ ep_type = "bulk";
+ break;
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ ep_type = "interrupt";
+ break;
+ default:
+ ep_type = "unknown";
+ break;
+ }
+ printf (" <endpoint %d>\n", ep_nr);
+ printf (" bLength %d\n", e->bLength);
+ printf (" bDescriptorType %d\n",
+ e->bDescriptorType);
+ printf (" bEndpointAddress 0x%02X (%s 0x%02X)\n",
+ e->bEndpointAddress,
+ e->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK ?
+ "in" : "out",
+ e->
+ bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
+ printf (" bmAttributes %d (%s)\n",
+ e->bmAttributes, ep_type);
+ printf (" wMaxPacketSize %d\n",
+ e->wMaxPacketSize);
+ printf (" bInterval %d ms\n", e->bInterval);
+ printf (" bRefresh %d\n", e->bRefresh);
+ printf (" bSynchAddress %d\n", e->bSynchAddress);
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Some heuristics, which device may be a scanner */
+ if (desc.idVendor == 0) /* hub */
+ --is_scanner;
+ if (desc.idProduct == 0) /* hub */
+ --is_scanner;
+
+ ret = libusb_get_config_descriptor (dev, 0, &config0);
+ if (ret < 0)
+ {
+ printf ("could not get config[0] descriptor: %s\n",
+ sfs_libusb_strerror (ret));
+
+ goto out_free;
+ }
+
+ for (intf = 0; (intf < config0->bNumInterfaces) && (is_scanner <= 0); intf++)
+ {
+ switch (desc.bDeviceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ ++is_scanner;
+ break;
+ case USB_CLASS_PER_INTERFACE:
+ if ((config0->interface[intf].num_altsetting == 0)
+ || !config0->interface[intf].altsetting)
+ break;
+ switch (config0->interface[intf].altsetting[0].bInterfaceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ case USB_CLASS_PER_INTERFACE:
+ case 16: /* data? */
+ ++is_scanner;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (is_scanner > 0)
+ {
+ char *chipset = NULL;
+
+ if(!from_file)
+ chipset = check_usb_chip (verbose, desc, hdl, config0);
+
+ printf ("found USB scanner (vendor=0x%04x", vid);
+ if (vendor)
+ printf (" [%s]", vendor);
+ printf (", product=0x%04x", pid);
+ if (product)
+ printf (" [%s]", product);
+ if (chipset)
+ printf (", chip=%s", chipset);
+ if (from_file)
+ printf (")\n");
+ else
+ printf (") at libusb:%03d:%03d\n", busno, address);
+
+ libusb_device_found = SANE_TRUE;
+ device_found = SANE_TRUE;
+ }
+
+ libusb_free_config_descriptor (config0);
+
+ out_free:
+ libusb_close (hdl);
+ if (vendor)
+ free (vendor);
+
+ if (product)
+ free (product);
+}
+#endif /* HAVE_LIBUSB_1_0 */
+
+
+static DIR *
+scan_directory (char *dir_name)
+{
+ struct stat stat_buf;
+ DIR *dir;
+
+ if (verbose > 2)
+ printf ("scanning directory %s\n", dir_name);
+
+ if (stat (dir_name, &stat_buf) < 0)
+ {
+ if (verbose > 1)
+ printf ("cannot stat `%s' (%s)\n", dir_name, strerror (errno));
+ return 0;
+ }
+ if (!S_ISDIR (stat_buf.st_mode))
+ {
+ if (verbose > 1)
+ printf ("`%s' is not a directory\n", dir_name);
+ return 0;
+ }
+ if ((dir = opendir (dir_name)) == 0)
+ {
+ if (verbose > 1)
+ printf ("cannot read directory `%s' (%s)\n", dir_name,
+ strerror (errno));
+ return 0;
+ }
+ return dir;
+}
+
+static char *
+get_next_file (char *dir_name, DIR * dir)
+{
+ struct dirent *dir_entry;
+ static char file_name[PATH_MAX];
+
+ do
+ {
+ dir_entry = readdir (dir);
+ if (!dir_entry)
+ return 0;
+ }
+ while (strcmp (dir_entry->d_name, ".") == 0
+ || strcmp (dir_entry->d_name, "..") == 0);
+
+ if (strlen (dir_name) + strlen (dir_entry->d_name) + 1 > PATH_MAX)
+ {
+ if (verbose > 1)
+ printf ("filename too long\n");
+ return 0;
+ }
+ sprintf (file_name, "%s%s", dir_name, dir_entry->d_name);
+ return file_name;
+}
+
+#if defined(WIN32_SCSI)
+/* Return a list of potential scanners. There's a lot of hardcoded values here that might break on a system with lots of scsi devices. */
+static char **build_scsi_dev_list(void)
+{
+ char **dev_list;
+ int dev_list_index;
+ int hca;
+ HANDLE fd;
+ char scsi_hca_name[20];
+ char buffer[4096];
+ DWORD BytesReturned;
+ BOOL ret;
+ size_t dev_list_size;
+ PSCSI_ADAPTER_BUS_INFO adapter;
+ PSCSI_INQUIRY_DATA inquiry;
+ int i;
+
+ /* Allocate room for about 100 scanners. That should be enough. */
+ dev_list_size = 100;
+ dev_list_index = 0;
+ dev_list = calloc(1, dev_list_size * sizeof(char *));
+
+ hca = 0;
+
+ for(hca = 0; ; hca++) {
+
+ /* Open the adapter */
+ snprintf(scsi_hca_name, 20, "\\\\.\\Scsi%d:", hca);
+ fd = CreateFile(scsi_hca_name, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_RANDOM_ACCESS, NULL );
+
+ if (fd == INVALID_HANDLE_VALUE) {
+ /* Assume there is no more adapter. This is wrong in the case
+ * of hot-plug stuff, but I have yet to see it on a user
+ * machine. */
+ break;
+ }
+
+ /* Get the inquiry info for the devices on that hca. */
+ ret = DeviceIoControl(fd,
+ IOCTL_SCSI_GET_INQUIRY_DATA,
+ NULL,
+ 0,
+ buffer,
+ sizeof(buffer),
+ &BytesReturned,
+ FALSE);
+
+ if(ret == 0)
+ {
+ CloseHandle(fd);
+ continue;
+ }
+
+ adapter = (PSCSI_ADAPTER_BUS_INFO)buffer;
+
+ for(i = 0; i < adapter->NumberOfBuses; i++) {
+
+ if (adapter->BusData[i].InquiryDataOffset == 0) {
+ /* No device here */
+ continue;
+ }
+
+ inquiry = (PSCSI_INQUIRY_DATA) (buffer +
+ adapter->BusData[i].InquiryDataOffset);
+ while(1) {
+ /* Check if it is a scanner or a processor
+ * device. Ignore the other
+ * device types. */
+ if (inquiry->InquiryDataLength >= 5 &&
+ ((inquiry->InquiryData[0] & 0x1f) == 3 ||
+ (inquiry->InquiryData[0] & 0x1f) == 6)) {
+ char device_name[20];
+ sprintf(device_name, "h%db%dt%dl%d", hca, inquiry->PathId, inquiry->TargetId, inquiry->Lun);
+ dev_list[dev_list_index] = strdup(device_name);
+ dev_list_index++;
+ }
+
+ if (inquiry->NextInquiryDataOffset == 0) {
+ /* No device here */
+ break;
+ } else {
+ inquiry = (PSCSI_INQUIRY_DATA) (buffer +
+ inquiry->NextInquiryDataOffset);
+ }
+ }
+ }
+
+ CloseHandle(fd);
+
+ }
+
+ return dev_list;
+
+}
+#endif
+
+#if defined (HAVE_IOKIT_CDB_IOSCSILIB_H) || \
+ defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
+ defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
+char **scsi_dev_list;
+int scsi_dev_list_index;
+
+static SANE_Status AddToSCSIDeviceList (const char *dev) {
+ if (scsi_dev_list_index < 99) {
+ scsi_dev_list [scsi_dev_list_index] = strdup (dev);
+ scsi_dev_list_index++;
+ return SANE_STATUS_GOOD;
+ }
+ else
+ return SANE_STATUS_NO_MEM;
+}
+
+static char **build_scsi_dev_list(void)
+{
+ scsi_dev_list_index = 0;
+ scsi_dev_list = malloc (100 * sizeof(char *));
+ sanei_scsi_find_devices (NULL, NULL, NULL, -1, -1, -1, -1,
+ AddToSCSIDeviceList);
+ scsi_dev_list [scsi_dev_list_index] = NULL;
+ return scsi_dev_list;
+}
+#endif
+
+static int
+check_mustek_pp_device (void)
+{
+ const char **devices;
+ int ctr = 0, found = 0, scsi = 0;
+
+ if (verbose > 1)
+ printf ("searching for Mustek parallel port scanners:\n");
+
+ devices = sanei_pa4s2_devices ();
+
+ while (devices[ctr] != NULL) {
+ int fd;
+ SANE_Status result;
+
+ /* ordinary parallel port scanner type */
+ if (verbose > 1)
+ printf ("checking %s...", devices[ctr]);
+
+ result = sanei_pa4s2_open (devices[ctr], &fd);
+
+ if (verbose > 1)
+ {
+ if (result != 0)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ else
+ printf (" open ok\n");
+ }
+
+ if (result == 0) {
+ printf ("found possible Mustek parallel port scanner at \"%s\"\n",
+ devices[ctr]);
+ found++;
+ sanei_pa4s2_close(fd);
+ }
+
+ /* trying scsi over pp devices */
+ if (verbose > 1)
+ printf ("checking %s (SCSI emulation)...", devices[ctr]);
+
+ result = sanei_pa4s2_scsi_pp_open (devices[ctr], &fd);
+
+ if (verbose > 1)
+ {
+ if (result != 0)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ else
+ printf (" open ok\n");
+ }
+
+ if (result == 0) {
+ printf ("found possible Mustek SCSI over PP scanner at \"%s\"\n",
+ devices[ctr]);
+ scsi++;
+ sanei_pa4s2_close(fd);
+ }
+
+ ctr++;
+ }
+
+ free(devices);
+
+ if (found > 0 && verbose > 0)
+ printf("\n # Your Mustek parallel port scanner was detected. It may or\n"
+ " # may not be supported by SANE. Please read the sane-mustek_pp\n"
+ " # man-page for setup instructions.\n");
+
+ if (scsi > 0 && verbose > 0)
+ printf("\n # Your Mustek parallel port scanner was detected. It may or\n"
+ " # may not be supported by SANE. Please read the sane-mustek_pp\n"
+ " # man-page for setup instructions.\n");
+
+ return (found > 0 || scsi > 0);
+}
+
+#ifdef HAVE_LIBUSB
+static SANE_Bool
+parse_num (char* search, const char* line, int base, long int * number)
+{
+ char* start_number;
+
+ start_number = strstr (line, search);
+ if (start_number == NULL)
+ return SANE_FALSE;
+ start_number += strlen (search);
+
+ *number = strtol (start_number, NULL, base);
+ if (verbose > 2)
+ printf ("Found %s%ld\n", search, *number);
+ return SANE_TRUE;
+}
+
+static SANE_Bool
+parse_bcd (char* search, const char* line, long int * number)
+{
+ char* start_number;
+ char* end_number;
+ int first_part;
+ int second_part;
+
+ start_number = strstr (line, search);
+ if (start_number == NULL)
+ return SANE_FALSE;
+ start_number += strlen (search);
+
+ first_part = strtol (start_number, &end_number, 10);
+ start_number = end_number + 1; /* skip colon */
+ second_part = strtol (start_number, NULL, 10);
+ *number = ((first_part / 10) << 12) + ((first_part % 10) << 8)
+ + ((second_part / 10) << 4) + (second_part % 10);
+ if (verbose > 2)
+ printf ("Found %s%ld\n", search, *number);
+ return SANE_TRUE;
+}
+
+static void
+parse_file (char *filename)
+{
+ FILE * parsefile;
+ char line [PATH_MAX], *token;
+ const char * p;
+ struct usb_device *dev = 0;
+ long int number = 0;
+ int current_config = 1;
+ int current_if = -1;
+ int current_as = -1;
+ int current_ep = -1;
+
+ if (verbose > 1)
+ printf ("trying to open %s\n", filename);
+ parsefile = fopen (filename, "r");
+
+ if (parsefile == NULL)
+ {
+ if (verbose > 0)
+ printf ("opening %s failed: %s\n", filename, strerror (errno));
+ return;
+ }
+
+ while (sanei_config_read (line, PATH_MAX, parsefile))
+ {
+ if (verbose > 2)
+ printf ("parsing line: `%s'\n", line);
+ p = sanei_config_get_string (line, &token);
+ if (!token || !p || token[0] == '\0')
+ continue;
+ if (token[1] != ':')
+ {
+ if (verbose > 2)
+ printf ("missing `:'?\n");
+ continue;
+ }
+ switch (token[0])
+ {
+ case 'T':
+ if (dev)
+ check_libusb_device (dev, SANE_TRUE);
+ dev = calloc (1, sizeof (struct usb_device));
+ dev->bus = calloc (1, sizeof (struct usb_bus));
+ current_config = 1;
+ current_if = -1;
+ current_as = -1;
+ current_ep = -1;
+ break;
+ case 'D':
+ if (parse_bcd ("Ver=", line, &number))
+ dev->descriptor.bcdUSB = number;
+ if (parse_num ("Cls=", line, 16, &number))
+ dev->descriptor.bDeviceClass = number;
+ if (parse_num ("Sub=", line, 16, &number))
+ dev->descriptor.bDeviceSubClass = number;
+ if (parse_num ("Prot=", line, 16, &number))
+ dev->descriptor.bDeviceProtocol = number;
+ if (parse_num ("MxPS=", line, 10, &number))
+ dev->descriptor.bMaxPacketSize0 = number;
+ if (parse_num ("#Cfgs=", line, 10, &number))
+ dev->descriptor.bNumConfigurations = number;
+ dev->config = calloc (number, sizeof (struct usb_config_descriptor));
+ break;
+ case 'P':
+ if (parse_num ("Vendor=", line, 16, &number))
+ dev->descriptor.idVendor = number;
+ if (parse_num ("ProdID=", line, 16, &number))
+ dev->descriptor.idProduct = number;
+ if (parse_bcd ("Rev=", line, &number))
+ dev->descriptor.bcdDevice = number;
+ break;
+ case 'C':
+ current_if = -1;
+ current_as = -1;
+ current_ep = -1;
+ if (parse_num ("Cfg#=", line, 10, &number))
+ {
+ current_config = number - 1;
+ dev->config[current_config].bConfigurationValue = number;
+ }
+ if (parse_num ("Ifs=", line, 10, &number))
+ dev->config[current_config].bNumInterfaces = number;
+ dev->config[current_config].interface
+ = calloc (number, sizeof (struct usb_interface));
+ if (parse_num ("Atr=", line, 16, &number))
+ dev->config[current_config].bmAttributes = number;
+ if (parse_num ("MxPwr=", line, 10, &number))
+ dev->config[current_config].MaxPower = number / 2;
+ break;
+ case 'I':
+ current_ep = -1;
+ if (parse_num ("If#=", line, 10, &number))
+ {
+ if (current_if != number)
+ {
+ current_if = number;
+ current_as = -1;
+ dev->config[current_config].interface[current_if].altsetting
+ = calloc (20, sizeof (struct usb_interface_descriptor));
+ /* Can't read number of altsettings */
+ dev->config[current_config].interface[current_if].num_altsetting = 1;
+ }
+ else
+ dev->config[current_config].interface[current_if].num_altsetting++;
+ }
+ if (parse_num ("Alt=", line, 10, &number))
+ {
+ current_as = number;
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceNumber
+ = current_if;
+ dev->config[current_config].interface[current_if].altsetting[current_as].bAlternateSetting
+ = current_as;
+ }
+ if (parse_num ("#EPs=", line, 10, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bNumEndpoints
+ = number;
+ dev->config[current_config].interface[current_if].altsetting[current_as].endpoint
+ = calloc (number, sizeof (struct usb_endpoint_descriptor));
+ if (parse_num ("Cls=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceClass
+ = number;
+ if (parse_num ("Sub=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceSubClass
+ = number;
+ if (parse_num ("Prot=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceProtocol
+ = number;
+ break;
+ case 'E':
+ current_ep++;
+ if (parse_num ("Ad=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].bEndpointAddress = number;
+ if (parse_num ("Atr=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].bmAttributes = number;
+ if (parse_num ("MxPS=", line, 10, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].wMaxPacketSize = number;
+ if (parse_num ("Ivl=", line, 10, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].bInterval = number;
+ break;
+ case 'S':
+ case 'B':
+ continue;
+ default:
+ if (verbose > 1)
+ printf ("ignoring unknown line identifier: %c\n", token[0]);
+ continue;
+ }
+ free (token);
+ }
+ if (dev)
+ check_libusb_device (dev, SANE_TRUE);
+ fclose (parsefile);
+ return;
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+ char **dev_list, **usb_dev_list, *dev_name, **ap;
+ int enable_pp_checks = SANE_FALSE;
+
+ prog_name = strrchr (argv[0], '/');
+ if (prog_name)
+ ++prog_name;
+ else
+ prog_name = argv[0];
+
+ for (ap = argv + 1; ap < argv + argc; ++ap)
+ {
+ if ((*ap)[0] != '-')
+ break;
+ switch ((*ap)[1])
+ {
+ case '?':
+ case 'h':
+ usage (0);
+ exit (0);
+
+ case 'v':
+ ++verbose;
+ break;
+
+ case 'q':
+ --verbose;
+ break;
+
+ case 'f':
+ force = SANE_TRUE;
+ break;
+
+ case 'p':
+ enable_pp_checks = SANE_TRUE;
+ break;
+
+ case 'F':
+#ifdef HAVE_LIBUSB
+ parse_file ((char *) (*(++ap)));
+#elif defined(HAVE_LIBUSB_1_0)
+ printf ("option -F not implemented with libusb-1.0\n");
+#else
+ printf ("libusb not available: option -F can't be used\n");
+#endif
+ exit (0);
+
+ default:
+ printf ("unknown option: -%c, try -h for help\n", (*ap)[1]);
+ exit (0);
+ }
+ }
+ if (ap < argv + argc)
+ {
+ dev_list = ap;
+ usb_dev_list = ap;
+ }
+ else
+ {
+ static char *default_dev_list[] = {
+#if defined(__sgi)
+ "/dev/scsi/sc0d1l0", "/dev/scsi/sc0d2l0",
+ "/dev/scsi/sc0d3l0", "/dev/scsi/sc0d4l0",
+ "/dev/scsi/sc0d5l0", "/dev/scsi/sc0d6l0",
+ "/dev/scsi/sc0d7l0", "/dev/scsi/sc0d8l0",
+ "/dev/scsi/sc0d9l0", "/dev/scsi/sc0d10l0",
+ "/dev/scsi/sc0d11l0", "/dev/scsi/sc0d12l0",
+ "/dev/scsi/sc0d13l0", "/dev/scsi/sc0d14l0",
+ "/dev/scsi/sc0d15l0",
+ "/dev/scsi/sc1d1l0", "/dev/scsi/sc1d2l0",
+ "/dev/scsi/sc1d3l0", "/dev/scsi/sc1d4l0",
+ "/dev/scsi/sc1d5l0", "/dev/scsi/sc1d6l0",
+ "/dev/scsi/sc1d7l0", "/dev/scsi/sc1d8l0",
+ "/dev/scsi/sc1d9l0", "/dev/scsi/sc1d10l0",
+ "/dev/scsi/sc1d11l0", "/dev/scsi/sc1d12l0",
+ "/dev/scsi/sc1d13l0", "/dev/scsi/sc1d14l0",
+ "/dev/scsi/sc1d15l0",
+ "/dev/scsi/sc2d1l0", "/dev/scsi/sc2d2l0",
+ "/dev/scsi/sc2d3l0", "/dev/scsi/sc2d4l0",
+ "/dev/scsi/sc2d5l0", "/dev/scsi/sc2d6l0",
+ "/dev/scsi/sc2d7l0", "/dev/scsi/sc2d8l0",
+ "/dev/scsi/sc2d9l0", "/dev/scsi/sc2d10l0",
+ "/dev/scsi/sc2d11l0", "/dev/scsi/sc2d12l0",
+ "/dev/scsi/sc2d13l0", "/dev/scsi/sc2d14l0",
+ "/dev/scsi/sc2d15l0",
+ "/dev/scsi/sc3d1l0", "/dev/scsi/sc3d2l0",
+ "/dev/scsi/sc3d3l0", "/dev/scsi/sc3d4l0",
+ "/dev/scsi/sc3d5l0", "/dev/scsi/sc3d6l0",
+ "/dev/scsi/sc3d7l0", "/dev/scsi/sc3d8l0",
+ "/dev/scsi/sc3d9l0", "/dev/scsi/sc3d10l0",
+ "/dev/scsi/sc3d11l0", "/dev/scsi/sc3d12l0",
+ "/dev/scsi/sc3d13l0", "/dev/scsi/sc3d14l0",
+ "/dev/scsi/sc3d15l0",
+ "/dev/scsi/sc4d1l0", "/dev/scsi/sc4d2l0",
+ "/dev/scsi/sc4d3l0", "/dev/scsi/sc4d4l0",
+ "/dev/scsi/sc4d5l0", "/dev/scsi/sc4d6l0",
+ "/dev/scsi/sc4d7l0", "/dev/scsi/sc4d8l0",
+ "/dev/scsi/sc4d9l0", "/dev/scsi/sc4d10l0",
+ "/dev/scsi/sc4d11l0", "/dev/scsi/sc4d12l0",
+ "/dev/scsi/sc4d13l0", "/dev/scsi/sc4d14l0",
+ "/dev/scsi/sc4d15l0",
+ "/dev/scsi/sc5d1l0", "/dev/scsi/sc5d2l0",
+ "/dev/scsi/sc5d3l0", "/dev/scsi/sc5d4l0",
+ "/dev/scsi/sc5d5l0", "/dev/scsi/sc5d6l0",
+ "/dev/scsi/sc5d7l0", "/dev/scsi/sc5d8l0",
+ "/dev/scsi/sc5d9l0", "/dev/scsi/sc5d10l0",
+ "/dev/scsi/sc5d11l0", "/dev/scsi/sc5d12l0",
+ "/dev/scsi/sc5d13l0", "/dev/scsi/sc5d14l0",
+ "/dev/scsi/sc5d15l0",
+ "/dev/scsi/sc6d1l0", "/dev/scsi/sc6d2l0",
+ "/dev/scsi/sc6d3l0", "/dev/scsi/sc6d4l0",
+ "/dev/scsi/sc6d5l0", "/dev/scsi/sc6d6l0",
+ "/dev/scsi/sc6d7l0", "/dev/scsi/sc6d8l0",
+ "/dev/scsi/sc6d9l0", "/dev/scsi/sc6d10l0",
+ "/dev/scsi/sc6d11l0", "/dev/scsi/sc6d12l0",
+ "/dev/scsi/sc6d13l0", "/dev/scsi/sc6d14l0",
+ "/dev/scsi/sc6d15l0",
+ "/dev/scsi/sc7d1l0", "/dev/scsi/sc7d2l0",
+ "/dev/scsi/sc7d3l0", "/dev/scsi/sc7d4l0",
+ "/dev/scsi/sc7d5l0", "/dev/scsi/sc7d6l0",
+ "/dev/scsi/sc7d7l0", "/dev/scsi/sc7d8l0",
+ "/dev/scsi/sc7d9l0", "/dev/scsi/sc7d10l0",
+ "/dev/scsi/sc7d11l0", "/dev/scsi/sc7d12l0",
+ "/dev/scsi/sc7d13l0", "/dev/scsi/sc7d14l0",
+ "/dev/scsi/sc7d15l0",
+ "/dev/scsi/sc8d1l0", "/dev/scsi/sc8d2l0",
+ "/dev/scsi/sc8d3l0", "/dev/scsi/sc8d4l0",
+ "/dev/scsi/sc8d5l0", "/dev/scsi/sc8d6l0",
+ "/dev/scsi/sc8d7l0", "/dev/scsi/sc8d8l0",
+ "/dev/scsi/sc8d9l0", "/dev/scsi/sc8d10l0",
+ "/dev/scsi/sc8d11l0", "/dev/scsi/sc8d12l0",
+ "/dev/scsi/sc8d13l0", "/dev/scsi/sc8d14l0",
+ "/dev/scsi/sc8d15l0",
+ "/dev/scsi/sc9d1l0", "/dev/scsi/sc9d2l0",
+ "/dev/scsi/sc9d3l0", "/dev/scsi/sc9d4l0",
+ "/dev/scsi/sc9d5l0", "/dev/scsi/sc9d6l0",
+ "/dev/scsi/sc9d7l0", "/dev/scsi/sc9d8l0",
+ "/dev/scsi/sc9d9l0", "/dev/scsi/sc9d10l0",
+ "/dev/scsi/sc9d11l0", "/dev/scsi/sc9d12l0",
+ "/dev/scsi/sc9d13l0", "/dev/scsi/sc9d14l0",
+ "/dev/scsi/sc9d15l0",
+ "/dev/scsi/sc10d1l0", "/dev/scsi/sc10d2l0",
+ "/dev/scsi/sc10d3l0", "/dev/scsi/sc10d4l0",
+ "/dev/scsi/sc10d5l0", "/dev/scsi/sc10d6l0",
+ "/dev/scsi/sc10d7l0", "/dev/scsi/sc10d8l0",
+ "/dev/scsi/sc10d9l0", "/dev/scsi/sc10d10l0",
+ "/dev/scsi/sc10d11l0", "/dev/scsi/sc10d12l0",
+ "/dev/scsi/sc10d13l0", "/dev/scsi/sc10d14l0",
+ "/dev/scsi/sc10d15l0",
+ "/dev/scsi/sc11d1l0", "/dev/scsi/sc11d2l0",
+ "/dev/scsi/sc11d3l0", "/dev/scsi/sc11d4l0",
+ "/dev/scsi/sc11d5l0", "/dev/scsi/sc11d6l0",
+ "/dev/scsi/sc11d7l0", "/dev/scsi/sc11d8l0",
+ "/dev/scsi/sc11d9l0", "/dev/scsi/sc11d10l0",
+ "/dev/scsi/sc11d11l0", "/dev/scsi/sc11d12l0",
+ "/dev/scsi/sc11d13l0", "/dev/scsi/sc11d14l0",
+ "/dev/scsi/sc11d15l0",
+ "/dev/scsi/sc12d1l0", "/dev/scsi/sc12d2l0",
+ "/dev/scsi/sc12d3l0", "/dev/scsi/sc12d4l0",
+ "/dev/scsi/sc12d5l0", "/dev/scsi/sc12d6l0",
+ "/dev/scsi/sc12d7l0", "/dev/scsi/sc12d8l0",
+ "/dev/scsi/sc12d9l0", "/dev/scsi/sc12d10l0",
+ "/dev/scsi/sc12d11l0", "/dev/scsi/sc12d12l0",
+ "/dev/scsi/sc12d13l0", "/dev/scsi/sc12d14l0",
+ "/dev/scsi/sc12d15l0",
+ "/dev/scsi/sc13d1l0", "/dev/scsi/sc13d2l0",
+ "/dev/scsi/sc13d3l0", "/dev/scsi/sc13d4l0",
+ "/dev/scsi/sc13d5l0", "/dev/scsi/sc13d6l0",
+ "/dev/scsi/sc13d7l0", "/dev/scsi/sc13d8l0",
+ "/dev/scsi/sc13d9l0", "/dev/scsi/sc13d10l0",
+ "/dev/scsi/sc13d11l0", "/dev/scsi/sc13d12l0",
+ "/dev/scsi/sc13d13l0", "/dev/scsi/sc13d14l0",
+ "/dev/scsi/sc13d15l0",
+ "/dev/scsi/sc14d1l0", "/dev/scsi/sc14d2l0",
+ "/dev/scsi/sc14d3l0", "/dev/scsi/sc14d4l0",
+ "/dev/scsi/sc14d5l0", "/dev/scsi/sc14d6l0",
+ "/dev/scsi/sc14d7l0", "/dev/scsi/sc14d8l0",
+ "/dev/scsi/sc14d9l0", "/dev/scsi/sc14d10l0",
+ "/dev/scsi/sc14d11l0", "/dev/scsi/sc14d12l0",
+ "/dev/scsi/sc14d13l0", "/dev/scsi/sc14d14l0",
+ "/dev/scsi/sc14d15l0",
+ "/dev/scsi/sc15d1l0", "/dev/scsi/sc15d2l0",
+ "/dev/scsi/sc15d3l0", "/dev/scsi/sc15d4l0",
+ "/dev/scsi/sc15d5l0", "/dev/scsi/sc15d6l0",
+ "/dev/scsi/sc15d7l0", "/dev/scsi/sc15d8l0",
+ "/dev/scsi/sc15d9l0", "/dev/scsi/sc15d10l0",
+ "/dev/scsi/sc15d11l0", "/dev/scsi/sc15d12l0",
+ "/dev/scsi/sc15d13l0", "/dev/scsi/sc15d14l0",
+ "/dev/scsi/sc15d15l0",
+#elif defined(__EMX__)
+ "b0t0l0", "b0t1l0", "b0t2l0", "b0t3l0",
+ "b0t4l0", "b0t5l0", "b0t6l0", "b0t7l0",
+ "b1t0l0", "b1t1l0", "b1t2l0", "b1t3l0",
+ "b1t4l0", "b1t5l0", "b1t6l0", "b1t7l0",
+ "b2t0l0", "b2t1l0", "b2t2l0", "b2t3l0",
+ "b2t4l0", "b2t5l0", "b2t6l0", "b2t7l0",
+ "b3t0l0", "b3t1l0", "b3t2l0", "b3t3l0",
+ "b3t4l0", "b3t5l0", "b3t6l0", "b3t7l0",
+#elif defined(__linux__)
+ "/dev/scanner",
+ "/dev/sg0", "/dev/sg1", "/dev/sg2", "/dev/sg3",
+ "/dev/sg4", "/dev/sg5", "/dev/sg6", "/dev/sg7",
+ "/dev/sg8", "/dev/sg9",
+ "/dev/sga", "/dev/sgb", "/dev/sgc", "/dev/sgd",
+ "/dev/sge", "/dev/sgf", "/dev/sgg", "/dev/sgh",
+ "/dev/sgi", "/dev/sgj", "/dev/sgk", "/dev/sgl",
+ "/dev/sgm", "/dev/sgn", "/dev/sgo", "/dev/sgp",
+ "/dev/sgq", "/dev/sgr", "/dev/sgs", "/dev/sgt",
+ "/dev/sgu", "/dev/sgv", "/dev/sgw", "/dev/sgx",
+ "/dev/sgy", "/dev/sgz",
+#elif defined(__NeXT__)
+ "/dev/sg0a", "/dev/sg0b", "/dev/sg0c", "/dev/sg0d",
+ "/dev/sg0e", "/dev/sg0f", "/dev/sg0g", "/dev/sg0h",
+ "/dev/sg1a", "/dev/sg1b", "/dev/sg1c", "/dev/sg1d",
+ "/dev/sg1e", "/dev/sg1f", "/dev/sg1g", "/dev/sg1h",
+ "/dev/sg2a", "/dev/sg2b", "/dev/sg2c", "/dev/sg2d",
+ "/dev/sg2e", "/dev/sg2f", "/dev/sg2g", "/dev/sg2h",
+ "/dev/sg3a", "/dev/sg3b", "/dev/sg3c", "/dev/sg3d",
+ "/dev/sg3e", "/dev/sg3f", "/dev/sg3g", "/dev/sg3h",
+#elif defined(_AIX)
+ "/dev/scanner",
+ "/dev/gsc0", "/dev/gsc1", "/dev/gsc2", "/dev/gsc3",
+ "/dev/gsc4", "/dev/gsc5", "/dev/gsc6", "/dev/gsc7",
+ "/dev/gsc8", "/dev/gsc9", "/dev/gsc10", "/dev/gsc11",
+ "/dev/gsc12", "/dev/gsc13", "/dev/gsc14", "/dev/gsc15",
+#elif defined(__sun)
+ "/dev/scg0a", "/dev/scg0b", "/dev/scg0c", "/dev/scg0d",
+ "/dev/scg0e", "/dev/scg0f", "/dev/scg0g",
+ "/dev/scg1a", "/dev/scg1b", "/dev/scg1c", "/dev/scg1d",
+ "/dev/scg1e", "/dev/scg1f", "/dev/scg1g",
+ "/dev/scg2a", "/dev/scg2b", "/dev/scg2c", "/dev/scg2d",
+ "/dev/scg2e", "/dev/scg2f", "/dev/scg2g",
+ "/dev/sg/0", "/dev/sg/1", "/dev/sg/2", "/dev/sg/3",
+ "/dev/sg/4", "/dev/sg/5", "/dev/sg/6",
+ "/dev/scsi/scanner/", "/dev/scsi/processor/",
+#elif defined(HAVE_CAMLIB_H)
+ "/dev/scanner", "/dev/scanner0", "/dev/scanner1",
+ "/dev/pass0", "/dev/pass1", "/dev/pass2", "/dev/pass3",
+ "/dev/pass4", "/dev/pass5", "/dev/pass6", "/dev/pass7",
+#elif defined(__FreeBSD__)
+ "/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
+ "/dev/uk5", "/dev/uk6",
+#elif defined(__NetBSD__)
+ "/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
+ "/dev/uk5", "/dev/uk6",
+ "/dev/ss0",
+#elif defined(__OpenBSD__)
+ "/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
+ "/dev/uk5", "/dev/uk6",
+#elif defined(__hpux)
+ "/dev/rscsi/",
+#endif
+ 0
+ };
+ static char *usb_default_dev_list[] = {
+#if defined(__linux__)
+ "/dev/usb/scanner",
+ "/dev/usb/scanner0", "/dev/usb/scanner1",
+ "/dev/usb/scanner2", "/dev/usb/scanner3",
+ "/dev/usb/scanner4", "/dev/usb/scanner5",
+ "/dev/usb/scanner5", "/dev/usb/scanner7",
+ "/dev/usb/scanner8", "/dev/usb/scanner9",
+ "/dev/usb/scanner10", "/dev/usb/scanner11",
+ "/dev/usb/scanner12", "/dev/usb/scanner13",
+ "/dev/usb/scanner14", "/dev/usb/scanner15",
+ "/dev/usbscanner",
+ "/dev/usbscanner0", "/dev/usbscanner1",
+ "/dev/usbscanner2", "/dev/usbscanner3",
+ "/dev/usbscanner4", "/dev/usbscanner5",
+ "/dev/usbscanner6", "/dev/usbscanner7",
+ "/dev/usbscanner8", "/dev/usbscanner9",
+ "/dev/usbscanner10", "/dev/usbscanner11",
+ "/dev/usbscanner12", "/dev/usbscanner13",
+ "/dev/usbscanner14", "/dev/usbscanner15",
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+ "/dev/uscanner",
+ "/dev/uscanner0", "/dev/uscanner1",
+ "/dev/uscanner2", "/dev/uscanner3",
+ "/dev/uscanner4", "/dev/uscanner5",
+ "/dev/uscanner6", "/dev/uscanner7",
+ "/dev/uscanner8", "/dev/uscanner9",
+ "/dev/uscanner10", "/dev/uscanner11",
+ "/dev/uscanner12", "/dev/uscanner13",
+ "/dev/uscanner14", "/dev/uscanner15",
+#endif
+ 0
+ };
+
+#if defined (WIN32_SCSI) || \
+ defined (HAVE_IOKIT_CDB_IOSCSILIB_H) || \
+ defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
+ defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
+ /* Build a list of valid of possible scanners found */
+ dev_list = build_scsi_dev_list();
+#else
+ dev_list = default_dev_list;
+#endif
+
+ usb_dev_list = usb_default_dev_list;
+ }
+ if (verbose > 1)
+ printf ("This is sane-find-scanner from %s\n", PACKAGE_STRING);
+
+ if (verbose > 0)
+ printf ("\n # sane-find-scanner will now attempt to detect your scanner. If the"
+ "\n # result is different from what you expected, first make sure your"
+ "\n # scanner is powered up and properly connected to your computer.\n\n");
+
+ if (verbose > 1)
+ printf ("searching for SCSI scanners:\n");
+
+ while ((dev_name = *dev_list++))
+ {
+ if (strlen (dev_name) == 0)
+ continue; /* Empty device names ... */
+
+ if (dev_name[strlen (dev_name) - 1] == '/')
+ {
+ /* check whole directories */
+ DIR *dir;
+ char *file_name;
+
+ dir = scan_directory (dev_name);
+ if (!dir)
+ continue;
+
+ while ((file_name = get_next_file (dev_name, dir)))
+ check_scsi_file (file_name);
+ }
+ else
+ {
+ /* check device files */
+ check_scsi_file (dev_name);
+ }
+ }
+ if (device_found)
+ {
+ if (verbose > 0)
+ printf
+ (" # Your SCSI scanner was detected. It may or may not be "
+ "supported by SANE. Try\n # scanimage -L and read the backend's "
+ "manpage.\n");
+ }
+ else
+ {
+ if (verbose > 0)
+ printf
+ (" # No SCSI scanners found. If you expected something different, "
+ "make sure that\n # you have loaded a kernel SCSI driver for your SCSI "
+ "adapter.\n");
+ if (!check_sg ())
+ {
+ if (verbose > 0)
+ printf
+ (" # Also you need support for SCSI Generic (sg) in your "
+ "operating system.\n # If using Linux, try \"modprobe "
+ "sg\".\n");
+ }
+ }
+ if (verbose > 0)
+ printf ("\n");
+ device_found = SANE_FALSE;
+ sanei_usb_init ();
+ if (verbose > 1)
+ printf ("searching for USB scanners:\n");
+
+ while ((dev_name = *usb_dev_list++))
+ {
+ if (strlen (dev_name) == 0)
+ continue; /* Empty device names ... */
+
+ if (dev_name[strlen (dev_name) - 1] == '/')
+ {
+ /* check whole directories */
+ DIR *dir;
+ char *file_name;
+
+ dir = scan_directory (dev_name);
+ if (!dir)
+ continue;
+
+ while ((file_name = get_next_file (dev_name, dir)))
+ check_usb_file (file_name);
+ }
+ else
+ {
+ /* check device files */
+ check_usb_file (dev_name);
+ }
+ }
+#ifdef HAVE_LIBUSB
+ /* Now the libusb devices */
+ {
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ if (ap < argv + argc)
+ {
+ /* user-specified devices not useful for libusb */
+ if (verbose > 1)
+ printf ("ignoring libusb devices\n");
+ }
+ else
+ {
+ if (verbose > 2)
+ printf ("trying libusb:\n");
+ for (bus = usb_get_busses (); bus; bus = bus->next)
+ {
+ for (dev = bus->devices; dev; dev = dev->next)
+ {
+ check_libusb_device (dev, SANE_FALSE);
+ } /* for (dev) */
+ } /* for (bus) */
+ }
+ }
+#elif defined(HAVE_LIBUSB_1_0)
+ /* Now the libusb-1.0 devices */
+ {
+ if (ap < argv + argc)
+ {
+ /* user-specified devices not useful for libusb */
+ if (verbose > 1)
+ printf ("ignoring libusb devices\n");
+ }
+ else
+ {
+ libusb_device **devlist;
+ ssize_t devcnt;
+ int i;
+ int ret;
+
+ if (verbose > 2)
+ printf ("trying libusb:\n");
+
+ ret = libusb_init (&sfs_usb_ctx);
+ if (ret < 0)
+ {
+ printf ("# Could not initialize libusb-1.0, error %d\n", ret);
+ printf ("# Skipping libusb devices\n");
+
+ goto failed_libusb_1_0;
+ }
+
+ if (verbose > 3)
+ libusb_set_debug (sfs_usb_ctx, 3);
+
+ devcnt = libusb_get_device_list (sfs_usb_ctx, &devlist);
+ if (devcnt < 0)
+ {
+ printf ("# Could not get device list, error %d\n", ret);
+
+ goto deinit_libusb_1_0;
+ }
+
+ for (i = 0; i < devcnt; i++)
+ {
+ check_libusb_device (devlist[i], SANE_FALSE);
+ }
+
+ libusb_free_device_list (devlist, 1);
+
+ deinit_libusb_1_0:
+ libusb_exit (sfs_usb_ctx);
+
+ failed_libusb_1_0:
+ ; /* init failed, jumping here */
+ }
+ }
+#else /* not HAVE_LIBUSB && not HAVE_LIBUSB_1_0 */
+ if (verbose > 1)
+ printf ("libusb not available\n");
+#endif /* not HAVE_LIBUSB && not HAVE_LIBUSB_1_0 */
+
+ if (device_found)
+ {
+ if (libusb_device_found)
+ {
+ if (verbose > 0)
+ printf
+ (" # Your USB scanner was (probably) detected. It "
+ "may or may not be supported by\n # SANE. Try scanimage "
+ "-L and read the backend's manpage.\n");
+ }
+ else if (verbose > 0)
+ printf
+ (" # Your USB scanner was detected. It may or may not "
+ "be supported by\n # SANE. Try scanimage -L and read the "
+ "backend's manpage.\n");
+ if (unknown_found && verbose > 0)
+ printf
+ (" # `UNKNOWN vendor and product' means that there seems to be a "
+ "scanner at this\n # device file but the vendor and product ids "
+ "couldn't be identified.\n # Currently identification only works "
+ "with Linux versions >= 2.4.8. You may\n # need to configure your "
+ "backend manually, see the backend's manpage.\n");
+ }
+ else
+ {
+ if (verbose > 0)
+ printf
+ (" # No USB scanners found. If you expected something different, "
+ "make sure that\n # you have loaded a kernel driver for your USB host "
+ "controller and have setup\n # the USB system correctly. "
+ "See man sane-usb for details.\n");
+#if !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUSB_1_0)
+ if (verbose > 0)
+ printf (" # SANE has been built without libusb support. This may be a "
+ "reason\n # for not detecting USB scanners. Read README for "
+ "more details.\n");
+#endif
+ }
+ if (enable_pp_checks == SANE_TRUE)
+ {
+ if (!check_mustek_pp_device() && verbose > 0)
+ printf ("\n # No Mustek parallel port scanners found. If you expected"
+ " something\n # different, make sure the scanner is correctly"
+ " connected to your computer\n # and you have apropriate"
+ " access rights.\n");
+ }
+ else if (verbose > 0)
+ printf ("\n # Not checking for parallel port scanners.\n");
+ if (verbose > 0)
+ printf ("\n # Most Scanners connected to the parallel port or other "
+ "proprietary ports\n # can't be detected by this program.\n");
+#ifdef HAVE_GETUID
+ if (getuid ())
+ if (verbose > 0)
+ printf
+ ("\n # You may want to run this program as root to find all devices. "
+ "Once you\n # found the scanner devices, be sure to adjust access "
+ "permissions as\n # necessary.\n");
+#endif
+
+ if (verbose > 1)
+ printf ("done\n");
+
+ return 0;
+}