diff --git a/ChangeLog b/ChangeLog index 844c95c8b..953bdc408 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-10-03 Henning Meier-Geinitz + + * doc/sane-find-scanner.man tools/check-usb-chip.c + tools/sane-find-scanner.c: sane-find-scanner can now load USB + descriptors from /proc/bus/usb/devices dumps (e.g. from the + unsupported scanner web pages). Minor modifications to some of + the chipset tests. + 2004-10-04 Peter Kirchgessner * backend/hp.h backend/hp.c backend/hp-scl.c: diff --git a/doc/sane-find-scanner.man b/doc/sane-find-scanner.man index 830e96243..008da533f 100644 --- a/doc/sane-find-scanner.man +++ b/doc/sane-find-scanner.man @@ -1,4 +1,4 @@ -.TH sane-find-scanner 1 "18 Jul 2003" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.TH sane-find-scanner 1 "4 Oct 2004" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" .IX sane-find-scanner .SH NAME sane-find-scanner \- find SCSI and USB scanners and their device files @@ -9,6 +9,8 @@ sane-find-scanner \- find SCSI and USB scanners and their device files .RB [ \-q ] .RB [ \-p ] .RB [ \-f ] +.RB [ \-F +.IR filename ] .RI [ devname ] .SH DESCRIPTION @@ -83,6 +85,14 @@ useful if .B sane-find-scanner is wrong in determing the device type. .TP 8 +.B \-F filename +filename is a file that contains USB descriptors in the format of +/proc/bus/usb/devices as used by Linux. +.B sane-find-scanner +tries to identify the chipset(s) of all USB scanners found in such a file. This +option is useful for developers when the output of "cat /proc/bus/usb/devices" +is avaliable but the scanner itsself isn't. +.TP 8 .B devname Test device file "devname". No other devices are checked if devname is given. .SH EXAMPLE @@ -120,6 +130,5 @@ NetBSD, OpenBSD, and HP-UX. .SH BUGS No support for most parallel port scanners yet. .br -Detection of USB chipsets is limited to GrandTech 6801 and 6816, Mustek chips -and National Semiconductor lm983x chips. +Detection of USB chipsets is limited to a few chipsets. diff --git a/tools/check-usb-chip.c b/tools/check-usb-chip.c index 6ee087389..229b555a8 100644 --- a/tools/check-usb-chip.c +++ b/tools/check-usb-chip.c @@ -27,19 +27,20 @@ #include "../include/sane/config.h" +#include "../include/sane/sane.h" #include #include #include static int verbose = 0; - +static SANE_Bool no_chipset_access; #define TIMEOUT 1000 #ifdef HAVE_LIBUSB #include -extern char *check_usb_chip (struct usb_device *dev, int verbosity); +extern char *check_usb_chip (struct usb_device *dev, int verbosity, SANE_Bool from_file); static int @@ -47,6 +48,9 @@ prepare_interface (struct usb_device *dev, usb_dev_handle ** handle) { int result; + if (no_chipset_access) + return 0; + *handle = usb_open (dev); if (*handle == 0) { @@ -860,20 +864,17 @@ check_ma1509 (struct usb_device *dev) || (dev->config[0].interface[0].altsetting[0].endpoint[0]. bmAttributes != 0x02) || (dev->config[0].interface[0].altsetting[0].endpoint[0]. - wMaxPacketSize != 0x40) - || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval != - 0xff)) + wMaxPacketSize != 0x40)) { if (verbose > 2) printf (" this is not a MA-1509 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, " - "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n", + "wMaxPacketSize = 0x%x)\n", dev->config[0].interface[0].altsetting[0].endpoint[0]. bEndpointAddress, dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes, dev->config[0].interface[0].altsetting[0].endpoint[0]. - wMaxPacketSize, - dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval); + wMaxPacketSize); return 0; } if ((dev->config[0].interface[0].altsetting[0].endpoint[1]. @@ -881,20 +882,17 @@ check_ma1509 (struct usb_device *dev) || (dev->config[0].interface[0].altsetting[0].endpoint[1]. bmAttributes != 0x02) || (dev->config[0].interface[0].altsetting[0].endpoint[1]. - wMaxPacketSize != 0x08) - || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval != - 0x00)) + wMaxPacketSize != 0x08)) { if (verbose > 2) printf (" this is not a MA-1509 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, " - "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n", + "wMaxPacketSize = 0x%x)\n", dev->config[0].interface[0].altsetting[0].endpoint[1]. bEndpointAddress, dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes, dev->config[0].interface[0].altsetting[0].endpoint[1]. - wMaxPacketSize, - dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval); + wMaxPacketSize); return 0; } if ((dev->config[0].interface[0].altsetting[0].endpoint[2]. @@ -1780,8 +1778,8 @@ check_gl841 (struct usb_device *dev) bmAttributes != 0x03) || (dev->config[0].interface[0].altsetting[0].endpoint[2]. wMaxPacketSize != 0x1) - || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval != - 8)) + || ((dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval != 8) + && (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval != 16))) { if (verbose > 2) printf @@ -2009,11 +2007,12 @@ check_icm532b (struct usb_device *dev) /* ====================================== end of icm532b ==================*/ char * -check_usb_chip (struct usb_device *dev, int verbosity) +check_usb_chip (struct usb_device *dev, int verbosity, SANE_Bool from_file) { char *chip_name = 0; verbose = verbosity; + no_chipset_access = from_file; if (verbose > 2) printf ("\n\n"); diff --git a/tools/sane-find-scanner.c b/tools/sane-find-scanner.c index fdd2f19b8..9f0fd7326 100644 --- a/tools/sane-find-scanner.c +++ b/tools/sane-find-scanner.c @@ -36,15 +36,16 @@ #include #endif -#ifdef HAVE_LIBUSB -#include "usb.h" -extern char * check_usb_chip (struct usb_device *dev, int verbosity); -#endif - #include "../include/sane/sanei.h" #include "../include/sane/sanei_scsi.h" #include "../include/sane/sanei_usb.h" #include "../include/sane/sanei_pa4s2.h" +#include "../include/sane/sanei_config.h" + +#ifdef HAVE_LIBUSB +#include "usb.h" +extern char * check_usb_chip (struct usb_device *dev, int verbosity, SANE_Bool from_file); +#endif #ifndef PATH_MAX # define PATH_MAX 1024 @@ -92,6 +93,8 @@ usage (char *msg) fprintf (stderr, "\t-f: force opening devname as SCSI even if it looks " "like USB\n"); fprintf (stderr, "\t-p: enable scannig for parallel port devices\n"); + fprintf (stderr, "\t-F file: try to detect chipset from given " + "/proc/bus/usb/devices file\n"); if (msg) fprintf (stderr, "\t%s\n", msg); } @@ -433,7 +436,7 @@ get_libusb_product (struct usb_device *dev) } static void -check_libusb_device (struct usb_device *dev) +check_libusb_device (struct usb_device *dev, SANE_Bool from_file) { int is_scanner = 0; char *vendor = get_libusb_vendor (dev); @@ -610,7 +613,7 @@ check_libusb_device (struct usb_device *dev) if (is_scanner > 0) { - char * chipset = check_usb_chip (dev, verbose); + char * chipset = check_usb_chip (dev, verbose, from_file); printf ("found USB scanner (vendor=0x%04x", dev->descriptor.idVendor); if (vendor) @@ -620,7 +623,10 @@ check_libusb_device (struct usb_device *dev) printf (" [%s]", product); if (chipset) printf (", chip=%s", chipset); - printf (") at libusb:%s:%s\n", dev->bus->dirname, dev->filename); + 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; @@ -882,7 +888,205 @@ check_mustek_pp_device (void) " # man-page for setup instructions.\n"); return (found > 0 || scsi > 0); +} +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; } int @@ -924,6 +1128,10 @@ main (int argc, char **argv) enable_pp_checks = SANE_TRUE; break; + case 'F': + parse_file ((char *) (*(++ap))); + exit (0); + default: printf ("unknown option: -%c, try -h for help\n", (*ap)[1]); exit (0); @@ -1301,7 +1509,7 @@ main (int argc, char **argv) { for (dev = bus->devices; dev; dev = dev->next) { - check_libusb_device (dev); + check_libusb_device (dev, SANE_FALSE); } /* for (dev) */ } /* for (bus) */ } /* if (usb_dev_list == ap) */