1141cc406Sopenharmony_ci/* sane-find-scanner.c
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 1997-2013 Oliver Rauch, Henning Meier-Geinitz, and others.
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
6141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
7141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
8141cc406Sopenharmony_ci   License, or (at your option) any later version.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
11141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13141cc406Sopenharmony_ci   General Public License for more details.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
16141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci */
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci#include "../include/sane/config.h"
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci#include <string.h>
23141cc406Sopenharmony_ci#include <stdlib.h>
24141cc406Sopenharmony_ci#include <stdio.h>
25141cc406Sopenharmony_ci#include <unistd.h>
26141cc406Sopenharmony_ci#include <sys/types.h>
27141cc406Sopenharmony_ci#include <sys/stat.h>
28141cc406Sopenharmony_ci#include <dirent.h>
29141cc406Sopenharmony_ci#include <errno.h>
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci#if defined (HAVE_DDK_NTDDSCSI_H) || defined (HAVE_NTDDSCSI_H)
32141cc406Sopenharmony_ci# define WIN32_SCSI
33141cc406Sopenharmony_ci# include <windows.h>
34141cc406Sopenharmony_ci# if defined (HAVE_DDK_NTDDSCSI_H)
35141cc406Sopenharmony_ci#  include <ddk/scsi.h>
36141cc406Sopenharmony_ci#  include <ddk/ntddscsi.h>
37141cc406Sopenharmony_ci# elif defined (HAVE_NTDDSCSI_H)
38141cc406Sopenharmony_ci#  include <ntddscsi.h>
39141cc406Sopenharmony_ci# endif
40141cc406Sopenharmony_ci#endif
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
43141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
44141cc406Sopenharmony_ci#include "../include/sane/sanei_pa4s2.h"
45141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY
48141cc406Sopenharmony_ci#ifdef HAVE_LUSB0_USB_H
49141cc406Sopenharmony_ci#include <lusb0_usb.h>
50141cc406Sopenharmony_ci#else
51141cc406Sopenharmony_ci#include <usb.h>
52141cc406Sopenharmony_ci#endif
53141cc406Sopenharmony_ciextern char * check_usb_chip (struct usb_device *dev, int verbosity, SANE_Bool from_file);
54141cc406Sopenharmony_ci#endif
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB
57141cc406Sopenharmony_ci#include <libusb.h>
58141cc406Sopenharmony_ciextern char * check_usb_chip (int verbosity,
59141cc406Sopenharmony_ci			      struct libusb_device_descriptor desc,
60141cc406Sopenharmony_ci			      libusb_device_handle *hdl,
61141cc406Sopenharmony_ci			      struct libusb_config_descriptor *config0);
62141cc406Sopenharmony_ci#endif
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci#ifndef PATH_MAX
67141cc406Sopenharmony_ci# define PATH_MAX 1024
68141cc406Sopenharmony_ci#endif
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_cistatic const char *prog_name;
71141cc406Sopenharmony_cistatic int verbose = 1;
72141cc406Sopenharmony_cistatic SANE_Bool force = SANE_FALSE;
73141cc406Sopenharmony_cistatic SANE_Bool device_found = SANE_FALSE;
74141cc406Sopenharmony_cistatic SANE_Bool libusb_device_found = SANE_FALSE;
75141cc406Sopenharmony_cistatic SANE_Bool unknown_found = SANE_FALSE;
76141cc406Sopenharmony_ci
77141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB
78141cc406Sopenharmony_cilibusb_context *sfs_usb_ctx;
79141cc406Sopenharmony_ci#endif
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_citypedef struct
82141cc406Sopenharmony_ci{
83141cc406Sopenharmony_ci  unsigned char *cmd;
84141cc406Sopenharmony_ci  size_t size;
85141cc406Sopenharmony_ci}
86141cc406Sopenharmony_ciscsiblk;
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci#define INQUIRY					0x12
89141cc406Sopenharmony_ci#define set_inquiry_return_size(icb,val)	icb[0x04]=val
90141cc406Sopenharmony_ci#define IN_periph_devtype_cpu			0x03
91141cc406Sopenharmony_ci#define IN_periph_devtype_scanner		0x06
92141cc406Sopenharmony_ci#define get_scsi_inquiry_vendor(in, buf)	snprintf(buf, 0x08 + 1, "%.*s", \
93141cc406Sopenharmony_ci								0x08, in + 0x08)
94141cc406Sopenharmony_ci#define get_scsi_inquiry_product(in, buf)	snprintf(buf, 0x10 + 1, "%.*s", \
95141cc406Sopenharmony_ci								0x10, in + 0x10)
96141cc406Sopenharmony_ci#define get_scsi_inquiry_version(in, buf)	snprintf(buf, 0x04 + 1, "%.*s", \
97141cc406Sopenharmony_ci								0x04, in + 0x20)
98141cc406Sopenharmony_ci#define get_scsi_inquiry_periph_devtype(in)	(in[0] & 0x1f)
99141cc406Sopenharmony_ci#define get_scsi_inquiry_additional_length(in)	in[0x04]
100141cc406Sopenharmony_ci#define set_scsi_inquiry_length(out,n)		out[0x04]=n-5
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_cistatic unsigned char inquiryC[] = {
103141cc406Sopenharmony_ci  INQUIRY, 0x00, 0x00, 0x00, 0xff, 0x00
104141cc406Sopenharmony_ci};
105141cc406Sopenharmony_cistatic scsiblk inquiry = {
106141cc406Sopenharmony_ci  inquiryC, sizeof (inquiryC)
107141cc406Sopenharmony_ci};
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_cistatic void
110141cc406Sopenharmony_ciusage (char *msg)
111141cc406Sopenharmony_ci{
112141cc406Sopenharmony_ci  fprintf (stderr, "Usage: %s [-hvqf] [devname ...]\n", prog_name);
113141cc406Sopenharmony_ci  fprintf (stderr, "\t-h: print this help message\n");
114141cc406Sopenharmony_ci  fprintf (stderr, "\t-v: be more verbose (can be used multiple times)\n");
115141cc406Sopenharmony_ci  fprintf (stderr, "\t-q: be quiet (print only devices, no comments)\n");
116141cc406Sopenharmony_ci  fprintf (stderr, "\t-f: force opening devname as SCSI even if it looks "
117141cc406Sopenharmony_ci	   "like USB\n");
118141cc406Sopenharmony_ci  fprintf (stderr, "\t-p: enable scanning for parallel port devices\n");
119141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY
120141cc406Sopenharmony_ci  fprintf (stderr, "\t-F file: try to detect chipset from given "
121141cc406Sopenharmony_ci	   "/proc/bus/usb/devices file\n");
122141cc406Sopenharmony_ci#endif
123141cc406Sopenharmony_ci  if (msg)
124141cc406Sopenharmony_ci    fprintf (stderr, "\t%s\n", msg);
125141cc406Sopenharmony_ci}
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci/* if SCSI generic is optional on your OS, and there is a software test
128141cc406Sopenharmony_ci   which will determine if it is included, add it here. If you are sure
129141cc406Sopenharmony_ci   that SCSI generic was found, return 1. If SCSI generic is always
130141cc406Sopenharmony_ci   available in your OS, return 1 */
131141cc406Sopenharmony_ci
132141cc406Sopenharmony_cistatic int
133141cc406Sopenharmony_cicheck_sg (void)
134141cc406Sopenharmony_ci{
135141cc406Sopenharmony_ci#if defined(__linux__)
136141cc406Sopenharmony_ci  /* Assumption: /proc/devices lines are shorter than 256 characters */
137141cc406Sopenharmony_ci  char line[256], driver[256] = "";
138141cc406Sopenharmony_ci  FILE *stream;
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_ci  stream = fopen ("/proc/devices", "r");
141141cc406Sopenharmony_ci  /* Likely reason for failure, no /proc => probably no SG either */
142141cc406Sopenharmony_ci  if (stream == NULL)
143141cc406Sopenharmony_ci    return 0;
144141cc406Sopenharmony_ci
145141cc406Sopenharmony_ci  while (fgets (line, sizeof (line) - 1, stream))
146141cc406Sopenharmony_ci    {
147141cc406Sopenharmony_ci      if (sscanf (line, " %*d %s\n", driver) > 0 && !strcmp (driver, "sg"))
148141cc406Sopenharmony_ci	break;
149141cc406Sopenharmony_ci    }
150141cc406Sopenharmony_ci  fclose (stream);
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_ci  if (strcmp (driver, "sg"))
153141cc406Sopenharmony_ci    {
154141cc406Sopenharmony_ci      return 0;
155141cc406Sopenharmony_ci    }
156141cc406Sopenharmony_ci  else
157141cc406Sopenharmony_ci    {
158141cc406Sopenharmony_ci      return 1;
159141cc406Sopenharmony_ci    }
160141cc406Sopenharmony_ci#endif
161141cc406Sopenharmony_ci  return 1;			/* Give up, and assume yes to avoid false negatives */
162141cc406Sopenharmony_ci}
163141cc406Sopenharmony_ci
164141cc406Sopenharmony_ci/* Display a buffer in the log. Display by lines of 16 bytes. */
165141cc406Sopenharmony_cistatic void
166141cc406Sopenharmony_cihexdump (const char *comment, unsigned char *buf, const int length)
167141cc406Sopenharmony_ci{
168141cc406Sopenharmony_ci  int i;
169141cc406Sopenharmony_ci  char line[128];
170141cc406Sopenharmony_ci  char *ptr;
171141cc406Sopenharmony_ci  char asc_buf[17];
172141cc406Sopenharmony_ci  char *asc_ptr;
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci  printf ("  %s\n", comment);
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci  i = 0;
177141cc406Sopenharmony_ci  goto start;
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci  do
180141cc406Sopenharmony_ci    {
181141cc406Sopenharmony_ci      if (i < length)
182141cc406Sopenharmony_ci	{
183141cc406Sopenharmony_ci	  ptr += sprintf (ptr, " %2.2x", *buf);
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci	  if (*buf >= 32 && *buf <= 127)
186141cc406Sopenharmony_ci	    {
187141cc406Sopenharmony_ci	      asc_ptr += sprintf (asc_ptr, "%c", *buf);
188141cc406Sopenharmony_ci	    }
189141cc406Sopenharmony_ci	  else
190141cc406Sopenharmony_ci	    {
191141cc406Sopenharmony_ci	      asc_ptr += sprintf (asc_ptr, ".");
192141cc406Sopenharmony_ci	    }
193141cc406Sopenharmony_ci	}
194141cc406Sopenharmony_ci      else
195141cc406Sopenharmony_ci	{
196141cc406Sopenharmony_ci	  /* After the length; do nothing. */
197141cc406Sopenharmony_ci	  ptr += sprintf (ptr, "   ");
198141cc406Sopenharmony_ci	}
199141cc406Sopenharmony_ci
200141cc406Sopenharmony_ci      i++;
201141cc406Sopenharmony_ci      buf++;
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci      if ((i % 16) == 0)
204141cc406Sopenharmony_ci	{
205141cc406Sopenharmony_ci	  /* It's a new line */
206141cc406Sopenharmony_ci	  printf ("  %s    %s\n", line, asc_buf);
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci	start:
209141cc406Sopenharmony_ci	  ptr = line;
210141cc406Sopenharmony_ci	  *ptr = '\0';
211141cc406Sopenharmony_ci	  asc_ptr = asc_buf;
212141cc406Sopenharmony_ci	  *asc_ptr = '\0';
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci	  ptr += sprintf (ptr, "  %3.3d:", i);
215141cc406Sopenharmony_ci	}
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci    }
218141cc406Sopenharmony_ci  while (i < ((length + 15) & ~15));
219141cc406Sopenharmony_ci}
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_cistatic SANE_Status
222141cc406Sopenharmony_ciscanner_do_scsi_inquiry (unsigned char *buffer, int sfd)
223141cc406Sopenharmony_ci{
224141cc406Sopenharmony_ci  size_t size;
225141cc406Sopenharmony_ci  SANE_Status status;
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci  memset (buffer, '\0', 256);	/* clear buffer */
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_ci  size = 5;			/* first get only 5 bytes to get size of
230141cc406Sopenharmony_ci				   inquiry_return_block */
231141cc406Sopenharmony_ci  set_inquiry_return_size (inquiry.cmd, size);
232141cc406Sopenharmony_ci  status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
235141cc406Sopenharmony_ci    return (status);
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci  size = get_scsi_inquiry_additional_length (buffer) + 5;
238141cc406Sopenharmony_ci
239141cc406Sopenharmony_ci  /* then get inquiry with actual size */
240141cc406Sopenharmony_ci  set_inquiry_return_size (inquiry.cmd, size);
241141cc406Sopenharmony_ci  status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_ci  return (status);
244141cc406Sopenharmony_ci}
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_cistatic void
247141cc406Sopenharmony_ciscanner_identify_scsi_scanner (unsigned char *buffer, int sfd,
248141cc406Sopenharmony_ci			       char *devicename)
249141cc406Sopenharmony_ci{
250141cc406Sopenharmony_ci  unsigned char vendor[9];
251141cc406Sopenharmony_ci  unsigned char product[17];
252141cc406Sopenharmony_ci  unsigned char version[5];
253141cc406Sopenharmony_ci  unsigned char *pp;
254141cc406Sopenharmony_ci  unsigned int devtype;
255141cc406Sopenharmony_ci  SANE_Status status;
256141cc406Sopenharmony_ci  static char *devtypes[] = {
257141cc406Sopenharmony_ci    "disk", "tape", "printer", "processor", "CD-writer",
258141cc406Sopenharmony_ci    "CD-drive", "scanner", "optical-drive", "jukebox",
259141cc406Sopenharmony_ci    "communicator"
260141cc406Sopenharmony_ci  };
261141cc406Sopenharmony_ci  status = scanner_do_scsi_inquiry (buffer, sfd);
262141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
263141cc406Sopenharmony_ci    {
264141cc406Sopenharmony_ci      if (verbose > 1)
265141cc406Sopenharmony_ci	printf ("inquiry for device %s failed (%s)\n",
266141cc406Sopenharmony_ci		devicename, sane_strstatus (status));
267141cc406Sopenharmony_ci      return;
268141cc406Sopenharmony_ci    }
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ci  if (verbose > 2)
271141cc406Sopenharmony_ci    hexdump ("Inquiry for device:", buffer,
272141cc406Sopenharmony_ci	     get_scsi_inquiry_additional_length (buffer) + 5);
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci  devtype = get_scsi_inquiry_periph_devtype (buffer);
275141cc406Sopenharmony_ci  if (verbose <= 1 && devtype != IN_periph_devtype_scanner
276141cc406Sopenharmony_ci      /* old HP scanners use the CPU id ... */
277141cc406Sopenharmony_ci      && devtype != IN_periph_devtype_cpu)
278141cc406Sopenharmony_ci    return;			/* no, continue searching */
279141cc406Sopenharmony_ci
280141cc406Sopenharmony_ci  get_scsi_inquiry_vendor ((char *) buffer, (char *) vendor);
281141cc406Sopenharmony_ci  get_scsi_inquiry_product ((char *) buffer, (char *) product);
282141cc406Sopenharmony_ci  get_scsi_inquiry_version ((char *) buffer, (char *) version);
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci  pp = &vendor[7];
285141cc406Sopenharmony_ci  vendor[8] = '\0';
286141cc406Sopenharmony_ci  while (pp >= vendor && (*pp == ' ' || *pp >= 127))
287141cc406Sopenharmony_ci    *pp-- = '\0';
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci  pp = &product[15];
290141cc406Sopenharmony_ci  product[16] = '\0';
291141cc406Sopenharmony_ci  while (pp >= product && (*pp == ' ' || *pp >= 127))
292141cc406Sopenharmony_ci    *pp-- = '\0';
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci  pp = &version[3];
295141cc406Sopenharmony_ci  version[4] = '\0';
296141cc406Sopenharmony_ci  while (pp >= version && (*pp == ' ' || *(pp - 1) >= 127))
297141cc406Sopenharmony_ci    *pp-- = '\0';
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci  device_found = SANE_TRUE;
300141cc406Sopenharmony_ci  printf ("found SCSI %s \"%s %s %s\" at %s\n",
301141cc406Sopenharmony_ci	  devtype < NELEMS (devtypes) ? devtypes[devtype] : "unknown device",
302141cc406Sopenharmony_ci	  vendor, product, version, devicename);
303141cc406Sopenharmony_ci  return;
304141cc406Sopenharmony_ci}
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_cistatic void
307141cc406Sopenharmony_cicheck_scsi_file (char *file_name)
308141cc406Sopenharmony_ci{
309141cc406Sopenharmony_ci  int result;
310141cc406Sopenharmony_ci  int sfd;
311141cc406Sopenharmony_ci  unsigned char buffer[16384];
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci  if (strstr (file_name, "usb")
314141cc406Sopenharmony_ci      || strstr (file_name, "uscanner") || strstr (file_name, "ugen"))
315141cc406Sopenharmony_ci    {
316141cc406Sopenharmony_ci      if (force)
317141cc406Sopenharmony_ci	{
318141cc406Sopenharmony_ci	  if (verbose > 1)
319141cc406Sopenharmony_ci	    printf ("checking %s even though it looks like a USB device...",
320141cc406Sopenharmony_ci		    file_name);
321141cc406Sopenharmony_ci	}
322141cc406Sopenharmony_ci      else
323141cc406Sopenharmony_ci	{
324141cc406Sopenharmony_ci	  if (verbose > 1)
325141cc406Sopenharmony_ci	    printf ("ignored %s (not a SCSI device)\n", file_name);
326141cc406Sopenharmony_ci	  return;
327141cc406Sopenharmony_ci	}
328141cc406Sopenharmony_ci    }
329141cc406Sopenharmony_ci  else if (verbose > 1)
330141cc406Sopenharmony_ci    printf ("checking %s...", file_name);
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci  result = sanei_scsi_open (file_name, &sfd, NULL, NULL);
333141cc406Sopenharmony_ci
334141cc406Sopenharmony_ci  if (verbose > 1)
335141cc406Sopenharmony_ci    {
336141cc406Sopenharmony_ci      if (result != 0)
337141cc406Sopenharmony_ci	printf (" failed to open (%s)\n", sane_strstatus (result));
338141cc406Sopenharmony_ci      else
339141cc406Sopenharmony_ci	printf (" open ok\n");
340141cc406Sopenharmony_ci    }
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci  if (result == SANE_STATUS_GOOD)
343141cc406Sopenharmony_ci    {
344141cc406Sopenharmony_ci      scanner_identify_scsi_scanner (buffer, sfd, file_name);
345141cc406Sopenharmony_ci      sanei_scsi_close (sfd);
346141cc406Sopenharmony_ci    }
347141cc406Sopenharmony_ci  return;
348141cc406Sopenharmony_ci}
349141cc406Sopenharmony_ci
350141cc406Sopenharmony_cistatic void
351141cc406Sopenharmony_cicheck_usb_file (char *file_name)
352141cc406Sopenharmony_ci{
353141cc406Sopenharmony_ci  SANE_Status result;
354141cc406Sopenharmony_ci  SANE_Word vendor, product;
355141cc406Sopenharmony_ci  SANE_Int fd;
356141cc406Sopenharmony_ci
357141cc406Sopenharmony_ci  if (!strstr (file_name, "usb")
358141cc406Sopenharmony_ci      && !strstr (file_name, "uscanner") && !strstr (file_name, "ugen"))
359141cc406Sopenharmony_ci    {
360141cc406Sopenharmony_ci      if (force)
361141cc406Sopenharmony_ci	{
362141cc406Sopenharmony_ci	  if (verbose > 1)
363141cc406Sopenharmony_ci	    printf ("checking %s even though doesn't look like a "
364141cc406Sopenharmony_ci		    "USB device...", file_name);
365141cc406Sopenharmony_ci	}
366141cc406Sopenharmony_ci      else
367141cc406Sopenharmony_ci	{
368141cc406Sopenharmony_ci	  if (verbose > 1)
369141cc406Sopenharmony_ci	    printf ("ignored %s (not a USB device)\n", file_name);
370141cc406Sopenharmony_ci	  return;
371141cc406Sopenharmony_ci	}
372141cc406Sopenharmony_ci    }
373141cc406Sopenharmony_ci  else if (verbose > 1)
374141cc406Sopenharmony_ci    printf ("checking %s...", file_name);
375141cc406Sopenharmony_ci
376141cc406Sopenharmony_ci  result = sanei_usb_open (file_name, &fd);
377141cc406Sopenharmony_ci
378141cc406Sopenharmony_ci  if (result != SANE_STATUS_GOOD)
379141cc406Sopenharmony_ci    {
380141cc406Sopenharmony_ci      if (verbose > 1)
381141cc406Sopenharmony_ci	printf (" failed to open (%s)\n", sane_strstatus (result));
382141cc406Sopenharmony_ci    }
383141cc406Sopenharmony_ci  else
384141cc406Sopenharmony_ci    {
385141cc406Sopenharmony_ci      result = sanei_usb_get_vendor_product (fd, &vendor, &product);
386141cc406Sopenharmony_ci      if (result == SANE_STATUS_GOOD)
387141cc406Sopenharmony_ci	{
388141cc406Sopenharmony_ci	  if (verbose > 1)
389141cc406Sopenharmony_ci	    printf (" open ok, vendor and product ids were identified\n");
390141cc406Sopenharmony_ci	  printf ("found possible USB scanner (vendor=0x%04x, "
391141cc406Sopenharmony_ci		  "product=0x%04x) at %s\n", vendor, product, file_name);
392141cc406Sopenharmony_ci	}
393141cc406Sopenharmony_ci      else
394141cc406Sopenharmony_ci	{
395141cc406Sopenharmony_ci	  if (verbose > 1)
396141cc406Sopenharmony_ci	    printf (" open ok, but vendor and product could NOT be "
397141cc406Sopenharmony_ci		    "identified\n");
398141cc406Sopenharmony_ci	  printf ("found possible USB scanner (UNKNOWN vendor and "
399141cc406Sopenharmony_ci		  "product) at %s\n", file_name);
400141cc406Sopenharmony_ci	  unknown_found = SANE_TRUE;
401141cc406Sopenharmony_ci	}
402141cc406Sopenharmony_ci      device_found = SANE_TRUE;
403141cc406Sopenharmony_ci      sanei_usb_close (fd);
404141cc406Sopenharmony_ci    }
405141cc406Sopenharmony_ci}
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_cistatic char *
410141cc406Sopenharmony_ciget_libusb_string_descriptor (struct usb_device *dev, int index)
411141cc406Sopenharmony_ci{
412141cc406Sopenharmony_ci  usb_dev_handle *handle;
413141cc406Sopenharmony_ci  char *buffer, short_buffer[2];
414141cc406Sopenharmony_ci  struct usb_string_descriptor *sd;
415141cc406Sopenharmony_ci  int size = 2;
416141cc406Sopenharmony_ci  int i;
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_ci  if (!index)
419141cc406Sopenharmony_ci    return 0;
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci  handle = usb_open (dev);
422141cc406Sopenharmony_ci  if (!handle)
423141cc406Sopenharmony_ci    return 0;
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci  sd = (struct usb_string_descriptor *) short_buffer;
426141cc406Sopenharmony_ci
427141cc406Sopenharmony_ci  if (usb_control_msg (handle,
428141cc406Sopenharmony_ci		       USB_ENDPOINT_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE,
429141cc406Sopenharmony_ci		       USB_REQ_GET_DESCRIPTOR,
430141cc406Sopenharmony_ci		       (USB_DT_STRING << 8) + index, 0, short_buffer,
431141cc406Sopenharmony_ci		       size, 1000) < 0)
432141cc406Sopenharmony_ci    {
433141cc406Sopenharmony_ci      usb_close (handle);
434141cc406Sopenharmony_ci      return 0;
435141cc406Sopenharmony_ci    }
436141cc406Sopenharmony_ci
437141cc406Sopenharmony_ci  if (sd->bLength < 2
438141cc406Sopenharmony_ci      || sd->bDescriptorType != USB_DT_STRING)
439141cc406Sopenharmony_ci    {
440141cc406Sopenharmony_ci      usb_close (handle);
441141cc406Sopenharmony_ci      return 0;
442141cc406Sopenharmony_ci    }
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ci  size = sd->bLength;
445141cc406Sopenharmony_ci
446141cc406Sopenharmony_ci  buffer = calloc (1, size + 1);
447141cc406Sopenharmony_ci  if (!buffer)
448141cc406Sopenharmony_ci    return 0;
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci  sd = (struct usb_string_descriptor *) buffer;
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci  if (usb_control_msg (handle,
453141cc406Sopenharmony_ci		       USB_ENDPOINT_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE,
454141cc406Sopenharmony_ci		       USB_REQ_GET_DESCRIPTOR,
455141cc406Sopenharmony_ci		       (USB_DT_STRING << 8) + index, 0, buffer,
456141cc406Sopenharmony_ci		       size, 1000) < 0)
457141cc406Sopenharmony_ci    {
458141cc406Sopenharmony_ci      usb_close (handle);
459141cc406Sopenharmony_ci      free (buffer);
460141cc406Sopenharmony_ci      return 0;
461141cc406Sopenharmony_ci    }
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_ci  if (sd->bLength < 2 || sd->bLength > size
464141cc406Sopenharmony_ci      || sd->bDescriptorType != USB_DT_STRING)
465141cc406Sopenharmony_ci    {
466141cc406Sopenharmony_ci      usb_close (handle);
467141cc406Sopenharmony_ci      free (buffer);
468141cc406Sopenharmony_ci      return 0;
469141cc406Sopenharmony_ci    }
470141cc406Sopenharmony_ci  size = sd->bLength - 2;
471141cc406Sopenharmony_ci  for (i = 0; i < (size / 2); i++)
472141cc406Sopenharmony_ci    buffer[i] = buffer[2 + 2 * i];
473141cc406Sopenharmony_ci  buffer[i] = 0;
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_ci  usb_close (handle);
476141cc406Sopenharmony_ci  return buffer;
477141cc406Sopenharmony_ci}
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_cistatic char *
480141cc406Sopenharmony_ciget_libusb_vendor (struct usb_device *dev)
481141cc406Sopenharmony_ci{
482141cc406Sopenharmony_ci  return get_libusb_string_descriptor (dev, dev->descriptor.iManufacturer);
483141cc406Sopenharmony_ci}
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_cistatic char *
486141cc406Sopenharmony_ciget_libusb_product (struct usb_device *dev)
487141cc406Sopenharmony_ci{
488141cc406Sopenharmony_ci  return get_libusb_string_descriptor (dev, dev->descriptor.iProduct);
489141cc406Sopenharmony_ci}
490141cc406Sopenharmony_ci
491141cc406Sopenharmony_cistatic void
492141cc406Sopenharmony_cicheck_libusb_device (struct usb_device *dev, SANE_Bool from_file)
493141cc406Sopenharmony_ci{
494141cc406Sopenharmony_ci  int is_scanner = 0;
495141cc406Sopenharmony_ci  char *vendor;
496141cc406Sopenharmony_ci  char *product;
497141cc406Sopenharmony_ci  int interface_nr;
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci  if (!dev->config)
500141cc406Sopenharmony_ci    {
501141cc406Sopenharmony_ci      if (verbose > 1)
502141cc406Sopenharmony_ci	printf ("device 0x%04x/0x%04x is not configured\n",
503141cc406Sopenharmony_ci		dev->descriptor.idVendor, dev->descriptor.idProduct);
504141cc406Sopenharmony_ci      return;
505141cc406Sopenharmony_ci    }
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci  vendor = get_libusb_vendor (dev);
508141cc406Sopenharmony_ci  product = get_libusb_product (dev);
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci  if (verbose > 2)
511141cc406Sopenharmony_ci    {
512141cc406Sopenharmony_ci      /* print everything we know about the device */
513141cc406Sopenharmony_ci      char *buf;
514141cc406Sopenharmony_ci      int config_nr;
515141cc406Sopenharmony_ci      struct usb_device_descriptor *d = &dev->descriptor;
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci      printf ("\n");
518141cc406Sopenharmony_ci      printf ("<device descriptor of 0x%04x/0x%04x at %s:%s",
519141cc406Sopenharmony_ci	      d->idVendor, d->idProduct, dev->bus->dirname, dev->filename);
520141cc406Sopenharmony_ci      if (vendor || product)
521141cc406Sopenharmony_ci	{
522141cc406Sopenharmony_ci	  printf (" (%s%s%s)", vendor ? vendor : "",
523141cc406Sopenharmony_ci		  (vendor && product) ? " " : "", product ? product : "");
524141cc406Sopenharmony_ci	}
525141cc406Sopenharmony_ci      printf (">\n");
526141cc406Sopenharmony_ci      printf ("bLength               %d\n", d->bLength);
527141cc406Sopenharmony_ci      printf ("bDescriptorType       %d\n", d->bDescriptorType);
528141cc406Sopenharmony_ci      printf ("bcdUSB                %d.%d%d\n", d->bcdUSB >> 8,
529141cc406Sopenharmony_ci	      (d->bcdUSB >> 4) & 15, d->bcdUSB & 15);
530141cc406Sopenharmony_ci      printf ("bDeviceClass          %d\n", d->bDeviceClass);
531141cc406Sopenharmony_ci      printf ("bDeviceSubClass       %d\n", d->bDeviceSubClass);
532141cc406Sopenharmony_ci      printf ("bDeviceProtocol       %d\n", d->bDeviceProtocol);
533141cc406Sopenharmony_ci      printf ("bMaxPacketSize0       %d\n", d->bMaxPacketSize0);
534141cc406Sopenharmony_ci      printf ("idVendor              0x%04X\n", d->idVendor);
535141cc406Sopenharmony_ci      printf ("idProduct             0x%04X\n", d->idProduct);
536141cc406Sopenharmony_ci      printf ("bcdDevice             %d.%d%d\n", d->bcdDevice >> 8,
537141cc406Sopenharmony_ci	      (d->bcdDevice >> 4) & 15, d->bcdDevice & 15);
538141cc406Sopenharmony_ci      printf ("iManufacturer         %d (%s)\n", d->iManufacturer,
539141cc406Sopenharmony_ci	      (vendor) ? vendor : "");
540141cc406Sopenharmony_ci      printf ("iProduct              %d (%s)\n", d->iProduct,
541141cc406Sopenharmony_ci	      (product) ? product : "");
542141cc406Sopenharmony_ci
543141cc406Sopenharmony_ci      buf = get_libusb_string_descriptor (dev, d->iSerialNumber);
544141cc406Sopenharmony_ci      printf ("iSerialNumber         %d (%s)\n", d->iSerialNumber,
545141cc406Sopenharmony_ci	      (buf) ? buf : "");
546141cc406Sopenharmony_ci      if (buf)
547141cc406Sopenharmony_ci	free (buf);
548141cc406Sopenharmony_ci      printf ("bNumConfigurations    %d\n", d->bNumConfigurations);
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci      for (config_nr = 0; config_nr < d->bNumConfigurations; config_nr++)
551141cc406Sopenharmony_ci	{
552141cc406Sopenharmony_ci	  struct usb_config_descriptor *c = &dev->config[config_nr];
553141cc406Sopenharmony_ci	  int interface_nr;
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci	  printf (" <configuration %d>\n", config_nr);
556141cc406Sopenharmony_ci	  printf (" bLength              %d\n", c->bLength);
557141cc406Sopenharmony_ci	  printf (" bDescriptorType      %d\n", c->bDescriptorType);
558141cc406Sopenharmony_ci	  printf (" wTotalLength         %d\n", c->wTotalLength);
559141cc406Sopenharmony_ci	  printf (" bNumInterfaces       %d\n", c->bNumInterfaces);
560141cc406Sopenharmony_ci	  printf (" bConfigurationValue  %d\n", c->bConfigurationValue);
561141cc406Sopenharmony_ci	  buf = get_libusb_string_descriptor (dev, c->iConfiguration);
562141cc406Sopenharmony_ci	  printf (" iConfiguration       %d (%s)\n", c->iConfiguration,
563141cc406Sopenharmony_ci		  (buf) ? buf : "");
564141cc406Sopenharmony_ci	  if (buf)
565141cc406Sopenharmony_ci	    free (buf);
566141cc406Sopenharmony_ci	  printf (" bmAttributes         %d (%s%s)\n", c->bmAttributes,
567141cc406Sopenharmony_ci		  c->bmAttributes & 64 ? "Self-powered" : "",
568141cc406Sopenharmony_ci		  c->bmAttributes & 32 ? "Remote Wakeup" : "");
569141cc406Sopenharmony_ci	  printf (" MaxPower             %d mA\n", c->MaxPower * 2);
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci	  for (interface_nr = 0; interface_nr < c->bNumInterfaces;
572141cc406Sopenharmony_ci	       interface_nr++)
573141cc406Sopenharmony_ci	    {
574141cc406Sopenharmony_ci	      struct usb_interface *interface = &c->interface[interface_nr];
575141cc406Sopenharmony_ci	      int alt_setting_nr;
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_ci	      printf ("  <interface %d>\n", interface_nr);
578141cc406Sopenharmony_ci	      for (alt_setting_nr = 0;
579141cc406Sopenharmony_ci		   alt_setting_nr < interface->num_altsetting;
580141cc406Sopenharmony_ci		   alt_setting_nr++)
581141cc406Sopenharmony_ci		{
582141cc406Sopenharmony_ci		  struct usb_interface_descriptor *i
583141cc406Sopenharmony_ci		    = &interface->altsetting[alt_setting_nr];
584141cc406Sopenharmony_ci		  int ep_nr;
585141cc406Sopenharmony_ci		  printf ("   <altsetting %d>\n", alt_setting_nr);
586141cc406Sopenharmony_ci		  printf ("   bLength            %d\n", i->bLength);
587141cc406Sopenharmony_ci		  printf ("   bDescriptorType    %d\n", i->bDescriptorType);
588141cc406Sopenharmony_ci		  printf ("   bInterfaceNumber   %d\n", i->bInterfaceNumber);
589141cc406Sopenharmony_ci		  printf ("   bAlternateSetting  %d\n", i->bAlternateSetting);
590141cc406Sopenharmony_ci		  printf ("   bNumEndpoints      %d\n", i->bNumEndpoints);
591141cc406Sopenharmony_ci		  printf ("   bInterfaceClass    %d\n", i->bInterfaceClass);
592141cc406Sopenharmony_ci		  printf ("   bInterfaceSubClass %d\n",
593141cc406Sopenharmony_ci			  i->bInterfaceSubClass);
594141cc406Sopenharmony_ci		  printf ("   bInterfaceProtocol %d\n",
595141cc406Sopenharmony_ci			  i->bInterfaceProtocol);
596141cc406Sopenharmony_ci		  buf = get_libusb_string_descriptor (dev, i->iInterface);
597141cc406Sopenharmony_ci		  printf ("   iInterface         %d (%s)\n", i->iInterface,
598141cc406Sopenharmony_ci			  (buf) ? buf : "");
599141cc406Sopenharmony_ci		  if (buf)
600141cc406Sopenharmony_ci		    free (buf);
601141cc406Sopenharmony_ci
602141cc406Sopenharmony_ci		  for (ep_nr = 0; ep_nr < i->bNumEndpoints; ep_nr++)
603141cc406Sopenharmony_ci		    {
604141cc406Sopenharmony_ci		      struct usb_endpoint_descriptor *e = &i->endpoint[ep_nr];
605141cc406Sopenharmony_ci		      char *ep_type;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci		      switch (e->bmAttributes & USB_ENDPOINT_TYPE_MASK)
608141cc406Sopenharmony_ci			{
609141cc406Sopenharmony_ci			case USB_ENDPOINT_TYPE_CONTROL:
610141cc406Sopenharmony_ci			  ep_type = "control";
611141cc406Sopenharmony_ci			  break;
612141cc406Sopenharmony_ci			case USB_ENDPOINT_TYPE_ISOCHRONOUS:
613141cc406Sopenharmony_ci			  ep_type = "isochronous";
614141cc406Sopenharmony_ci			  break;
615141cc406Sopenharmony_ci			case USB_ENDPOINT_TYPE_BULK:
616141cc406Sopenharmony_ci			  ep_type = "bulk";
617141cc406Sopenharmony_ci			  break;
618141cc406Sopenharmony_ci			case USB_ENDPOINT_TYPE_INTERRUPT:
619141cc406Sopenharmony_ci			  ep_type = "interrupt";
620141cc406Sopenharmony_ci			  break;
621141cc406Sopenharmony_ci			default:
622141cc406Sopenharmony_ci			  ep_type = "unknown";
623141cc406Sopenharmony_ci			  break;
624141cc406Sopenharmony_ci			}
625141cc406Sopenharmony_ci		      printf ("    <endpoint %d>\n", ep_nr);
626141cc406Sopenharmony_ci		      printf ("    bLength           %d\n", e->bLength);
627141cc406Sopenharmony_ci		      printf ("    bDescriptorType   %d\n",
628141cc406Sopenharmony_ci			      e->bDescriptorType);
629141cc406Sopenharmony_ci		      printf ("    bEndpointAddress  0x%02X (%s 0x%02X)\n",
630141cc406Sopenharmony_ci			      e->bEndpointAddress,
631141cc406Sopenharmony_ci			      e->bEndpointAddress & USB_ENDPOINT_DIR_MASK ?
632141cc406Sopenharmony_ci			      "in" : "out",
633141cc406Sopenharmony_ci			      e->
634141cc406Sopenharmony_ci			      bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
635141cc406Sopenharmony_ci		      printf ("    bmAttributes      %d (%s)\n",
636141cc406Sopenharmony_ci			      e->bmAttributes, ep_type);
637141cc406Sopenharmony_ci		      printf ("    wMaxPacketSize    %d\n",
638141cc406Sopenharmony_ci			      e->wMaxPacketSize);
639141cc406Sopenharmony_ci		      printf ("    bInterval         %d ms\n", e->bInterval);
640141cc406Sopenharmony_ci		      printf ("    bRefresh          %d\n", e->bRefresh);
641141cc406Sopenharmony_ci		      printf ("    bSynchAddress     %d\n", e->bSynchAddress);
642141cc406Sopenharmony_ci		    }
643141cc406Sopenharmony_ci		}
644141cc406Sopenharmony_ci	    }
645141cc406Sopenharmony_ci	}
646141cc406Sopenharmony_ci
647141cc406Sopenharmony_ci    }
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci  /* Some heuristics, which device may be a scanner */
650141cc406Sopenharmony_ci  if (dev->descriptor.idVendor == 0)	/* hub */
651141cc406Sopenharmony_ci    --is_scanner;
652141cc406Sopenharmony_ci  if (dev->descriptor.idProduct == 0)	/* hub */
653141cc406Sopenharmony_ci    --is_scanner;
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci  for (interface_nr = 0; interface_nr < dev->config[0].bNumInterfaces && is_scanner <= 0; interface_nr++)
656141cc406Sopenharmony_ci    {
657141cc406Sopenharmony_ci      switch (dev->descriptor.bDeviceClass)
658141cc406Sopenharmony_ci	{
659141cc406Sopenharmony_ci	case USB_CLASS_VENDOR_SPEC:
660141cc406Sopenharmony_ci	  ++is_scanner;
661141cc406Sopenharmony_ci	  break;
662141cc406Sopenharmony_ci	case USB_CLASS_PER_INTERFACE:
663141cc406Sopenharmony_ci	  if (dev->config[0].interface[interface_nr].num_altsetting == 0 ||
664141cc406Sopenharmony_ci	      !dev->config[0].interface[interface_nr].altsetting)
665141cc406Sopenharmony_ci	    break;
666141cc406Sopenharmony_ci	  switch (dev->config[0].interface[interface_nr].altsetting[0].bInterfaceClass)
667141cc406Sopenharmony_ci	    {
668141cc406Sopenharmony_ci	    case USB_CLASS_VENDOR_SPEC:
669141cc406Sopenharmony_ci	    case USB_CLASS_PER_INTERFACE:
670141cc406Sopenharmony_ci	    case 16:                /* data? */
671141cc406Sopenharmony_ci	      ++is_scanner;
672141cc406Sopenharmony_ci	      break;
673141cc406Sopenharmony_ci	    }
674141cc406Sopenharmony_ci	  break;
675141cc406Sopenharmony_ci	}
676141cc406Sopenharmony_ci    }
677141cc406Sopenharmony_ci
678141cc406Sopenharmony_ci  if (is_scanner > 0)
679141cc406Sopenharmony_ci    {
680141cc406Sopenharmony_ci      char * chipset = check_usb_chip (dev, verbose, from_file);
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci      printf ("found possible USB scanner (vendor=0x%04x",
683141cc406Sopenharmony_ci	      dev->descriptor.idVendor);
684141cc406Sopenharmony_ci      if (vendor)
685141cc406Sopenharmony_ci	printf (" [%s]", vendor);
686141cc406Sopenharmony_ci      printf (", product=0x%04x", dev->descriptor.idProduct);
687141cc406Sopenharmony_ci      if (product)
688141cc406Sopenharmony_ci	printf (" [%s]", product);
689141cc406Sopenharmony_ci      if (chipset)
690141cc406Sopenharmony_ci	printf (", chip=%s", chipset);
691141cc406Sopenharmony_ci      if (from_file)
692141cc406Sopenharmony_ci	printf (")\n");
693141cc406Sopenharmony_ci      else
694141cc406Sopenharmony_ci	printf (") at libusb:%s:%s\n", dev->bus->dirname, dev->filename);
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci      libusb_device_found = SANE_TRUE;
697141cc406Sopenharmony_ci      device_found = SANE_TRUE;
698141cc406Sopenharmony_ci    }
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci  if (vendor)
701141cc406Sopenharmony_ci    free (vendor);
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci  if (product)
704141cc406Sopenharmony_ci    free (product);
705141cc406Sopenharmony_ci}
706141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY */
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci
709141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB
710141cc406Sopenharmony_cistatic char *
711141cc406Sopenharmony_cisfs_libusb_strerror (int errcode)
712141cc406Sopenharmony_ci{
713141cc406Sopenharmony_ci  /* Error codes & descriptions from the libusb-1.0 documentation */
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  switch (errcode)
716141cc406Sopenharmony_ci    {
717141cc406Sopenharmony_ci      case LIBUSB_SUCCESS:
718141cc406Sopenharmony_ci	return "Success (no error)";
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci      case LIBUSB_ERROR_IO:
721141cc406Sopenharmony_ci	return "Input/output error";
722141cc406Sopenharmony_ci
723141cc406Sopenharmony_ci      case LIBUSB_ERROR_INVALID_PARAM:
724141cc406Sopenharmony_ci	return "Invalid parameter";
725141cc406Sopenharmony_ci
726141cc406Sopenharmony_ci      case LIBUSB_ERROR_ACCESS:
727141cc406Sopenharmony_ci	return "Access denied (insufficient permissions)";
728141cc406Sopenharmony_ci
729141cc406Sopenharmony_ci      case LIBUSB_ERROR_NO_DEVICE:
730141cc406Sopenharmony_ci	return "No such device (it may have been disconnected)";
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci      case LIBUSB_ERROR_NOT_FOUND:
733141cc406Sopenharmony_ci	return "Entity not found";
734141cc406Sopenharmony_ci
735141cc406Sopenharmony_ci      case LIBUSB_ERROR_BUSY:
736141cc406Sopenharmony_ci	return "Resource busy";
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci      case LIBUSB_ERROR_TIMEOUT:
739141cc406Sopenharmony_ci	return "Operation timed out";
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci      case LIBUSB_ERROR_OVERFLOW:
742141cc406Sopenharmony_ci	return "Overflow";
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci      case LIBUSB_ERROR_PIPE:
745141cc406Sopenharmony_ci	return "Pipe error";
746141cc406Sopenharmony_ci
747141cc406Sopenharmony_ci      case LIBUSB_ERROR_INTERRUPTED:
748141cc406Sopenharmony_ci	return "System call interrupted (perhaps due to signal)";
749141cc406Sopenharmony_ci
750141cc406Sopenharmony_ci      case LIBUSB_ERROR_NO_MEM:
751141cc406Sopenharmony_ci	return "Insufficient memory";
752141cc406Sopenharmony_ci
753141cc406Sopenharmony_ci      case LIBUSB_ERROR_NOT_SUPPORTED:
754141cc406Sopenharmony_ci	return "Operation not supported or unimplemented on this platform";
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci      case LIBUSB_ERROR_OTHER:
757141cc406Sopenharmony_ci	return "Other error";
758141cc406Sopenharmony_ci
759141cc406Sopenharmony_ci      default:
760141cc406Sopenharmony_ci	return "Unknown libusb-1.0 error code";
761141cc406Sopenharmony_ci    }
762141cc406Sopenharmony_ci}
763141cc406Sopenharmony_ci
764141cc406Sopenharmony_cistatic char *
765141cc406Sopenharmony_ciget_libusb_string_descriptor (libusb_device_handle *hdl, int index)
766141cc406Sopenharmony_ci{
767141cc406Sopenharmony_ci  unsigned char *buffer, short_buffer[2];
768141cc406Sopenharmony_ci  int size;
769141cc406Sopenharmony_ci  int ret;
770141cc406Sopenharmony_ci  int i;
771141cc406Sopenharmony_ci
772141cc406Sopenharmony_ci  if (!index)
773141cc406Sopenharmony_ci    return NULL;
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci  ret = libusb_get_descriptor (hdl, LIBUSB_DT_STRING, index,
776141cc406Sopenharmony_ci			       short_buffer, sizeof (short_buffer));
777141cc406Sopenharmony_ci  if (ret < 0)
778141cc406Sopenharmony_ci    {
779141cc406Sopenharmony_ci      printf ("could not fetch string descriptor: %s\n",
780141cc406Sopenharmony_ci	      sfs_libusb_strerror (ret));
781141cc406Sopenharmony_ci      return NULL;
782141cc406Sopenharmony_ci    }
783141cc406Sopenharmony_ci
784141cc406Sopenharmony_ci  if ((short_buffer[0] < 2) /* descriptor length */
785141cc406Sopenharmony_ci      || (short_buffer[1] != LIBUSB_DT_STRING)) /* descriptor type */
786141cc406Sopenharmony_ci    return NULL;
787141cc406Sopenharmony_ci
788141cc406Sopenharmony_ci  size = short_buffer[0];
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci  buffer = calloc (1, size + 1);
791141cc406Sopenharmony_ci  if (!buffer)
792141cc406Sopenharmony_ci    return NULL;
793141cc406Sopenharmony_ci
794141cc406Sopenharmony_ci  ret = libusb_get_descriptor (hdl, LIBUSB_DT_STRING, index,
795141cc406Sopenharmony_ci			       buffer, size);
796141cc406Sopenharmony_ci  if (ret < 0)
797141cc406Sopenharmony_ci    {
798141cc406Sopenharmony_ci      printf ("could not fetch string descriptor (again): %s\n",
799141cc406Sopenharmony_ci	      sfs_libusb_strerror (ret));
800141cc406Sopenharmony_ci      free (buffer);
801141cc406Sopenharmony_ci      return NULL;
802141cc406Sopenharmony_ci    }
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ci  if ((buffer[0] < 2) || (buffer[0] > size) /* descriptor length */
805141cc406Sopenharmony_ci      || (buffer[1] != LIBUSB_DT_STRING)) /* descriptor type */
806141cc406Sopenharmony_ci    {
807141cc406Sopenharmony_ci      free (buffer);
808141cc406Sopenharmony_ci      return NULL;
809141cc406Sopenharmony_ci    }
810141cc406Sopenharmony_ci
811141cc406Sopenharmony_ci  size = buffer[0] - 2;
812141cc406Sopenharmony_ci  for (i = 0; i < (size / 2); i++)
813141cc406Sopenharmony_ci    buffer[i] = buffer[2 + 2 * i];
814141cc406Sopenharmony_ci  buffer[i] = '\0';
815141cc406Sopenharmony_ci
816141cc406Sopenharmony_ci  return (char *) buffer;
817141cc406Sopenharmony_ci}
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_cistatic void
820141cc406Sopenharmony_cicheck_libusb_device (libusb_device *dev, SANE_Bool from_file)
821141cc406Sopenharmony_ci{
822141cc406Sopenharmony_ci  libusb_device_handle *hdl;
823141cc406Sopenharmony_ci  struct libusb_device_descriptor desc;
824141cc406Sopenharmony_ci  struct libusb_config_descriptor *config0;
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_ci  int is_scanner = 0;
827141cc406Sopenharmony_ci  char *vendor;
828141cc406Sopenharmony_ci  char *product;
829141cc406Sopenharmony_ci  unsigned short vid, pid;
830141cc406Sopenharmony_ci  unsigned char busno, address;
831141cc406Sopenharmony_ci  int config;
832141cc406Sopenharmony_ci  int intf;
833141cc406Sopenharmony_ci  int ret;
834141cc406Sopenharmony_ci
835141cc406Sopenharmony_ci  busno = libusb_get_bus_number (dev);
836141cc406Sopenharmony_ci  address = libusb_get_device_address (dev);
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci  ret = libusb_get_device_descriptor (dev, &desc);
839141cc406Sopenharmony_ci  if (ret < 0)
840141cc406Sopenharmony_ci    {
841141cc406Sopenharmony_ci      printf ("could not get device descriptor for device at %03d:%03d: %s\n",
842141cc406Sopenharmony_ci	      busno, address, sfs_libusb_strerror (ret));
843141cc406Sopenharmony_ci      return;
844141cc406Sopenharmony_ci    }
845141cc406Sopenharmony_ci
846141cc406Sopenharmony_ci  vid = desc.idVendor;
847141cc406Sopenharmony_ci  pid = desc.idProduct;
848141cc406Sopenharmony_ci
849141cc406Sopenharmony_ci  ret = libusb_open (dev, &hdl);
850141cc406Sopenharmony_ci  if (ret < 0)
851141cc406Sopenharmony_ci    {
852141cc406Sopenharmony_ci      printf ("could not open USB device 0x%04x/0x%04x at %03d:%03d: %s\n",
853141cc406Sopenharmony_ci	      vid, pid, busno, address, sfs_libusb_strerror (ret));
854141cc406Sopenharmony_ci      return;
855141cc406Sopenharmony_ci    }
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci  ret = libusb_get_configuration (hdl, &config);
858141cc406Sopenharmony_ci  if (ret < 0)
859141cc406Sopenharmony_ci    {
860141cc406Sopenharmony_ci      printf ("could not get configuration for device 0x%04x/0x%04x at %03d:%03d: %s\n",
861141cc406Sopenharmony_ci	      vid, pid, busno, address, sfs_libusb_strerror (ret));
862141cc406Sopenharmony_ci      libusb_close (hdl);
863141cc406Sopenharmony_ci      return;
864141cc406Sopenharmony_ci    }
865141cc406Sopenharmony_ci
866141cc406Sopenharmony_ci  if (config == 0)
867141cc406Sopenharmony_ci    {
868141cc406Sopenharmony_ci      if (verbose > 1)
869141cc406Sopenharmony_ci	printf ("device 0x%04x/0x%04x at %03d:%03d is not configured\n",
870141cc406Sopenharmony_ci		vid, pid, busno, address);
871141cc406Sopenharmony_ci      libusb_close (hdl);
872141cc406Sopenharmony_ci      return;
873141cc406Sopenharmony_ci    }
874141cc406Sopenharmony_ci
875141cc406Sopenharmony_ci  vendor = get_libusb_string_descriptor (hdl, desc.iManufacturer);
876141cc406Sopenharmony_ci  product = get_libusb_string_descriptor (hdl, desc.iProduct);
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci  if (verbose > 2)
879141cc406Sopenharmony_ci    {
880141cc406Sopenharmony_ci      /* print everything we know about the device */
881141cc406Sopenharmony_ci      char *buf;
882141cc406Sopenharmony_ci      int config_nr;
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_ci      printf ("\n");
885141cc406Sopenharmony_ci      printf ("<device descriptor of 0x%04x/0x%04x at %03d:%03d",
886141cc406Sopenharmony_ci	      vid, pid, busno, address);
887141cc406Sopenharmony_ci      if (vendor || product)
888141cc406Sopenharmony_ci	{
889141cc406Sopenharmony_ci	  printf (" (%s%s%s)", (vendor) ? vendor : "",
890141cc406Sopenharmony_ci		  (vendor && product) ? " " : "", (product) ? product : "");
891141cc406Sopenharmony_ci	}
892141cc406Sopenharmony_ci      printf (">\n");
893141cc406Sopenharmony_ci      printf ("bLength               %d\n", desc.bLength);
894141cc406Sopenharmony_ci      printf ("bDescriptorType       %d\n", desc.bDescriptorType);
895141cc406Sopenharmony_ci      printf ("bcdUSB                %d.%d%d\n", desc.bcdUSB >> 8,
896141cc406Sopenharmony_ci	      (desc.bcdUSB >> 4) & 15, desc.bcdUSB & 15);
897141cc406Sopenharmony_ci      printf ("bDeviceClass          %d\n", desc.bDeviceClass);
898141cc406Sopenharmony_ci      printf ("bDeviceSubClass       %d\n", desc.bDeviceSubClass);
899141cc406Sopenharmony_ci      printf ("bDeviceProtocol       %d\n", desc.bDeviceProtocol);
900141cc406Sopenharmony_ci      printf ("bMaxPacketSize0       %d\n", desc.bMaxPacketSize0);
901141cc406Sopenharmony_ci      printf ("idVendor              0x%04X\n", desc.idVendor);
902141cc406Sopenharmony_ci      printf ("idProduct             0x%04X\n", desc.idProduct);
903141cc406Sopenharmony_ci      printf ("bcdDevice             %d.%d%d\n", desc.bcdDevice >> 8,
904141cc406Sopenharmony_ci	      (desc.bcdDevice >> 4) & 15, desc.bcdDevice & 15);
905141cc406Sopenharmony_ci      printf ("iManufacturer         %d (%s)\n", desc.iManufacturer,
906141cc406Sopenharmony_ci	      (vendor) ? vendor : "");
907141cc406Sopenharmony_ci      printf ("iProduct              %d (%s)\n", desc.iProduct,
908141cc406Sopenharmony_ci	      (product) ? product : "");
909141cc406Sopenharmony_ci      buf = get_libusb_string_descriptor (hdl, desc.iSerialNumber);
910141cc406Sopenharmony_ci      printf ("iSerialNumber         %d (%s)\n", desc.iSerialNumber,
911141cc406Sopenharmony_ci	      (buf) ? buf : "");
912141cc406Sopenharmony_ci      if (buf)
913141cc406Sopenharmony_ci	free (buf);
914141cc406Sopenharmony_ci      printf ("bNumConfigurations    %d\n", desc.bNumConfigurations);
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci      for (config_nr = 0; config_nr < desc.bNumConfigurations; config_nr++)
917141cc406Sopenharmony_ci	{
918141cc406Sopenharmony_ci	  struct libusb_config_descriptor *c;
919141cc406Sopenharmony_ci
920141cc406Sopenharmony_ci	  ret = libusb_get_config_descriptor (dev, config_nr, &c);
921141cc406Sopenharmony_ci	  if (ret < 0)
922141cc406Sopenharmony_ci	    {
923141cc406Sopenharmony_ci	      printf ("could not get configuration descriptor %d: %s\n",
924141cc406Sopenharmony_ci		      config_nr, sfs_libusb_strerror (ret));
925141cc406Sopenharmony_ci	      continue;
926141cc406Sopenharmony_ci	    }
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci	  printf (" <configuration %d>\n", config_nr);
929141cc406Sopenharmony_ci	  printf (" bLength              %d\n", c->bLength);
930141cc406Sopenharmony_ci	  printf (" bDescriptorType      %d\n", c->bDescriptorType);
931141cc406Sopenharmony_ci	  printf (" wTotalLength         %d\n", c->wTotalLength);
932141cc406Sopenharmony_ci	  printf (" bNumInterfaces       %d\n", c->bNumInterfaces);
933141cc406Sopenharmony_ci	  printf (" bConfigurationValue  %d\n", c->bConfigurationValue);
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci	  buf = get_libusb_string_descriptor (hdl, c->iConfiguration);
936141cc406Sopenharmony_ci	  printf (" iConfiguration       %d (%s)\n", c->iConfiguration,
937141cc406Sopenharmony_ci		  (buf) ? buf : "");
938141cc406Sopenharmony_ci	  free (buf);
939141cc406Sopenharmony_ci
940141cc406Sopenharmony_ci	  printf (" bmAttributes         %d (%s%s)\n", c->bmAttributes,
941141cc406Sopenharmony_ci		  c->bmAttributes & 64 ? "Self-powered" : "",
942141cc406Sopenharmony_ci		  c->bmAttributes & 32 ? "Remote Wakeup" : "");
943141cc406Sopenharmony_ci	  printf (" MaxPower             %d mA\n", c->MaxPower * 2);
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci	  for (intf = 0; intf < c->bNumInterfaces; intf++)
946141cc406Sopenharmony_ci	    {
947141cc406Sopenharmony_ci	      const struct libusb_interface *interface;
948141cc406Sopenharmony_ci	      int alt_setting_nr;
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci	      interface = &c->interface[intf];
951141cc406Sopenharmony_ci
952141cc406Sopenharmony_ci	      printf ("  <interface %d>\n", intf);
953141cc406Sopenharmony_ci	      for (alt_setting_nr = 0;
954141cc406Sopenharmony_ci		   alt_setting_nr < interface->num_altsetting;
955141cc406Sopenharmony_ci		   alt_setting_nr++)
956141cc406Sopenharmony_ci		{
957141cc406Sopenharmony_ci		  const struct libusb_interface_descriptor *i;
958141cc406Sopenharmony_ci		  int ep_nr;
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_ci		  i = &interface->altsetting[alt_setting_nr];
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci		  printf ("   <altsetting %d>\n", alt_setting_nr);
963141cc406Sopenharmony_ci		  printf ("   bLength            %d\n", i->bLength);
964141cc406Sopenharmony_ci		  printf ("   bDescriptorType    %d\n", i->bDescriptorType);
965141cc406Sopenharmony_ci		  printf ("   bInterfaceNumber   %d\n", i->bInterfaceNumber);
966141cc406Sopenharmony_ci		  printf ("   bAlternateSetting  %d\n", i->bAlternateSetting);
967141cc406Sopenharmony_ci		  printf ("   bNumEndpoints      %d\n", i->bNumEndpoints);
968141cc406Sopenharmony_ci		  printf ("   bInterfaceClass    %d\n", i->bInterfaceClass);
969141cc406Sopenharmony_ci		  printf ("   bInterfaceSubClass %d\n",
970141cc406Sopenharmony_ci			  i->bInterfaceSubClass);
971141cc406Sopenharmony_ci		  printf ("   bInterfaceProtocol %d\n",
972141cc406Sopenharmony_ci			  i->bInterfaceProtocol);
973141cc406Sopenharmony_ci
974141cc406Sopenharmony_ci		  buf = NULL;
975141cc406Sopenharmony_ci		  buf = get_libusb_string_descriptor (hdl, i->iInterface);
976141cc406Sopenharmony_ci		  printf ("   iInterface         %d (%s)\n", i->iInterface,
977141cc406Sopenharmony_ci			  (buf) ? buf : "");
978141cc406Sopenharmony_ci		  free (buf);
979141cc406Sopenharmony_ci		  for (ep_nr = 0; ep_nr < i->bNumEndpoints; ep_nr++)
980141cc406Sopenharmony_ci		    {
981141cc406Sopenharmony_ci		      const struct libusb_endpoint_descriptor *e;
982141cc406Sopenharmony_ci		      char *ep_type;
983141cc406Sopenharmony_ci
984141cc406Sopenharmony_ci		      e = &i->endpoint[ep_nr];
985141cc406Sopenharmony_ci
986141cc406Sopenharmony_ci		      switch (e->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
987141cc406Sopenharmony_ci			{
988141cc406Sopenharmony_ci			  case LIBUSB_TRANSFER_TYPE_CONTROL:
989141cc406Sopenharmony_ci			    ep_type = "control";
990141cc406Sopenharmony_ci			    break;
991141cc406Sopenharmony_ci			  case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
992141cc406Sopenharmony_ci			    ep_type = "isochronous";
993141cc406Sopenharmony_ci			    break;
994141cc406Sopenharmony_ci			  case LIBUSB_TRANSFER_TYPE_BULK:
995141cc406Sopenharmony_ci			    ep_type = "bulk";
996141cc406Sopenharmony_ci			    break;
997141cc406Sopenharmony_ci			  case LIBUSB_TRANSFER_TYPE_INTERRUPT:
998141cc406Sopenharmony_ci			    ep_type = "interrupt";
999141cc406Sopenharmony_ci			    break;
1000141cc406Sopenharmony_ci			  default:
1001141cc406Sopenharmony_ci			    ep_type = "unknown";
1002141cc406Sopenharmony_ci			    break;
1003141cc406Sopenharmony_ci			}
1004141cc406Sopenharmony_ci		      printf ("    <endpoint %d>\n", ep_nr);
1005141cc406Sopenharmony_ci		      printf ("    bLength           %d\n", e->bLength);
1006141cc406Sopenharmony_ci		      printf ("    bDescriptorType   %d\n",
1007141cc406Sopenharmony_ci			      e->bDescriptorType);
1008141cc406Sopenharmony_ci		      printf ("    bEndpointAddress  0x%02X (%s 0x%02X)\n",
1009141cc406Sopenharmony_ci			      e->bEndpointAddress,
1010141cc406Sopenharmony_ci			      e->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK ?
1011141cc406Sopenharmony_ci			      "in" : "out",
1012141cc406Sopenharmony_ci			      e->
1013141cc406Sopenharmony_ci			      bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
1014141cc406Sopenharmony_ci		      printf ("    bmAttributes      %d (%s)\n",
1015141cc406Sopenharmony_ci			      e->bmAttributes, ep_type);
1016141cc406Sopenharmony_ci		      printf ("    wMaxPacketSize    %d\n",
1017141cc406Sopenharmony_ci			      e->wMaxPacketSize);
1018141cc406Sopenharmony_ci		      printf ("    bInterval         %d ms\n", e->bInterval);
1019141cc406Sopenharmony_ci		      printf ("    bRefresh          %d\n", e->bRefresh);
1020141cc406Sopenharmony_ci		      printf ("    bSynchAddress     %d\n", e->bSynchAddress);
1021141cc406Sopenharmony_ci		    }
1022141cc406Sopenharmony_ci		}
1023141cc406Sopenharmony_ci	    }
1024141cc406Sopenharmony_ci	}
1025141cc406Sopenharmony_ci    }
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci  /* Some heuristics, which device may be a scanner */
1029141cc406Sopenharmony_ci  if (desc.idVendor == 0)	/* hub */
1030141cc406Sopenharmony_ci    --is_scanner;
1031141cc406Sopenharmony_ci  if (desc.idProduct == 0)	/* hub */
1032141cc406Sopenharmony_ci    --is_scanner;
1033141cc406Sopenharmony_ci
1034141cc406Sopenharmony_ci  ret = libusb_get_config_descriptor (dev, 0, &config0);
1035141cc406Sopenharmony_ci  if (ret < 0)
1036141cc406Sopenharmony_ci    {
1037141cc406Sopenharmony_ci      printf ("could not get config[0] descriptor: %s\n",
1038141cc406Sopenharmony_ci	      sfs_libusb_strerror (ret));
1039141cc406Sopenharmony_ci
1040141cc406Sopenharmony_ci      goto out_free;
1041141cc406Sopenharmony_ci    }
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci  for (intf = 0; (intf < config0->bNumInterfaces) && (is_scanner <= 0); intf++)
1044141cc406Sopenharmony_ci    {
1045141cc406Sopenharmony_ci      switch (desc.bDeviceClass)
1046141cc406Sopenharmony_ci	{
1047141cc406Sopenharmony_ci	  case USB_CLASS_VENDOR_SPEC:
1048141cc406Sopenharmony_ci	    ++is_scanner;
1049141cc406Sopenharmony_ci	    break;
1050141cc406Sopenharmony_ci	  case USB_CLASS_PER_INTERFACE:
1051141cc406Sopenharmony_ci	    if ((config0->interface[intf].num_altsetting == 0)
1052141cc406Sopenharmony_ci		|| !config0->interface[intf].altsetting)
1053141cc406Sopenharmony_ci	      break;
1054141cc406Sopenharmony_ci	    switch (config0->interface[intf].altsetting[0].bInterfaceClass)
1055141cc406Sopenharmony_ci	      {
1056141cc406Sopenharmony_ci	        case USB_CLASS_VENDOR_SPEC:
1057141cc406Sopenharmony_ci	        case USB_CLASS_PER_INTERFACE:
1058141cc406Sopenharmony_ci	        case 16:                /* data? */
1059141cc406Sopenharmony_ci		  ++is_scanner;
1060141cc406Sopenharmony_ci		  break;
1061141cc406Sopenharmony_ci	      }
1062141cc406Sopenharmony_ci	    break;
1063141cc406Sopenharmony_ci	}
1064141cc406Sopenharmony_ci    }
1065141cc406Sopenharmony_ci
1066141cc406Sopenharmony_ci  if (is_scanner > 0)
1067141cc406Sopenharmony_ci    {
1068141cc406Sopenharmony_ci      char *chipset = NULL;
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ci      if(!from_file)
1071141cc406Sopenharmony_ci        chipset = check_usb_chip (verbose, desc, hdl, config0);
1072141cc406Sopenharmony_ci
1073141cc406Sopenharmony_ci      printf ("found possible USB scanner (vendor=0x%04x", vid);
1074141cc406Sopenharmony_ci      if (vendor)
1075141cc406Sopenharmony_ci	printf (" [%s]", vendor);
1076141cc406Sopenharmony_ci      printf (", product=0x%04x", pid);
1077141cc406Sopenharmony_ci      if (product)
1078141cc406Sopenharmony_ci	printf (" [%s]", product);
1079141cc406Sopenharmony_ci      if (chipset)
1080141cc406Sopenharmony_ci	printf (", chip=%s", chipset);
1081141cc406Sopenharmony_ci      if (from_file)
1082141cc406Sopenharmony_ci	printf (")\n");
1083141cc406Sopenharmony_ci      else
1084141cc406Sopenharmony_ci	printf (") at libusb:%03d:%03d\n", busno, address);
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci      libusb_device_found = SANE_TRUE;
1087141cc406Sopenharmony_ci      device_found = SANE_TRUE;
1088141cc406Sopenharmony_ci    }
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci  libusb_free_config_descriptor (config0);
1091141cc406Sopenharmony_ci
1092141cc406Sopenharmony_ci out_free:
1093141cc406Sopenharmony_ci  libusb_close (hdl);
1094141cc406Sopenharmony_ci  if (vendor)
1095141cc406Sopenharmony_ci    free (vendor);
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci  if (product)
1098141cc406Sopenharmony_ci    free (product);
1099141cc406Sopenharmony_ci}
1100141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB */
1101141cc406Sopenharmony_ci
1102141cc406Sopenharmony_ci
1103141cc406Sopenharmony_cistatic DIR *
1104141cc406Sopenharmony_ciscan_directory (char *dir_name)
1105141cc406Sopenharmony_ci{
1106141cc406Sopenharmony_ci  struct stat stat_buf;
1107141cc406Sopenharmony_ci  DIR *dir;
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci  if (verbose > 2)
1110141cc406Sopenharmony_ci    printf ("scanning directory %s\n", dir_name);
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_ci  if (stat (dir_name, &stat_buf) < 0)
1113141cc406Sopenharmony_ci    {
1114141cc406Sopenharmony_ci      if (verbose > 1)
1115141cc406Sopenharmony_ci	printf ("cannot stat `%s' (%s)\n", dir_name, strerror (errno));
1116141cc406Sopenharmony_ci      return 0;
1117141cc406Sopenharmony_ci    }
1118141cc406Sopenharmony_ci  if (!S_ISDIR (stat_buf.st_mode))
1119141cc406Sopenharmony_ci    {
1120141cc406Sopenharmony_ci      if (verbose > 1)
1121141cc406Sopenharmony_ci	printf ("`%s' is not a directory\n", dir_name);
1122141cc406Sopenharmony_ci      return 0;
1123141cc406Sopenharmony_ci    }
1124141cc406Sopenharmony_ci  if ((dir = opendir (dir_name)) == 0)
1125141cc406Sopenharmony_ci    {
1126141cc406Sopenharmony_ci      if (verbose > 1)
1127141cc406Sopenharmony_ci	printf ("cannot read directory `%s' (%s)\n", dir_name,
1128141cc406Sopenharmony_ci		strerror (errno));
1129141cc406Sopenharmony_ci      return 0;
1130141cc406Sopenharmony_ci    }
1131141cc406Sopenharmony_ci  return dir;
1132141cc406Sopenharmony_ci}
1133141cc406Sopenharmony_ci
1134141cc406Sopenharmony_cistatic char *
1135141cc406Sopenharmony_ciget_next_file (char *dir_name, DIR * dir)
1136141cc406Sopenharmony_ci{
1137141cc406Sopenharmony_ci  struct dirent *dir_entry;
1138141cc406Sopenharmony_ci  static char file_name[PATH_MAX];
1139141cc406Sopenharmony_ci
1140141cc406Sopenharmony_ci  do
1141141cc406Sopenharmony_ci    {
1142141cc406Sopenharmony_ci      dir_entry = readdir (dir);
1143141cc406Sopenharmony_ci      if (!dir_entry)
1144141cc406Sopenharmony_ci	return 0;
1145141cc406Sopenharmony_ci    }
1146141cc406Sopenharmony_ci  while (strcmp (dir_entry->d_name, ".") == 0
1147141cc406Sopenharmony_ci	 || strcmp (dir_entry->d_name, "..") == 0);
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci  if (strlen (dir_name) + strlen (dir_entry->d_name) + 1 > PATH_MAX)
1150141cc406Sopenharmony_ci    {
1151141cc406Sopenharmony_ci      if (verbose > 1)
1152141cc406Sopenharmony_ci	printf ("filename too long\n");
1153141cc406Sopenharmony_ci      return 0;
1154141cc406Sopenharmony_ci    }
1155141cc406Sopenharmony_ci  sprintf (file_name, "%s%s", dir_name, dir_entry->d_name);
1156141cc406Sopenharmony_ci  return file_name;
1157141cc406Sopenharmony_ci}
1158141cc406Sopenharmony_ci
1159141cc406Sopenharmony_ci#if defined(WIN32_SCSI)
1160141cc406Sopenharmony_ci/* 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. */
1161141cc406Sopenharmony_cistatic char **build_scsi_dev_list(void)
1162141cc406Sopenharmony_ci{
1163141cc406Sopenharmony_ci	char **dev_list;
1164141cc406Sopenharmony_ci	int dev_list_index;
1165141cc406Sopenharmony_ci	int hca;
1166141cc406Sopenharmony_ci	HANDLE fd;
1167141cc406Sopenharmony_ci	char scsi_hca_name[20];
1168141cc406Sopenharmony_ci	char buffer[4096];
1169141cc406Sopenharmony_ci	DWORD BytesReturned;
1170141cc406Sopenharmony_ci	BOOL ret;
1171141cc406Sopenharmony_ci	size_t dev_list_size;
1172141cc406Sopenharmony_ci	PSCSI_ADAPTER_BUS_INFO adapter;
1173141cc406Sopenharmony_ci	PSCSI_INQUIRY_DATA inquiry;
1174141cc406Sopenharmony_ci	int i;
1175141cc406Sopenharmony_ci
1176141cc406Sopenharmony_ci	/* Allocate room for about 100 scanners. That should be enough. */
1177141cc406Sopenharmony_ci	dev_list_size = 100;
1178141cc406Sopenharmony_ci	dev_list_index = 0;
1179141cc406Sopenharmony_ci	dev_list = calloc(1, dev_list_size * sizeof(char *));
1180141cc406Sopenharmony_ci
1181141cc406Sopenharmony_ci	hca = 0;
1182141cc406Sopenharmony_ci
1183141cc406Sopenharmony_ci	for(hca = 0; ; hca++) {
1184141cc406Sopenharmony_ci
1185141cc406Sopenharmony_ci		/* Open the adapter */
1186141cc406Sopenharmony_ci		snprintf(scsi_hca_name, 20, "\\\\.\\Scsi%d:", hca);
1187141cc406Sopenharmony_ci		fd = CreateFile(scsi_hca_name, GENERIC_READ | GENERIC_WRITE,
1188141cc406Sopenharmony_ci						FILE_SHARE_READ | FILE_SHARE_WRITE,
1189141cc406Sopenharmony_ci						NULL, OPEN_EXISTING,
1190141cc406Sopenharmony_ci						FILE_FLAG_RANDOM_ACCESS, NULL );
1191141cc406Sopenharmony_ci
1192141cc406Sopenharmony_ci		if (fd == INVALID_HANDLE_VALUE) {
1193141cc406Sopenharmony_ci			/* Assume there is no more adapter. This is wrong in the case
1194141cc406Sopenharmony_ci			 * of hot-plug stuff, but I have yet to see it on a user
1195141cc406Sopenharmony_ci			 * machine. */
1196141cc406Sopenharmony_ci			break;
1197141cc406Sopenharmony_ci		}
1198141cc406Sopenharmony_ci
1199141cc406Sopenharmony_ci		/* Get the inquiry info for the devices on that hca. */
1200141cc406Sopenharmony_ci        ret = DeviceIoControl(fd,
1201141cc406Sopenharmony_ci							  IOCTL_SCSI_GET_INQUIRY_DATA,
1202141cc406Sopenharmony_ci							  NULL,
1203141cc406Sopenharmony_ci							  0,
1204141cc406Sopenharmony_ci							  buffer,
1205141cc406Sopenharmony_ci							  sizeof(buffer),
1206141cc406Sopenharmony_ci							  &BytesReturned,
1207141cc406Sopenharmony_ci							  FALSE);
1208141cc406Sopenharmony_ci
1209141cc406Sopenharmony_ci        if(ret == 0)
1210141cc406Sopenharmony_ci			{
1211141cc406Sopenharmony_ci				CloseHandle(fd);
1212141cc406Sopenharmony_ci				continue;
1213141cc406Sopenharmony_ci			}
1214141cc406Sopenharmony_ci
1215141cc406Sopenharmony_ci		adapter = (PSCSI_ADAPTER_BUS_INFO)buffer;
1216141cc406Sopenharmony_ci
1217141cc406Sopenharmony_ci		for(i = 0; i < adapter->NumberOfBuses; i++) {
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci			if (adapter->BusData[i].InquiryDataOffset == 0) {
1220141cc406Sopenharmony_ci				/* No device here */
1221141cc406Sopenharmony_ci				continue;
1222141cc406Sopenharmony_ci			}
1223141cc406Sopenharmony_ci
1224141cc406Sopenharmony_ci			inquiry = (PSCSI_INQUIRY_DATA) (buffer +
1225141cc406Sopenharmony_ci											adapter->BusData[i].InquiryDataOffset);
1226141cc406Sopenharmony_ci			while(1) {
1227141cc406Sopenharmony_ci				/* Check if it is a scanner or a processor
1228141cc406Sopenharmony_ci				 * device. Ignore the other
1229141cc406Sopenharmony_ci				 * device types. */
1230141cc406Sopenharmony_ci				if (inquiry->InquiryDataLength >= 5 &&
1231141cc406Sopenharmony_ci					((inquiry->InquiryData[0] & 0x1f) == 3 ||
1232141cc406Sopenharmony_ci					 (inquiry->InquiryData[0] & 0x1f) == 6)) {
1233141cc406Sopenharmony_ci					char device_name[20];
1234141cc406Sopenharmony_ci					sprintf(device_name, "h%db%dt%dl%d", hca, inquiry->PathId, inquiry->TargetId, inquiry->Lun);
1235141cc406Sopenharmony_ci					dev_list[dev_list_index] = strdup(device_name);
1236141cc406Sopenharmony_ci					dev_list_index++;
1237141cc406Sopenharmony_ci				}
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci				if (inquiry->NextInquiryDataOffset == 0) {
1240141cc406Sopenharmony_ci					/* No device here */
1241141cc406Sopenharmony_ci					break;
1242141cc406Sopenharmony_ci				} else {
1243141cc406Sopenharmony_ci					inquiry =  (PSCSI_INQUIRY_DATA) (buffer +
1244141cc406Sopenharmony_ci													 inquiry->NextInquiryDataOffset);
1245141cc406Sopenharmony_ci				}
1246141cc406Sopenharmony_ci			}
1247141cc406Sopenharmony_ci	    }
1248141cc406Sopenharmony_ci
1249141cc406Sopenharmony_ci		CloseHandle(fd);
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_ci	}
1252141cc406Sopenharmony_ci
1253141cc406Sopenharmony_ci	return dev_list;
1254141cc406Sopenharmony_ci
1255141cc406Sopenharmony_ci}
1256141cc406Sopenharmony_ci#endif
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci#if defined (HAVE_IOKIT_CDB_IOSCSILIB_H) || \
1259141cc406Sopenharmony_ci    defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
1260141cc406Sopenharmony_ci    defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
1261141cc406Sopenharmony_cichar **scsi_dev_list;
1262141cc406Sopenharmony_ciint scsi_dev_list_index;
1263141cc406Sopenharmony_ci
1264141cc406Sopenharmony_cistatic SANE_Status AddToSCSIDeviceList (const char *dev) {
1265141cc406Sopenharmony_ci  if (scsi_dev_list_index < 99) {
1266141cc406Sopenharmony_ci    scsi_dev_list [scsi_dev_list_index] = strdup (dev);
1267141cc406Sopenharmony_ci    scsi_dev_list_index++;
1268141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1269141cc406Sopenharmony_ci  }
1270141cc406Sopenharmony_ci  else
1271141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1272141cc406Sopenharmony_ci}
1273141cc406Sopenharmony_ci
1274141cc406Sopenharmony_cistatic char **build_scsi_dev_list(void)
1275141cc406Sopenharmony_ci{
1276141cc406Sopenharmony_ci  scsi_dev_list_index = 0;
1277141cc406Sopenharmony_ci  scsi_dev_list = malloc (100 * sizeof(char *));
1278141cc406Sopenharmony_ci  sanei_scsi_find_devices (NULL, NULL, NULL, -1, -1, -1, -1,
1279141cc406Sopenharmony_ci			   AddToSCSIDeviceList);
1280141cc406Sopenharmony_ci  scsi_dev_list [scsi_dev_list_index] = NULL;
1281141cc406Sopenharmony_ci  return scsi_dev_list;
1282141cc406Sopenharmony_ci}
1283141cc406Sopenharmony_ci#endif
1284141cc406Sopenharmony_ci
1285141cc406Sopenharmony_cistatic int
1286141cc406Sopenharmony_cicheck_mustek_pp_device (void)
1287141cc406Sopenharmony_ci{
1288141cc406Sopenharmony_ci  const char **devices;
1289141cc406Sopenharmony_ci  int ctr = 0, found = 0, scsi = 0;
1290141cc406Sopenharmony_ci
1291141cc406Sopenharmony_ci  if (verbose > 1)
1292141cc406Sopenharmony_ci    printf ("searching for Mustek parallel port scanners:\n");
1293141cc406Sopenharmony_ci
1294141cc406Sopenharmony_ci  devices = sanei_pa4s2_devices ();
1295141cc406Sopenharmony_ci
1296141cc406Sopenharmony_ci  while (devices[ctr] != NULL) {
1297141cc406Sopenharmony_ci    int fd;
1298141cc406Sopenharmony_ci    SANE_Status result;
1299141cc406Sopenharmony_ci
1300141cc406Sopenharmony_ci    /* ordinary parallel port scanner type */
1301141cc406Sopenharmony_ci    if (verbose > 1)
1302141cc406Sopenharmony_ci      printf ("checking %s...", devices[ctr]);
1303141cc406Sopenharmony_ci
1304141cc406Sopenharmony_ci    result = sanei_pa4s2_open (devices[ctr], &fd);
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ci    if (verbose > 1)
1307141cc406Sopenharmony_ci      {
1308141cc406Sopenharmony_ci        if (result != 0)
1309141cc406Sopenharmony_ci  	  printf (" failed to open (%s)\n", sane_strstatus (result));
1310141cc406Sopenharmony_ci        else
1311141cc406Sopenharmony_ci	  printf (" open ok\n");
1312141cc406Sopenharmony_ci      }
1313141cc406Sopenharmony_ci
1314141cc406Sopenharmony_ci    if (result == 0) {
1315141cc406Sopenharmony_ci      printf ("found possible Mustek parallel port scanner at \"%s\"\n",
1316141cc406Sopenharmony_ci              devices[ctr]);
1317141cc406Sopenharmony_ci      found++;
1318141cc406Sopenharmony_ci      sanei_pa4s2_close(fd);
1319141cc406Sopenharmony_ci    }
1320141cc406Sopenharmony_ci
1321141cc406Sopenharmony_ci    /* trying scsi over pp devices */
1322141cc406Sopenharmony_ci    if (verbose > 1)
1323141cc406Sopenharmony_ci      printf ("checking %s (SCSI emulation)...", devices[ctr]);
1324141cc406Sopenharmony_ci
1325141cc406Sopenharmony_ci    result = sanei_pa4s2_scsi_pp_open (devices[ctr], &fd);
1326141cc406Sopenharmony_ci
1327141cc406Sopenharmony_ci    if (verbose > 1)
1328141cc406Sopenharmony_ci      {
1329141cc406Sopenharmony_ci        if (result != 0)
1330141cc406Sopenharmony_ci  	  printf (" failed to open (%s)\n", sane_strstatus (result));
1331141cc406Sopenharmony_ci        else
1332141cc406Sopenharmony_ci	  printf (" open ok\n");
1333141cc406Sopenharmony_ci      }
1334141cc406Sopenharmony_ci
1335141cc406Sopenharmony_ci    if (result == 0) {
1336141cc406Sopenharmony_ci      printf ("found possible Mustek SCSI over PP scanner at \"%s\"\n",
1337141cc406Sopenharmony_ci              devices[ctr]);
1338141cc406Sopenharmony_ci      scsi++;
1339141cc406Sopenharmony_ci      sanei_pa4s2_close(fd);
1340141cc406Sopenharmony_ci    }
1341141cc406Sopenharmony_ci
1342141cc406Sopenharmony_ci    ctr++;
1343141cc406Sopenharmony_ci  }
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci  free(devices);
1346141cc406Sopenharmony_ci
1347141cc406Sopenharmony_ci  if (found > 0 && verbose > 0)
1348141cc406Sopenharmony_ci    printf("\n  # Your Mustek parallel port scanner was detected.  It may or\n"
1349141cc406Sopenharmony_ci           "  # may not be supported by SANE.  Please read the sane-mustek_pp\n"
1350141cc406Sopenharmony_ci	   "  # man-page for setup instructions.\n");
1351141cc406Sopenharmony_ci
1352141cc406Sopenharmony_ci  if (scsi > 0 && verbose > 0)
1353141cc406Sopenharmony_ci    printf("\n  # Your Mustek parallel port scanner was detected.  It may or\n"
1354141cc406Sopenharmony_ci           "  # may not be supported by SANE.  Please read the sane-mustek_pp\n"
1355141cc406Sopenharmony_ci	   "  # man-page for setup instructions.\n");
1356141cc406Sopenharmony_ci
1357141cc406Sopenharmony_ci  return (found > 0 || scsi > 0);
1358141cc406Sopenharmony_ci}
1359141cc406Sopenharmony_ci
1360141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY
1361141cc406Sopenharmony_cistatic SANE_Bool
1362141cc406Sopenharmony_ciparse_num (char* search, const char* line, int base, long int * number)
1363141cc406Sopenharmony_ci{
1364141cc406Sopenharmony_ci  char* start_number;
1365141cc406Sopenharmony_ci
1366141cc406Sopenharmony_ci  start_number = strstr (line, search);
1367141cc406Sopenharmony_ci  if (start_number == NULL)
1368141cc406Sopenharmony_ci    return SANE_FALSE;
1369141cc406Sopenharmony_ci  start_number += strlen (search);
1370141cc406Sopenharmony_ci
1371141cc406Sopenharmony_ci  *number = strtol (start_number, NULL, base);
1372141cc406Sopenharmony_ci  if (verbose > 2)
1373141cc406Sopenharmony_ci    printf ("Found %s%ld\n", search, *number);
1374141cc406Sopenharmony_ci  return SANE_TRUE;
1375141cc406Sopenharmony_ci}
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_cistatic SANE_Bool
1378141cc406Sopenharmony_ciparse_bcd (char* search, const char* line, long int * number)
1379141cc406Sopenharmony_ci{
1380141cc406Sopenharmony_ci  char* start_number;
1381141cc406Sopenharmony_ci  char* end_number;
1382141cc406Sopenharmony_ci  int first_part;
1383141cc406Sopenharmony_ci  int second_part;
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci  start_number = strstr (line, search);
1386141cc406Sopenharmony_ci  if (start_number == NULL)
1387141cc406Sopenharmony_ci    return SANE_FALSE;
1388141cc406Sopenharmony_ci  start_number += strlen (search);
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci  first_part = strtol (start_number, &end_number, 10);
1391141cc406Sopenharmony_ci  start_number = end_number + 1; /* skip colon */
1392141cc406Sopenharmony_ci  second_part = strtol (start_number, NULL, 10);
1393141cc406Sopenharmony_ci  *number = ((first_part / 10) << 12) + ((first_part % 10) << 8)
1394141cc406Sopenharmony_ci    + ((second_part / 10) << 4) + (second_part % 10);
1395141cc406Sopenharmony_ci  if (verbose > 2)
1396141cc406Sopenharmony_ci    printf ("Found %s%ld\n", search, *number);
1397141cc406Sopenharmony_ci  return SANE_TRUE;
1398141cc406Sopenharmony_ci}
1399141cc406Sopenharmony_ci
1400141cc406Sopenharmony_cistatic void
1401141cc406Sopenharmony_ciparse_file (char *filename)
1402141cc406Sopenharmony_ci{
1403141cc406Sopenharmony_ci  FILE * parsefile;
1404141cc406Sopenharmony_ci  char line [PATH_MAX], *token;
1405141cc406Sopenharmony_ci  const char * p;
1406141cc406Sopenharmony_ci  struct usb_device *dev = 0;
1407141cc406Sopenharmony_ci  long int number = 0;
1408141cc406Sopenharmony_ci  int current_config = 1;
1409141cc406Sopenharmony_ci  int current_if = -1;
1410141cc406Sopenharmony_ci  int current_as = -1;
1411141cc406Sopenharmony_ci  int current_ep = -1;
1412141cc406Sopenharmony_ci
1413141cc406Sopenharmony_ci  if (verbose > 1)
1414141cc406Sopenharmony_ci    printf ("trying to open %s\n", filename);
1415141cc406Sopenharmony_ci  parsefile = fopen (filename, "r");
1416141cc406Sopenharmony_ci
1417141cc406Sopenharmony_ci  if (parsefile == NULL)
1418141cc406Sopenharmony_ci    {
1419141cc406Sopenharmony_ci      if (verbose > 0)
1420141cc406Sopenharmony_ci	printf ("opening %s failed: %s\n", filename, strerror (errno));
1421141cc406Sopenharmony_ci      return;
1422141cc406Sopenharmony_ci    }
1423141cc406Sopenharmony_ci
1424141cc406Sopenharmony_ci  while (sanei_config_read (line, PATH_MAX, parsefile))
1425141cc406Sopenharmony_ci    {
1426141cc406Sopenharmony_ci      if (verbose > 2)
1427141cc406Sopenharmony_ci	printf ("parsing line: `%s'\n", line);
1428141cc406Sopenharmony_ci      p = sanei_config_get_string (line, &token);
1429141cc406Sopenharmony_ci      if (!token || !p || token[0] == '\0')
1430141cc406Sopenharmony_ci	continue;
1431141cc406Sopenharmony_ci      if (token[1] != ':')
1432141cc406Sopenharmony_ci	{
1433141cc406Sopenharmony_ci	  if (verbose > 2)
1434141cc406Sopenharmony_ci	    printf ("missing `:'?\n");
1435141cc406Sopenharmony_ci	  continue;
1436141cc406Sopenharmony_ci	}
1437141cc406Sopenharmony_ci      switch (token[0])
1438141cc406Sopenharmony_ci	{
1439141cc406Sopenharmony_ci	case 'T':
1440141cc406Sopenharmony_ci	  if (dev)
1441141cc406Sopenharmony_ci	    check_libusb_device (dev, SANE_TRUE);
1442141cc406Sopenharmony_ci	  dev = calloc (1, sizeof (struct usb_device));
1443141cc406Sopenharmony_ci	  dev->bus = calloc (1, sizeof (struct usb_bus));
1444141cc406Sopenharmony_ci	  current_config = 1;
1445141cc406Sopenharmony_ci	  current_if = -1;
1446141cc406Sopenharmony_ci	  current_as = -1;
1447141cc406Sopenharmony_ci	  current_ep = -1;
1448141cc406Sopenharmony_ci	  break;
1449141cc406Sopenharmony_ci	case 'D':
1450141cc406Sopenharmony_ci	  if (parse_bcd ("Ver=", line, &number))
1451141cc406Sopenharmony_ci	    dev->descriptor.bcdUSB = number;
1452141cc406Sopenharmony_ci	  if (parse_num ("Cls=", line, 16, &number))
1453141cc406Sopenharmony_ci	    dev->descriptor.bDeviceClass = number;
1454141cc406Sopenharmony_ci	  if (parse_num ("Sub=", line, 16, &number))
1455141cc406Sopenharmony_ci	    dev->descriptor.bDeviceSubClass = number;
1456141cc406Sopenharmony_ci	  if (parse_num ("Prot=", line, 16, &number))
1457141cc406Sopenharmony_ci	    dev->descriptor.bDeviceProtocol = number;
1458141cc406Sopenharmony_ci	  if (parse_num ("MxPS=", line, 10, &number))
1459141cc406Sopenharmony_ci	    dev->descriptor.bMaxPacketSize0 = number;
1460141cc406Sopenharmony_ci	  if (parse_num ("#Cfgs=", line, 10, &number))
1461141cc406Sopenharmony_ci	    dev->descriptor.bNumConfigurations = number;
1462141cc406Sopenharmony_ci	  dev->config = calloc (number, sizeof (struct usb_config_descriptor));
1463141cc406Sopenharmony_ci	  break;
1464141cc406Sopenharmony_ci	case 'P':
1465141cc406Sopenharmony_ci	  if (parse_num ("Vendor=", line, 16, &number))
1466141cc406Sopenharmony_ci	    dev->descriptor.idVendor = number;
1467141cc406Sopenharmony_ci	  if (parse_num ("ProdID=", line, 16, &number))
1468141cc406Sopenharmony_ci	    dev->descriptor.idProduct = number;
1469141cc406Sopenharmony_ci	  if (parse_bcd ("Rev=", line, &number))
1470141cc406Sopenharmony_ci	    dev->descriptor.bcdDevice = number;
1471141cc406Sopenharmony_ci	  break;
1472141cc406Sopenharmony_ci	case 'C':
1473141cc406Sopenharmony_ci	  current_if = -1;
1474141cc406Sopenharmony_ci	  current_as = -1;
1475141cc406Sopenharmony_ci	  current_ep = -1;
1476141cc406Sopenharmony_ci	  if (parse_num ("Cfg#=", line, 10, &number))
1477141cc406Sopenharmony_ci	    {
1478141cc406Sopenharmony_ci	      current_config = number - 1;
1479141cc406Sopenharmony_ci	      dev->config[current_config].bConfigurationValue = number;
1480141cc406Sopenharmony_ci	    }
1481141cc406Sopenharmony_ci	  if (parse_num ("Ifs=", line, 10, &number))
1482141cc406Sopenharmony_ci	    dev->config[current_config].bNumInterfaces = number;
1483141cc406Sopenharmony_ci	  dev->config[current_config].interface
1484141cc406Sopenharmony_ci	    = calloc (number, sizeof (struct usb_interface));
1485141cc406Sopenharmony_ci	  if (parse_num ("Atr=", line, 16, &number))
1486141cc406Sopenharmony_ci	    dev->config[current_config].bmAttributes = number;
1487141cc406Sopenharmony_ci	  if (parse_num ("MxPwr=", line, 10, &number))
1488141cc406Sopenharmony_ci	    dev->config[current_config].MaxPower = number / 2;
1489141cc406Sopenharmony_ci	  break;
1490141cc406Sopenharmony_ci	case 'I':
1491141cc406Sopenharmony_ci	  current_ep = -1;
1492141cc406Sopenharmony_ci	  if (parse_num ("If#=", line, 10, &number))
1493141cc406Sopenharmony_ci	    {
1494141cc406Sopenharmony_ci	      if (current_if != number)
1495141cc406Sopenharmony_ci		{
1496141cc406Sopenharmony_ci		  current_if = number;
1497141cc406Sopenharmony_ci		  current_as = -1;
1498141cc406Sopenharmony_ci		  dev->config[current_config].interface[current_if].altsetting
1499141cc406Sopenharmony_ci		    = calloc (20, sizeof (struct usb_interface_descriptor));
1500141cc406Sopenharmony_ci		  /* Can't read number of altsettings */
1501141cc406Sopenharmony_ci		  dev->config[current_config].interface[current_if].num_altsetting = 1;
1502141cc406Sopenharmony_ci		}
1503141cc406Sopenharmony_ci	      else
1504141cc406Sopenharmony_ci		dev->config[current_config].interface[current_if].num_altsetting++;
1505141cc406Sopenharmony_ci	    }
1506141cc406Sopenharmony_ci	  if (parse_num ("Alt=", line, 10, &number))
1507141cc406Sopenharmony_ci	    {
1508141cc406Sopenharmony_ci	      current_as = number;
1509141cc406Sopenharmony_ci	      dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceNumber
1510141cc406Sopenharmony_ci		= current_if;
1511141cc406Sopenharmony_ci	      dev->config[current_config].interface[current_if].altsetting[current_as].bAlternateSetting
1512141cc406Sopenharmony_ci		= current_as;
1513141cc406Sopenharmony_ci	    }
1514141cc406Sopenharmony_ci	  if (parse_num ("#EPs=", line, 10, &number))
1515141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as].bNumEndpoints
1516141cc406Sopenharmony_ci	      = number;
1517141cc406Sopenharmony_ci	  dev->config[current_config].interface[current_if].altsetting[current_as].endpoint
1518141cc406Sopenharmony_ci	    = calloc (number, sizeof (struct usb_endpoint_descriptor));
1519141cc406Sopenharmony_ci	  if (parse_num ("Cls=", line, 16, &number))
1520141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceClass
1521141cc406Sopenharmony_ci	      = number;
1522141cc406Sopenharmony_ci	  if (parse_num ("Sub=", line, 16, &number))
1523141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceSubClass
1524141cc406Sopenharmony_ci	      = number;
1525141cc406Sopenharmony_ci	  if (parse_num ("Prot=", line, 16, &number))
1526141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceProtocol
1527141cc406Sopenharmony_ci	      = number;
1528141cc406Sopenharmony_ci	  break;
1529141cc406Sopenharmony_ci	case 'E':
1530141cc406Sopenharmony_ci	  current_ep++;
1531141cc406Sopenharmony_ci	  if (parse_num ("Ad=", line, 16, &number))
1532141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as]
1533141cc406Sopenharmony_ci	      .endpoint[current_ep].bEndpointAddress = number;
1534141cc406Sopenharmony_ci	  if (parse_num ("Atr=", line, 16, &number))
1535141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as]
1536141cc406Sopenharmony_ci	      .endpoint[current_ep].bmAttributes = number;
1537141cc406Sopenharmony_ci	  if (parse_num ("MxPS=", line, 10, &number))
1538141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as]
1539141cc406Sopenharmony_ci	      .endpoint[current_ep].wMaxPacketSize = number;
1540141cc406Sopenharmony_ci	  if (parse_num ("Ivl=", line, 10, &number))
1541141cc406Sopenharmony_ci	    dev->config[current_config].interface[current_if].altsetting[current_as]
1542141cc406Sopenharmony_ci	      .endpoint[current_ep].bInterval = number;
1543141cc406Sopenharmony_ci	  break;
1544141cc406Sopenharmony_ci	case 'S':
1545141cc406Sopenharmony_ci	case 'B':
1546141cc406Sopenharmony_ci	  continue;
1547141cc406Sopenharmony_ci	default:
1548141cc406Sopenharmony_ci	  if (verbose > 1)
1549141cc406Sopenharmony_ci	    printf ("ignoring unknown line identifier: %c\n", token[0]);
1550141cc406Sopenharmony_ci	  continue;
1551141cc406Sopenharmony_ci	}
1552141cc406Sopenharmony_ci      free (token);
1553141cc406Sopenharmony_ci    }
1554141cc406Sopenharmony_ci  if (dev)
1555141cc406Sopenharmony_ci    check_libusb_device (dev, SANE_TRUE);
1556141cc406Sopenharmony_ci  fclose (parsefile);
1557141cc406Sopenharmony_ci  return;
1558141cc406Sopenharmony_ci}
1559141cc406Sopenharmony_ci#endif
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ciint
1562141cc406Sopenharmony_cimain (int argc, char **argv)
1563141cc406Sopenharmony_ci{
1564141cc406Sopenharmony_ci  char **dev_list, **usb_dev_list, *dev_name, **ap;
1565141cc406Sopenharmony_ci  int enable_pp_checks = SANE_FALSE;
1566141cc406Sopenharmony_ci
1567141cc406Sopenharmony_ci  prog_name = strrchr (argv[0], '/');
1568141cc406Sopenharmony_ci  if (prog_name)
1569141cc406Sopenharmony_ci    ++prog_name;
1570141cc406Sopenharmony_ci  else
1571141cc406Sopenharmony_ci    prog_name = argv[0];
1572141cc406Sopenharmony_ci
1573141cc406Sopenharmony_ci  for (ap = argv + 1; ap < argv + argc; ++ap)
1574141cc406Sopenharmony_ci    {
1575141cc406Sopenharmony_ci      if ((*ap)[0] != '-')
1576141cc406Sopenharmony_ci	break;
1577141cc406Sopenharmony_ci      switch ((*ap)[1])
1578141cc406Sopenharmony_ci	{
1579141cc406Sopenharmony_ci	case '?':
1580141cc406Sopenharmony_ci	case 'h':
1581141cc406Sopenharmony_ci	  usage (0);
1582141cc406Sopenharmony_ci	  exit (0);
1583141cc406Sopenharmony_ci
1584141cc406Sopenharmony_ci	case 'v':
1585141cc406Sopenharmony_ci	  ++verbose;
1586141cc406Sopenharmony_ci	  break;
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci	case 'q':
1589141cc406Sopenharmony_ci	  --verbose;
1590141cc406Sopenharmony_ci	  break;
1591141cc406Sopenharmony_ci
1592141cc406Sopenharmony_ci	case 'f':
1593141cc406Sopenharmony_ci	  force = SANE_TRUE;
1594141cc406Sopenharmony_ci	  break;
1595141cc406Sopenharmony_ci
1596141cc406Sopenharmony_ci	case 'p':
1597141cc406Sopenharmony_ci	  enable_pp_checks = SANE_TRUE;
1598141cc406Sopenharmony_ci	  break;
1599141cc406Sopenharmony_ci
1600141cc406Sopenharmony_ci	case 'F':
1601141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY
1602141cc406Sopenharmony_ci	  parse_file ((char *) (*(++ap)));
1603141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB)
1604141cc406Sopenharmony_ci	  printf ("option -F not implemented with libusb-1.0\n");
1605141cc406Sopenharmony_ci#else
1606141cc406Sopenharmony_ci	  printf ("libusb not available: option -F can't be used\n");
1607141cc406Sopenharmony_ci#endif
1608141cc406Sopenharmony_ci	  exit (0);
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_ci	case '-':
1611141cc406Sopenharmony_ci	  if (!strcmp((*ap), "--help"))
1612141cc406Sopenharmony_ci	    {
1613141cc406Sopenharmony_ci	      usage (0);
1614141cc406Sopenharmony_ci	      exit (0);
1615141cc406Sopenharmony_ci	    }
1616141cc406Sopenharmony_ci          // fall through
1617141cc406Sopenharmony_ci	default:
1618141cc406Sopenharmony_ci	  printf ("unknown option: -%c, try -h for help\n", (*ap)[1]);
1619141cc406Sopenharmony_ci	  exit (0);
1620141cc406Sopenharmony_ci	}
1621141cc406Sopenharmony_ci    }
1622141cc406Sopenharmony_ci  if (ap < argv + argc)
1623141cc406Sopenharmony_ci    {
1624141cc406Sopenharmony_ci      dev_list = ap;
1625141cc406Sopenharmony_ci      usb_dev_list = ap;
1626141cc406Sopenharmony_ci    }
1627141cc406Sopenharmony_ci  else
1628141cc406Sopenharmony_ci    {
1629141cc406Sopenharmony_ci      static char *default_dev_list[] = {
1630141cc406Sopenharmony_ci#if defined(__sgi)
1631141cc406Sopenharmony_ci	"/dev/scsi/sc0d1l0", "/dev/scsi/sc0d2l0",
1632141cc406Sopenharmony_ci	"/dev/scsi/sc0d3l0", "/dev/scsi/sc0d4l0",
1633141cc406Sopenharmony_ci	"/dev/scsi/sc0d5l0", "/dev/scsi/sc0d6l0",
1634141cc406Sopenharmony_ci	"/dev/scsi/sc0d7l0", "/dev/scsi/sc0d8l0",
1635141cc406Sopenharmony_ci	"/dev/scsi/sc0d9l0", "/dev/scsi/sc0d10l0",
1636141cc406Sopenharmony_ci	"/dev/scsi/sc0d11l0", "/dev/scsi/sc0d12l0",
1637141cc406Sopenharmony_ci	"/dev/scsi/sc0d13l0", "/dev/scsi/sc0d14l0",
1638141cc406Sopenharmony_ci	"/dev/scsi/sc0d15l0",
1639141cc406Sopenharmony_ci	"/dev/scsi/sc1d1l0", "/dev/scsi/sc1d2l0",
1640141cc406Sopenharmony_ci	"/dev/scsi/sc1d3l0", "/dev/scsi/sc1d4l0",
1641141cc406Sopenharmony_ci	"/dev/scsi/sc1d5l0", "/dev/scsi/sc1d6l0",
1642141cc406Sopenharmony_ci	"/dev/scsi/sc1d7l0", "/dev/scsi/sc1d8l0",
1643141cc406Sopenharmony_ci	"/dev/scsi/sc1d9l0", "/dev/scsi/sc1d10l0",
1644141cc406Sopenharmony_ci	"/dev/scsi/sc1d11l0", "/dev/scsi/sc1d12l0",
1645141cc406Sopenharmony_ci	"/dev/scsi/sc1d13l0", "/dev/scsi/sc1d14l0",
1646141cc406Sopenharmony_ci	"/dev/scsi/sc1d15l0",
1647141cc406Sopenharmony_ci	"/dev/scsi/sc2d1l0", "/dev/scsi/sc2d2l0",
1648141cc406Sopenharmony_ci	"/dev/scsi/sc2d3l0", "/dev/scsi/sc2d4l0",
1649141cc406Sopenharmony_ci	"/dev/scsi/sc2d5l0", "/dev/scsi/sc2d6l0",
1650141cc406Sopenharmony_ci	"/dev/scsi/sc2d7l0", "/dev/scsi/sc2d8l0",
1651141cc406Sopenharmony_ci	"/dev/scsi/sc2d9l0", "/dev/scsi/sc2d10l0",
1652141cc406Sopenharmony_ci	"/dev/scsi/sc2d11l0", "/dev/scsi/sc2d12l0",
1653141cc406Sopenharmony_ci	"/dev/scsi/sc2d13l0", "/dev/scsi/sc2d14l0",
1654141cc406Sopenharmony_ci	"/dev/scsi/sc2d15l0",
1655141cc406Sopenharmony_ci	"/dev/scsi/sc3d1l0", "/dev/scsi/sc3d2l0",
1656141cc406Sopenharmony_ci	"/dev/scsi/sc3d3l0", "/dev/scsi/sc3d4l0",
1657141cc406Sopenharmony_ci	"/dev/scsi/sc3d5l0", "/dev/scsi/sc3d6l0",
1658141cc406Sopenharmony_ci	"/dev/scsi/sc3d7l0", "/dev/scsi/sc3d8l0",
1659141cc406Sopenharmony_ci	"/dev/scsi/sc3d9l0", "/dev/scsi/sc3d10l0",
1660141cc406Sopenharmony_ci	"/dev/scsi/sc3d11l0", "/dev/scsi/sc3d12l0",
1661141cc406Sopenharmony_ci	"/dev/scsi/sc3d13l0", "/dev/scsi/sc3d14l0",
1662141cc406Sopenharmony_ci	"/dev/scsi/sc3d15l0",
1663141cc406Sopenharmony_ci	"/dev/scsi/sc4d1l0", "/dev/scsi/sc4d2l0",
1664141cc406Sopenharmony_ci	"/dev/scsi/sc4d3l0", "/dev/scsi/sc4d4l0",
1665141cc406Sopenharmony_ci	"/dev/scsi/sc4d5l0", "/dev/scsi/sc4d6l0",
1666141cc406Sopenharmony_ci	"/dev/scsi/sc4d7l0", "/dev/scsi/sc4d8l0",
1667141cc406Sopenharmony_ci	"/dev/scsi/sc4d9l0", "/dev/scsi/sc4d10l0",
1668141cc406Sopenharmony_ci	"/dev/scsi/sc4d11l0", "/dev/scsi/sc4d12l0",
1669141cc406Sopenharmony_ci	"/dev/scsi/sc4d13l0", "/dev/scsi/sc4d14l0",
1670141cc406Sopenharmony_ci	"/dev/scsi/sc4d15l0",
1671141cc406Sopenharmony_ci	"/dev/scsi/sc5d1l0", "/dev/scsi/sc5d2l0",
1672141cc406Sopenharmony_ci	"/dev/scsi/sc5d3l0", "/dev/scsi/sc5d4l0",
1673141cc406Sopenharmony_ci	"/dev/scsi/sc5d5l0", "/dev/scsi/sc5d6l0",
1674141cc406Sopenharmony_ci	"/dev/scsi/sc5d7l0", "/dev/scsi/sc5d8l0",
1675141cc406Sopenharmony_ci	"/dev/scsi/sc5d9l0", "/dev/scsi/sc5d10l0",
1676141cc406Sopenharmony_ci	"/dev/scsi/sc5d11l0", "/dev/scsi/sc5d12l0",
1677141cc406Sopenharmony_ci	"/dev/scsi/sc5d13l0", "/dev/scsi/sc5d14l0",
1678141cc406Sopenharmony_ci	"/dev/scsi/sc5d15l0",
1679141cc406Sopenharmony_ci	"/dev/scsi/sc6d1l0", "/dev/scsi/sc6d2l0",
1680141cc406Sopenharmony_ci	"/dev/scsi/sc6d3l0", "/dev/scsi/sc6d4l0",
1681141cc406Sopenharmony_ci	"/dev/scsi/sc6d5l0", "/dev/scsi/sc6d6l0",
1682141cc406Sopenharmony_ci	"/dev/scsi/sc6d7l0", "/dev/scsi/sc6d8l0",
1683141cc406Sopenharmony_ci	"/dev/scsi/sc6d9l0", "/dev/scsi/sc6d10l0",
1684141cc406Sopenharmony_ci	"/dev/scsi/sc6d11l0", "/dev/scsi/sc6d12l0",
1685141cc406Sopenharmony_ci	"/dev/scsi/sc6d13l0", "/dev/scsi/sc6d14l0",
1686141cc406Sopenharmony_ci	"/dev/scsi/sc6d15l0",
1687141cc406Sopenharmony_ci	"/dev/scsi/sc7d1l0", "/dev/scsi/sc7d2l0",
1688141cc406Sopenharmony_ci	"/dev/scsi/sc7d3l0", "/dev/scsi/sc7d4l0",
1689141cc406Sopenharmony_ci	"/dev/scsi/sc7d5l0", "/dev/scsi/sc7d6l0",
1690141cc406Sopenharmony_ci	"/dev/scsi/sc7d7l0", "/dev/scsi/sc7d8l0",
1691141cc406Sopenharmony_ci	"/dev/scsi/sc7d9l0", "/dev/scsi/sc7d10l0",
1692141cc406Sopenharmony_ci	"/dev/scsi/sc7d11l0", "/dev/scsi/sc7d12l0",
1693141cc406Sopenharmony_ci	"/dev/scsi/sc7d13l0", "/dev/scsi/sc7d14l0",
1694141cc406Sopenharmony_ci	"/dev/scsi/sc7d15l0",
1695141cc406Sopenharmony_ci	"/dev/scsi/sc8d1l0", "/dev/scsi/sc8d2l0",
1696141cc406Sopenharmony_ci	"/dev/scsi/sc8d3l0", "/dev/scsi/sc8d4l0",
1697141cc406Sopenharmony_ci	"/dev/scsi/sc8d5l0", "/dev/scsi/sc8d6l0",
1698141cc406Sopenharmony_ci	"/dev/scsi/sc8d7l0", "/dev/scsi/sc8d8l0",
1699141cc406Sopenharmony_ci	"/dev/scsi/sc8d9l0", "/dev/scsi/sc8d10l0",
1700141cc406Sopenharmony_ci	"/dev/scsi/sc8d11l0", "/dev/scsi/sc8d12l0",
1701141cc406Sopenharmony_ci	"/dev/scsi/sc8d13l0", "/dev/scsi/sc8d14l0",
1702141cc406Sopenharmony_ci	"/dev/scsi/sc8d15l0",
1703141cc406Sopenharmony_ci	"/dev/scsi/sc9d1l0", "/dev/scsi/sc9d2l0",
1704141cc406Sopenharmony_ci	"/dev/scsi/sc9d3l0", "/dev/scsi/sc9d4l0",
1705141cc406Sopenharmony_ci	"/dev/scsi/sc9d5l0", "/dev/scsi/sc9d6l0",
1706141cc406Sopenharmony_ci	"/dev/scsi/sc9d7l0", "/dev/scsi/sc9d8l0",
1707141cc406Sopenharmony_ci	"/dev/scsi/sc9d9l0", "/dev/scsi/sc9d10l0",
1708141cc406Sopenharmony_ci	"/dev/scsi/sc9d11l0", "/dev/scsi/sc9d12l0",
1709141cc406Sopenharmony_ci	"/dev/scsi/sc9d13l0", "/dev/scsi/sc9d14l0",
1710141cc406Sopenharmony_ci	"/dev/scsi/sc9d15l0",
1711141cc406Sopenharmony_ci	"/dev/scsi/sc10d1l0", "/dev/scsi/sc10d2l0",
1712141cc406Sopenharmony_ci	"/dev/scsi/sc10d3l0", "/dev/scsi/sc10d4l0",
1713141cc406Sopenharmony_ci	"/dev/scsi/sc10d5l0", "/dev/scsi/sc10d6l0",
1714141cc406Sopenharmony_ci	"/dev/scsi/sc10d7l0", "/dev/scsi/sc10d8l0",
1715141cc406Sopenharmony_ci	"/dev/scsi/sc10d9l0", "/dev/scsi/sc10d10l0",
1716141cc406Sopenharmony_ci	"/dev/scsi/sc10d11l0", "/dev/scsi/sc10d12l0",
1717141cc406Sopenharmony_ci	"/dev/scsi/sc10d13l0", "/dev/scsi/sc10d14l0",
1718141cc406Sopenharmony_ci	"/dev/scsi/sc10d15l0",
1719141cc406Sopenharmony_ci	"/dev/scsi/sc11d1l0", "/dev/scsi/sc11d2l0",
1720141cc406Sopenharmony_ci	"/dev/scsi/sc11d3l0", "/dev/scsi/sc11d4l0",
1721141cc406Sopenharmony_ci	"/dev/scsi/sc11d5l0", "/dev/scsi/sc11d6l0",
1722141cc406Sopenharmony_ci	"/dev/scsi/sc11d7l0", "/dev/scsi/sc11d8l0",
1723141cc406Sopenharmony_ci	"/dev/scsi/sc11d9l0", "/dev/scsi/sc11d10l0",
1724141cc406Sopenharmony_ci	"/dev/scsi/sc11d11l0", "/dev/scsi/sc11d12l0",
1725141cc406Sopenharmony_ci	"/dev/scsi/sc11d13l0", "/dev/scsi/sc11d14l0",
1726141cc406Sopenharmony_ci	"/dev/scsi/sc11d15l0",
1727141cc406Sopenharmony_ci	"/dev/scsi/sc12d1l0", "/dev/scsi/sc12d2l0",
1728141cc406Sopenharmony_ci	"/dev/scsi/sc12d3l0", "/dev/scsi/sc12d4l0",
1729141cc406Sopenharmony_ci	"/dev/scsi/sc12d5l0", "/dev/scsi/sc12d6l0",
1730141cc406Sopenharmony_ci	"/dev/scsi/sc12d7l0", "/dev/scsi/sc12d8l0",
1731141cc406Sopenharmony_ci	"/dev/scsi/sc12d9l0", "/dev/scsi/sc12d10l0",
1732141cc406Sopenharmony_ci	"/dev/scsi/sc12d11l0", "/dev/scsi/sc12d12l0",
1733141cc406Sopenharmony_ci	"/dev/scsi/sc12d13l0", "/dev/scsi/sc12d14l0",
1734141cc406Sopenharmony_ci	"/dev/scsi/sc12d15l0",
1735141cc406Sopenharmony_ci	"/dev/scsi/sc13d1l0", "/dev/scsi/sc13d2l0",
1736141cc406Sopenharmony_ci	"/dev/scsi/sc13d3l0", "/dev/scsi/sc13d4l0",
1737141cc406Sopenharmony_ci	"/dev/scsi/sc13d5l0", "/dev/scsi/sc13d6l0",
1738141cc406Sopenharmony_ci	"/dev/scsi/sc13d7l0", "/dev/scsi/sc13d8l0",
1739141cc406Sopenharmony_ci	"/dev/scsi/sc13d9l0", "/dev/scsi/sc13d10l0",
1740141cc406Sopenharmony_ci	"/dev/scsi/sc13d11l0", "/dev/scsi/sc13d12l0",
1741141cc406Sopenharmony_ci	"/dev/scsi/sc13d13l0", "/dev/scsi/sc13d14l0",
1742141cc406Sopenharmony_ci	"/dev/scsi/sc13d15l0",
1743141cc406Sopenharmony_ci	"/dev/scsi/sc14d1l0", "/dev/scsi/sc14d2l0",
1744141cc406Sopenharmony_ci	"/dev/scsi/sc14d3l0", "/dev/scsi/sc14d4l0",
1745141cc406Sopenharmony_ci	"/dev/scsi/sc14d5l0", "/dev/scsi/sc14d6l0",
1746141cc406Sopenharmony_ci	"/dev/scsi/sc14d7l0", "/dev/scsi/sc14d8l0",
1747141cc406Sopenharmony_ci	"/dev/scsi/sc14d9l0", "/dev/scsi/sc14d10l0",
1748141cc406Sopenharmony_ci	"/dev/scsi/sc14d11l0", "/dev/scsi/sc14d12l0",
1749141cc406Sopenharmony_ci	"/dev/scsi/sc14d13l0", "/dev/scsi/sc14d14l0",
1750141cc406Sopenharmony_ci	"/dev/scsi/sc14d15l0",
1751141cc406Sopenharmony_ci	"/dev/scsi/sc15d1l0", "/dev/scsi/sc15d2l0",
1752141cc406Sopenharmony_ci	"/dev/scsi/sc15d3l0", "/dev/scsi/sc15d4l0",
1753141cc406Sopenharmony_ci	"/dev/scsi/sc15d5l0", "/dev/scsi/sc15d6l0",
1754141cc406Sopenharmony_ci	"/dev/scsi/sc15d7l0", "/dev/scsi/sc15d8l0",
1755141cc406Sopenharmony_ci	"/dev/scsi/sc15d9l0", "/dev/scsi/sc15d10l0",
1756141cc406Sopenharmony_ci	"/dev/scsi/sc15d11l0", "/dev/scsi/sc15d12l0",
1757141cc406Sopenharmony_ci	"/dev/scsi/sc15d13l0", "/dev/scsi/sc15d14l0",
1758141cc406Sopenharmony_ci	"/dev/scsi/sc15d15l0",
1759141cc406Sopenharmony_ci#elif defined(__EMX__)
1760141cc406Sopenharmony_ci	"b0t0l0", "b0t1l0", "b0t2l0", "b0t3l0",
1761141cc406Sopenharmony_ci	"b0t4l0", "b0t5l0", "b0t6l0", "b0t7l0",
1762141cc406Sopenharmony_ci	"b1t0l0", "b1t1l0", "b1t2l0", "b1t3l0",
1763141cc406Sopenharmony_ci	"b1t4l0", "b1t5l0", "b1t6l0", "b1t7l0",
1764141cc406Sopenharmony_ci	"b2t0l0", "b2t1l0", "b2t2l0", "b2t3l0",
1765141cc406Sopenharmony_ci	"b2t4l0", "b2t5l0", "b2t6l0", "b2t7l0",
1766141cc406Sopenharmony_ci	"b3t0l0", "b3t1l0", "b3t2l0", "b3t3l0",
1767141cc406Sopenharmony_ci	"b3t4l0", "b3t5l0", "b3t6l0", "b3t7l0",
1768141cc406Sopenharmony_ci#elif defined(__linux__)
1769141cc406Sopenharmony_ci	"/dev/scanner",
1770141cc406Sopenharmony_ci	"/dev/sg0", "/dev/sg1", "/dev/sg2", "/dev/sg3",
1771141cc406Sopenharmony_ci	"/dev/sg4", "/dev/sg5", "/dev/sg6", "/dev/sg7",
1772141cc406Sopenharmony_ci	"/dev/sg8", "/dev/sg9",
1773141cc406Sopenharmony_ci	"/dev/sga", "/dev/sgb", "/dev/sgc", "/dev/sgd",
1774141cc406Sopenharmony_ci	"/dev/sge", "/dev/sgf", "/dev/sgg", "/dev/sgh",
1775141cc406Sopenharmony_ci	"/dev/sgi", "/dev/sgj", "/dev/sgk", "/dev/sgl",
1776141cc406Sopenharmony_ci	"/dev/sgm", "/dev/sgn", "/dev/sgo", "/dev/sgp",
1777141cc406Sopenharmony_ci	"/dev/sgq", "/dev/sgr", "/dev/sgs", "/dev/sgt",
1778141cc406Sopenharmony_ci	"/dev/sgu", "/dev/sgv", "/dev/sgw", "/dev/sgx",
1779141cc406Sopenharmony_ci	"/dev/sgy", "/dev/sgz",
1780141cc406Sopenharmony_ci#elif defined(__NeXT__)
1781141cc406Sopenharmony_ci	"/dev/sg0a", "/dev/sg0b", "/dev/sg0c", "/dev/sg0d",
1782141cc406Sopenharmony_ci	"/dev/sg0e", "/dev/sg0f", "/dev/sg0g", "/dev/sg0h",
1783141cc406Sopenharmony_ci	"/dev/sg1a", "/dev/sg1b", "/dev/sg1c", "/dev/sg1d",
1784141cc406Sopenharmony_ci	"/dev/sg1e", "/dev/sg1f", "/dev/sg1g", "/dev/sg1h",
1785141cc406Sopenharmony_ci	"/dev/sg2a", "/dev/sg2b", "/dev/sg2c", "/dev/sg2d",
1786141cc406Sopenharmony_ci	"/dev/sg2e", "/dev/sg2f", "/dev/sg2g", "/dev/sg2h",
1787141cc406Sopenharmony_ci	"/dev/sg3a", "/dev/sg3b", "/dev/sg3c", "/dev/sg3d",
1788141cc406Sopenharmony_ci	"/dev/sg3e", "/dev/sg3f", "/dev/sg3g", "/dev/sg3h",
1789141cc406Sopenharmony_ci#elif defined(_AIX)
1790141cc406Sopenharmony_ci	"/dev/scanner",
1791141cc406Sopenharmony_ci	"/dev/gsc0", "/dev/gsc1", "/dev/gsc2", "/dev/gsc3",
1792141cc406Sopenharmony_ci	"/dev/gsc4", "/dev/gsc5", "/dev/gsc6", "/dev/gsc7",
1793141cc406Sopenharmony_ci	"/dev/gsc8", "/dev/gsc9", "/dev/gsc10", "/dev/gsc11",
1794141cc406Sopenharmony_ci	"/dev/gsc12", "/dev/gsc13", "/dev/gsc14", "/dev/gsc15",
1795141cc406Sopenharmony_ci#elif defined(__sun)
1796141cc406Sopenharmony_ci	"/dev/scg0a", "/dev/scg0b", "/dev/scg0c", "/dev/scg0d",
1797141cc406Sopenharmony_ci	"/dev/scg0e", "/dev/scg0f", "/dev/scg0g",
1798141cc406Sopenharmony_ci	"/dev/scg1a", "/dev/scg1b", "/dev/scg1c", "/dev/scg1d",
1799141cc406Sopenharmony_ci	"/dev/scg1e", "/dev/scg1f", "/dev/scg1g",
1800141cc406Sopenharmony_ci	"/dev/scg2a", "/dev/scg2b", "/dev/scg2c", "/dev/scg2d",
1801141cc406Sopenharmony_ci	"/dev/scg2e", "/dev/scg2f", "/dev/scg2g",
1802141cc406Sopenharmony_ci	"/dev/sg/0", "/dev/sg/1", "/dev/sg/2", "/dev/sg/3",
1803141cc406Sopenharmony_ci	"/dev/sg/4", "/dev/sg/5", "/dev/sg/6",
1804141cc406Sopenharmony_ci	"/dev/scsi/scanner/", "/dev/scsi/processor/",
1805141cc406Sopenharmony_ci#elif defined(HAVE_CAMLIB_H)
1806141cc406Sopenharmony_ci	"/dev/scanner", "/dev/scanner0", "/dev/scanner1",
1807141cc406Sopenharmony_ci	"/dev/pass0", "/dev/pass1", "/dev/pass2", "/dev/pass3",
1808141cc406Sopenharmony_ci	"/dev/pass4", "/dev/pass5", "/dev/pass6", "/dev/pass7",
1809141cc406Sopenharmony_ci#elif defined(__FreeBSD__) || defined(__DragonFly__)
1810141cc406Sopenharmony_ci	"/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
1811141cc406Sopenharmony_ci	"/dev/uk5", "/dev/uk6",
1812141cc406Sopenharmony_ci#elif defined(__NetBSD__)
1813141cc406Sopenharmony_ci	"/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
1814141cc406Sopenharmony_ci	"/dev/uk5", "/dev/uk6",
1815141cc406Sopenharmony_ci	"/dev/ss0",
1816141cc406Sopenharmony_ci#elif defined(__OpenBSD__)
1817141cc406Sopenharmony_ci	"/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
1818141cc406Sopenharmony_ci	"/dev/uk5", "/dev/uk6",
1819141cc406Sopenharmony_ci#elif defined(__hpux)
1820141cc406Sopenharmony_ci	"/dev/rscsi/",
1821141cc406Sopenharmony_ci#endif
1822141cc406Sopenharmony_ci	0
1823141cc406Sopenharmony_ci      };
1824141cc406Sopenharmony_ci      static char *usb_default_dev_list[] = {
1825141cc406Sopenharmony_ci#if defined(__linux__)
1826141cc406Sopenharmony_ci	"/dev/usb/scanner",
1827141cc406Sopenharmony_ci	"/dev/usb/scanner0", "/dev/usb/scanner1",
1828141cc406Sopenharmony_ci	"/dev/usb/scanner2", "/dev/usb/scanner3",
1829141cc406Sopenharmony_ci	"/dev/usb/scanner4", "/dev/usb/scanner5",
1830141cc406Sopenharmony_ci	"/dev/usb/scanner5", "/dev/usb/scanner7",
1831141cc406Sopenharmony_ci	"/dev/usb/scanner8", "/dev/usb/scanner9",
1832141cc406Sopenharmony_ci	"/dev/usb/scanner10", "/dev/usb/scanner11",
1833141cc406Sopenharmony_ci	"/dev/usb/scanner12", "/dev/usb/scanner13",
1834141cc406Sopenharmony_ci	"/dev/usb/scanner14", "/dev/usb/scanner15",
1835141cc406Sopenharmony_ci	"/dev/usbscanner",
1836141cc406Sopenharmony_ci	"/dev/usbscanner0", "/dev/usbscanner1",
1837141cc406Sopenharmony_ci	"/dev/usbscanner2", "/dev/usbscanner3",
1838141cc406Sopenharmony_ci	"/dev/usbscanner4", "/dev/usbscanner5",
1839141cc406Sopenharmony_ci	"/dev/usbscanner6", "/dev/usbscanner7",
1840141cc406Sopenharmony_ci	"/dev/usbscanner8", "/dev/usbscanner9",
1841141cc406Sopenharmony_ci	"/dev/usbscanner10", "/dev/usbscanner11",
1842141cc406Sopenharmony_ci	"/dev/usbscanner12", "/dev/usbscanner13",
1843141cc406Sopenharmony_ci	"/dev/usbscanner14", "/dev/usbscanner15",
1844141cc406Sopenharmony_ci#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1845141cc406Sopenharmony_ci	"/dev/uscanner",
1846141cc406Sopenharmony_ci	"/dev/uscanner0", "/dev/uscanner1",
1847141cc406Sopenharmony_ci	"/dev/uscanner2", "/dev/uscanner3",
1848141cc406Sopenharmony_ci	"/dev/uscanner4", "/dev/uscanner5",
1849141cc406Sopenharmony_ci	"/dev/uscanner6", "/dev/uscanner7",
1850141cc406Sopenharmony_ci	"/dev/uscanner8", "/dev/uscanner9",
1851141cc406Sopenharmony_ci	"/dev/uscanner10", "/dev/uscanner11",
1852141cc406Sopenharmony_ci	"/dev/uscanner12", "/dev/uscanner13",
1853141cc406Sopenharmony_ci	"/dev/uscanner14", "/dev/uscanner15",
1854141cc406Sopenharmony_ci#endif
1855141cc406Sopenharmony_ci	0
1856141cc406Sopenharmony_ci      };
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci#if defined (WIN32_SCSI) || \
1859141cc406Sopenharmony_ci    defined (HAVE_IOKIT_CDB_IOSCSILIB_H) || \
1860141cc406Sopenharmony_ci    defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
1861141cc406Sopenharmony_ci    defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
1862141cc406Sopenharmony_ci   /* Build a list of valid of possible scanners found */
1863141cc406Sopenharmony_ci      dev_list = build_scsi_dev_list();
1864141cc406Sopenharmony_ci#else
1865141cc406Sopenharmony_ci      dev_list = default_dev_list;
1866141cc406Sopenharmony_ci#endif
1867141cc406Sopenharmony_ci
1868141cc406Sopenharmony_ci      usb_dev_list = usb_default_dev_list;
1869141cc406Sopenharmony_ci    }
1870141cc406Sopenharmony_ci  if (verbose > 1)
1871141cc406Sopenharmony_ci    printf ("This is sane-find-scanner from %s\n", PACKAGE_STRING);
1872141cc406Sopenharmony_ci
1873141cc406Sopenharmony_ci  if (verbose > 0)
1874141cc406Sopenharmony_ci    printf ("\n  # sane-find-scanner will now attempt to detect your scanner. If the"
1875141cc406Sopenharmony_ci	    "\n  # result is different from what you expected, first make sure your"
1876141cc406Sopenharmony_ci	    "\n  # scanner is powered up and properly connected to your computer.\n\n");
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_ci  if (verbose > 1)
1879141cc406Sopenharmony_ci    printf ("searching for SCSI scanners:\n");
1880141cc406Sopenharmony_ci
1881141cc406Sopenharmony_ci  while ((dev_name = *dev_list++))
1882141cc406Sopenharmony_ci    {
1883141cc406Sopenharmony_ci      if (strlen (dev_name) == 0)
1884141cc406Sopenharmony_ci	continue;		/* Empty device names ... */
1885141cc406Sopenharmony_ci
1886141cc406Sopenharmony_ci      if (dev_name[strlen (dev_name) - 1] == '/')
1887141cc406Sopenharmony_ci	{
1888141cc406Sopenharmony_ci	  /* check whole directories */
1889141cc406Sopenharmony_ci	  DIR *dir;
1890141cc406Sopenharmony_ci	  char *file_name;
1891141cc406Sopenharmony_ci
1892141cc406Sopenharmony_ci	  dir = scan_directory (dev_name);
1893141cc406Sopenharmony_ci	  if (!dir)
1894141cc406Sopenharmony_ci	    continue;
1895141cc406Sopenharmony_ci
1896141cc406Sopenharmony_ci	  while ((file_name = get_next_file (dev_name, dir)))
1897141cc406Sopenharmony_ci	    check_scsi_file (file_name);
1898141cc406Sopenharmony_ci	}
1899141cc406Sopenharmony_ci      else
1900141cc406Sopenharmony_ci	{
1901141cc406Sopenharmony_ci	  /* check device files */
1902141cc406Sopenharmony_ci	  check_scsi_file (dev_name);
1903141cc406Sopenharmony_ci	}
1904141cc406Sopenharmony_ci    }
1905141cc406Sopenharmony_ci  if (device_found)
1906141cc406Sopenharmony_ci    {
1907141cc406Sopenharmony_ci      if (verbose > 0)
1908141cc406Sopenharmony_ci	printf
1909141cc406Sopenharmony_ci	  ("  # Your SCSI scanner was detected. It may or may not be "
1910141cc406Sopenharmony_ci	   "supported by SANE. Try\n  # scanimage -L and read the backend's "
1911141cc406Sopenharmony_ci	   "manpage.\n");
1912141cc406Sopenharmony_ci    }
1913141cc406Sopenharmony_ci  else
1914141cc406Sopenharmony_ci    {
1915141cc406Sopenharmony_ci      if (verbose > 0)
1916141cc406Sopenharmony_ci	printf
1917141cc406Sopenharmony_ci	  ("  # No SCSI scanners found. If you expected something different, "
1918141cc406Sopenharmony_ci	   "make sure that\n  # you have loaded a kernel SCSI driver for your SCSI "
1919141cc406Sopenharmony_ci	   "adapter.\n");
1920141cc406Sopenharmony_ci      if (!check_sg ())
1921141cc406Sopenharmony_ci	{
1922141cc406Sopenharmony_ci	  if (verbose > 0)
1923141cc406Sopenharmony_ci	    printf
1924141cc406Sopenharmony_ci	      ("  # Also you need support for SCSI Generic (sg) in your "
1925141cc406Sopenharmony_ci	       "operating system.\n  # If using Linux, try \"modprobe "
1926141cc406Sopenharmony_ci	       "sg\".\n");
1927141cc406Sopenharmony_ci	}
1928141cc406Sopenharmony_ci    }
1929141cc406Sopenharmony_ci  if (verbose > 0)
1930141cc406Sopenharmony_ci    printf ("\n");
1931141cc406Sopenharmony_ci  device_found = SANE_FALSE;
1932141cc406Sopenharmony_ci  sanei_usb_init ();
1933141cc406Sopenharmony_ci  if (verbose > 1)
1934141cc406Sopenharmony_ci    printf ("searching for USB scanners:\n");
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci  while ((dev_name = *usb_dev_list++))
1937141cc406Sopenharmony_ci    {
1938141cc406Sopenharmony_ci      if (strlen (dev_name) == 0)
1939141cc406Sopenharmony_ci	continue;		/* Empty device names ... */
1940141cc406Sopenharmony_ci
1941141cc406Sopenharmony_ci      if (dev_name[strlen (dev_name) - 1] == '/')
1942141cc406Sopenharmony_ci	{
1943141cc406Sopenharmony_ci	  /* check whole directories */
1944141cc406Sopenharmony_ci	  DIR *dir;
1945141cc406Sopenharmony_ci	  char *file_name;
1946141cc406Sopenharmony_ci
1947141cc406Sopenharmony_ci	  dir = scan_directory (dev_name);
1948141cc406Sopenharmony_ci	  if (!dir)
1949141cc406Sopenharmony_ci	    continue;
1950141cc406Sopenharmony_ci
1951141cc406Sopenharmony_ci	  while ((file_name = get_next_file (dev_name, dir)))
1952141cc406Sopenharmony_ci	    check_usb_file (file_name);
1953141cc406Sopenharmony_ci	}
1954141cc406Sopenharmony_ci      else
1955141cc406Sopenharmony_ci	{
1956141cc406Sopenharmony_ci	  /* check device files */
1957141cc406Sopenharmony_ci	  check_usb_file (dev_name);
1958141cc406Sopenharmony_ci	}
1959141cc406Sopenharmony_ci    }
1960141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY
1961141cc406Sopenharmony_ci  /* Now the libusb devices */
1962141cc406Sopenharmony_ci  {
1963141cc406Sopenharmony_ci    struct usb_bus *bus;
1964141cc406Sopenharmony_ci    struct usb_device *dev;
1965141cc406Sopenharmony_ci
1966141cc406Sopenharmony_ci    if (ap < argv + argc)
1967141cc406Sopenharmony_ci      {
1968141cc406Sopenharmony_ci	/* user-specified devices not useful for libusb */
1969141cc406Sopenharmony_ci	if (verbose > 1)
1970141cc406Sopenharmony_ci	  printf ("ignoring libusb devices\n");
1971141cc406Sopenharmony_ci      }
1972141cc406Sopenharmony_ci    else
1973141cc406Sopenharmony_ci      {
1974141cc406Sopenharmony_ci	if (verbose > 2)
1975141cc406Sopenharmony_ci	  printf ("trying libusb:\n");
1976141cc406Sopenharmony_ci	for (bus = usb_get_busses (); bus; bus = bus->next)
1977141cc406Sopenharmony_ci	  {
1978141cc406Sopenharmony_ci	    for (dev = bus->devices; dev; dev = dev->next)
1979141cc406Sopenharmony_ci	      {
1980141cc406Sopenharmony_ci		check_libusb_device (dev, SANE_FALSE);
1981141cc406Sopenharmony_ci	      }			/* for (dev) */
1982141cc406Sopenharmony_ci	  }			/* for (bus) */
1983141cc406Sopenharmony_ci      }
1984141cc406Sopenharmony_ci  }
1985141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB)
1986141cc406Sopenharmony_ci  /* Now the libusb-1.0 devices */
1987141cc406Sopenharmony_ci  {
1988141cc406Sopenharmony_ci    if (ap < argv + argc)
1989141cc406Sopenharmony_ci      {
1990141cc406Sopenharmony_ci	/* user-specified devices not useful for libusb */
1991141cc406Sopenharmony_ci	if (verbose > 1)
1992141cc406Sopenharmony_ci	  printf ("ignoring libusb devices\n");
1993141cc406Sopenharmony_ci      }
1994141cc406Sopenharmony_ci    else
1995141cc406Sopenharmony_ci      {
1996141cc406Sopenharmony_ci	libusb_device **devlist;
1997141cc406Sopenharmony_ci	ssize_t devcnt;
1998141cc406Sopenharmony_ci	int i;
1999141cc406Sopenharmony_ci	int ret;
2000141cc406Sopenharmony_ci
2001141cc406Sopenharmony_ci	if (verbose > 2)
2002141cc406Sopenharmony_ci	  printf ("trying libusb:\n");
2003141cc406Sopenharmony_ci
2004141cc406Sopenharmony_ci	ret = libusb_init (&sfs_usb_ctx);
2005141cc406Sopenharmony_ci	if (ret < 0)
2006141cc406Sopenharmony_ci	  {
2007141cc406Sopenharmony_ci	    printf ("# Could not initialize libusb-1.0, error %d\n", ret);
2008141cc406Sopenharmony_ci	    printf ("# Skipping libusb devices\n");
2009141cc406Sopenharmony_ci
2010141cc406Sopenharmony_ci	    goto failed_libusb_1_0;
2011141cc406Sopenharmony_ci	  }
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci	if (verbose > 3)
2014141cc406Sopenharmony_ci#if LIBUSB_API_VERSION >= 0x01000106
2015141cc406Sopenharmony_ci          libusb_set_option (sfs_usb_ctx, LIBUSB_OPTION_LOG_LEVEL,
2016141cc406Sopenharmony_ci                             LIBUSB_LOG_LEVEL_INFO);
2017141cc406Sopenharmony_ci#else
2018141cc406Sopenharmony_ci	  libusb_set_debug (sfs_usb_ctx, 3);
2019141cc406Sopenharmony_ci#endif
2020141cc406Sopenharmony_ci
2021141cc406Sopenharmony_ci	devcnt = libusb_get_device_list (sfs_usb_ctx, &devlist);
2022141cc406Sopenharmony_ci	if (devcnt < 0)
2023141cc406Sopenharmony_ci	  {
2024141cc406Sopenharmony_ci	    printf ("# Could not get device list, error %d\n", ret);
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci	    goto deinit_libusb_1_0;
2027141cc406Sopenharmony_ci	  }
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_ci	for (i = 0; i < devcnt; i++)
2030141cc406Sopenharmony_ci	  {
2031141cc406Sopenharmony_ci	    check_libusb_device (devlist[i], SANE_FALSE);
2032141cc406Sopenharmony_ci	  }
2033141cc406Sopenharmony_ci
2034141cc406Sopenharmony_ci	libusb_free_device_list (devlist, 1);
2035141cc406Sopenharmony_ci
2036141cc406Sopenharmony_ci      deinit_libusb_1_0:
2037141cc406Sopenharmony_ci	libusb_exit (sfs_usb_ctx);
2038141cc406Sopenharmony_ci
2039141cc406Sopenharmony_ci      failed_libusb_1_0:
2040141cc406Sopenharmony_ci	; /* init failed, jumping here */
2041141cc406Sopenharmony_ci      }
2042141cc406Sopenharmony_ci  }
2043141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */
2044141cc406Sopenharmony_ci  if (verbose > 1)
2045141cc406Sopenharmony_ci    printf ("libusb not available\n");
2046141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */
2047141cc406Sopenharmony_ci
2048141cc406Sopenharmony_ci  if (device_found)
2049141cc406Sopenharmony_ci    {
2050141cc406Sopenharmony_ci      if (libusb_device_found)
2051141cc406Sopenharmony_ci	{
2052141cc406Sopenharmony_ci	  if (verbose > 0)
2053141cc406Sopenharmony_ci	    printf
2054141cc406Sopenharmony_ci	      ("  # Your USB scanner was (probably) detected. It "
2055141cc406Sopenharmony_ci	       "may or may not be supported by\n  # SANE. Try scanimage "
2056141cc406Sopenharmony_ci	       "-L and read the backend's manpage.\n");
2057141cc406Sopenharmony_ci	}
2058141cc406Sopenharmony_ci      else if (verbose > 0)
2059141cc406Sopenharmony_ci	printf
2060141cc406Sopenharmony_ci	  ("  # Your USB scanner was detected. It may or may not "
2061141cc406Sopenharmony_ci	   "be supported by\n  # SANE. Try scanimage -L and read the "
2062141cc406Sopenharmony_ci	   "backend's manpage.\n");
2063141cc406Sopenharmony_ci      if (unknown_found && verbose > 0)
2064141cc406Sopenharmony_ci	printf
2065141cc406Sopenharmony_ci	  ("  # `UNKNOWN vendor and product' means that there seems to be a "
2066141cc406Sopenharmony_ci	   "scanner at this\n  # device file but the vendor and product ids "
2067141cc406Sopenharmony_ci	   "couldn't be identified.\n  # Currently identification only works "
2068141cc406Sopenharmony_ci	   "with Linux versions >= 2.4.8. You may\n  # need to configure your "
2069141cc406Sopenharmony_ci	   "backend manually, see the backend's manpage.\n");
2070141cc406Sopenharmony_ci    }
2071141cc406Sopenharmony_ci  else
2072141cc406Sopenharmony_ci    {
2073141cc406Sopenharmony_ci      if (verbose > 0)
2074141cc406Sopenharmony_ci	printf
2075141cc406Sopenharmony_ci	  ("  # No USB scanners found. If you expected something different, "
2076141cc406Sopenharmony_ci	   "make sure that\n  # you have loaded a kernel driver for your USB host "
2077141cc406Sopenharmony_ci	   "controller and have setup\n  # the USB system correctly. "
2078141cc406Sopenharmony_ci	   "See man sane-usb for details.\n");
2079141cc406Sopenharmony_ci#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB)
2080141cc406Sopenharmony_ci      if (verbose > 0)
2081141cc406Sopenharmony_ci	printf ("  # SANE has been built without libusb support. This may be a "
2082141cc406Sopenharmony_ci		"reason\n  # for not detecting USB scanners. Read README for "
2083141cc406Sopenharmony_ci		"more details.\n");
2084141cc406Sopenharmony_ci#endif
2085141cc406Sopenharmony_ci    }
2086141cc406Sopenharmony_ci  if (enable_pp_checks == SANE_TRUE)
2087141cc406Sopenharmony_ci    {
2088141cc406Sopenharmony_ci      if (!check_mustek_pp_device() && verbose > 0)
2089141cc406Sopenharmony_ci        printf ("\n  # No Mustek parallel port scanners found. If you expected"
2090141cc406Sopenharmony_ci                " something\n  # different, make sure the scanner is correctly"
2091141cc406Sopenharmony_ci	        " connected to your computer\n  # and you have appropriate"
2092141cc406Sopenharmony_ci	        " access rights.\n");
2093141cc406Sopenharmony_ci    }
2094141cc406Sopenharmony_ci  else if (verbose > 0)
2095141cc406Sopenharmony_ci    printf ("\n  # Not checking for parallel port scanners.\n");
2096141cc406Sopenharmony_ci  if (verbose > 0)
2097141cc406Sopenharmony_ci    printf ("\n  # Most Scanners connected to the parallel port or other "
2098141cc406Sopenharmony_ci	    "proprietary ports\n  # can't be detected by this program.\n");
2099141cc406Sopenharmony_ci#ifdef HAVE_GETUID
2100141cc406Sopenharmony_ci  if (getuid ())
2101141cc406Sopenharmony_ci    if (verbose > 0)
2102141cc406Sopenharmony_ci      printf
2103141cc406Sopenharmony_ci	("\n  # You may want to run this program as root to find all devices. "
2104141cc406Sopenharmony_ci	 "Once you\n  # found the scanner devices, be sure to adjust access "
2105141cc406Sopenharmony_ci	 "permissions as\n  # necessary.\n");
2106141cc406Sopenharmony_ci#endif
2107141cc406Sopenharmony_ci
2108141cc406Sopenharmony_ci  if (verbose > 1)
2109141cc406Sopenharmony_ci    printf ("done\n");
2110141cc406Sopenharmony_ci
2111141cc406Sopenharmony_ci  return 0;
2112141cc406Sopenharmony_ci}
2113