2001-08-11 13:12:39 +00:00
|
|
|
/* sane - Scanner Access Now Easy.
|
2005-07-15 09:02:02 +00:00
|
|
|
Copyright (C) 2003 Rene Rebe (sanei_read_int,sanei_set_timeout)
|
2005-09-23 12:52:35 +00:00
|
|
|
Copyright (C) 2001 - 2005 Henning Meier-Geinitz
|
2002-01-03 19:18:27 +00:00
|
|
|
Copyright (C) 2001 Frank Zago (sanei_usb_control_msg)
|
2005-08-07 14:26:33 +00:00
|
|
|
Copyright (C) 2005 Paul Smedley <paul@smedley.info> (OS/2 usbcalls)
|
2001-08-11 13:12:39 +00:00
|
|
|
This file is part of the SANE package.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
|
|
MA 02111-1307, USA.
|
|
|
|
|
|
|
|
As a special exception, the authors of SANE give permission for
|
|
|
|
additional uses of the libraries contained in this release of SANE.
|
|
|
|
|
|
|
|
The exception is that, if you link a SANE library with other files
|
|
|
|
to produce an executable, this does not by itself cause the
|
|
|
|
resulting executable to be covered by the GNU General Public
|
|
|
|
License. Your use of that executable is in no way restricted on
|
|
|
|
account of linking the SANE library code into it.
|
|
|
|
|
|
|
|
This exception does not, however, invalidate any other reasons why
|
|
|
|
the executable file might be covered by the GNU General Public
|
|
|
|
License.
|
|
|
|
|
|
|
|
If you submit changes to SANE to the maintainers to be included in
|
|
|
|
a subsequent release, you agree by submitting the changes that
|
|
|
|
those changes may be distributed with this exception intact.
|
|
|
|
|
|
|
|
If you write modifications of your own for SANE, it is your choice
|
|
|
|
whether to permit this exception to apply to your modifications.
|
|
|
|
If you do not wish that, delete this exception notice.
|
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
This file provides a generic USB interface. */
|
2001-08-11 13:12:39 +00:00
|
|
|
|
|
|
|
#include "../include/sane/config.h"
|
|
|
|
|
2001-09-05 19:48:24 +00:00
|
|
|
#include <stdlib.h>
|
2001-08-11 13:12:39 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <stdio.h>
|
2003-01-22 16:54:14 +00:00
|
|
|
#include <dirent.h>
|
2008-04-28 00:48:48 +00:00
|
|
|
#include <time.h>
|
2001-08-11 13:12:39 +00:00
|
|
|
|
2004-07-26 15:15:39 +00:00
|
|
|
#ifdef HAVE_RESMGR
|
|
|
|
#include <resmgr.h>
|
|
|
|
#endif
|
2002-07-03 14:07:44 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
#include <usb.h>
|
|
|
|
#endif /* HAVE_LIBUSB */
|
|
|
|
|
2005-08-07 14:26:33 +00:00
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
#include <usb.h>
|
|
|
|
#include <os2.h>
|
|
|
|
#include <usbcalls.h>
|
|
|
|
#define MAX_RW 64000
|
|
|
|
static int usbcalls_timeout = 30 * 1000; /* 30 seconds */
|
|
|
|
USBHANDLE dh;
|
2005-08-09 16:28:38 +00:00
|
|
|
PHEV pUsbIrqStartHev=NULL;
|
2005-08-07 14:26:33 +00:00
|
|
|
|
|
|
|
static
|
|
|
|
struct usb_descriptor_header *GetNextDescriptor( struct usb_descriptor_header *currHead, UCHAR *lastBytePtr)
|
|
|
|
{
|
|
|
|
UCHAR *currBytePtr, *nextBytePtr;
|
|
|
|
|
|
|
|
if (!currHead->bLength)
|
|
|
|
return (NULL);
|
|
|
|
currBytePtr=(UCHAR *)currHead;
|
|
|
|
nextBytePtr=currBytePtr+currHead->bLength;
|
|
|
|
if (nextBytePtr>=lastBytePtr)
|
|
|
|
return (NULL);
|
|
|
|
return ((struct usb_descriptor_header*)nextBytePtr);
|
|
|
|
}
|
|
|
|
#endif /* HAVE_USBCALLS */
|
|
|
|
|
2006-03-11 12:56:34 +00:00
|
|
|
#if defined (__FreeBSD__)
|
2005-11-01 20:57:03 +00:00
|
|
|
#include <dev/usb/usb.h>
|
|
|
|
#endif /* __FreeBSD__ */
|
2006-03-11 12:56:34 +00:00
|
|
|
#if defined (__DragonFly__)
|
|
|
|
#include <bus/usb/usb.h>
|
|
|
|
#endif
|
2005-11-01 20:57:03 +00:00
|
|
|
|
2001-08-11 13:12:39 +00:00
|
|
|
#define BACKEND_NAME sanei_usb
|
|
|
|
#include "../include/sane/sane.h"
|
|
|
|
#include "../include/sane/sanei_debug.h"
|
|
|
|
#include "../include/sane/sanei_usb.h"
|
2001-09-05 19:48:24 +00:00
|
|
|
#include "../include/sane/sanei_config.h"
|
2001-08-11 13:12:39 +00:00
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
sanei_usb_method_scanner_driver = 0, /* kernel scanner driver
|
|
|
|
(Linux, BSD) */
|
2005-08-07 14:26:33 +00:00
|
|
|
sanei_usb_method_libusb,
|
|
|
|
|
|
|
|
sanei_usb_method_usbcalls
|
2002-07-03 14:07:44 +00:00
|
|
|
}
|
|
|
|
sanei_usb_access_method_type;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
SANE_Bool open;
|
|
|
|
sanei_usb_access_method_type method;
|
|
|
|
int fd;
|
2002-07-14 16:31:14 +00:00
|
|
|
SANE_String devname;
|
2003-01-22 16:54:14 +00:00
|
|
|
SANE_Int vendor;
|
|
|
|
SANE_Int product;
|
2002-07-03 14:07:44 +00:00
|
|
|
SANE_Int bulk_in_ep;
|
|
|
|
SANE_Int bulk_out_ep;
|
2005-04-15 20:48:24 +00:00
|
|
|
SANE_Int iso_in_ep;
|
|
|
|
SANE_Int iso_out_ep;
|
2003-03-24 01:36:27 +00:00
|
|
|
SANE_Int int_in_ep;
|
|
|
|
SANE_Int int_out_ep;
|
2005-04-15 20:48:24 +00:00
|
|
|
SANE_Int control_in_ep;
|
|
|
|
SANE_Int control_out_ep;
|
2002-12-30 13:51:10 +00:00
|
|
|
SANE_Int interface_nr;
|
2002-07-03 14:07:44 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
usb_dev_handle *libusb_handle;
|
2003-01-22 16:54:14 +00:00
|
|
|
struct usb_device *libusb_device;
|
2005-04-15 20:48:24 +00:00
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
#endif /* HAVE_LIBUSB */
|
|
|
|
}
|
|
|
|
device_list_type;
|
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
/* total number of devices that can be opened at the same time */
|
2002-07-03 14:07:44 +00:00
|
|
|
#define MAX_DEVICES 100
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
/* per-device information, using the functions' parameters dn as index */
|
2002-07-03 14:07:44 +00:00
|
|
|
static device_list_type devices[MAX_DEVICES];
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBUSB
|
2005-07-15 18:16:35 +00:00
|
|
|
static int libusb_timeout = 30 * 1000; /* 30 seconds */
|
2002-07-03 14:07:44 +00:00
|
|
|
#endif /* HAVE_LIBUSB */
|
2002-01-03 19:18:27 +00:00
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
#if defined (__linux__)
|
2002-01-03 19:18:27 +00:00
|
|
|
/* From /usr/src/linux/driver/usb/scanner.h */
|
|
|
|
#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
|
|
|
|
#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
|
|
|
|
#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest)
|
|
|
|
/* Older (unofficial) IOCTL numbers for Linux < v2.4.13 */
|
|
|
|
#define SCANNER_IOCTL_VENDOR_OLD _IOR('u', 0xa0, int)
|
|
|
|
#define SCANNER_IOCTL_PRODUCT_OLD _IOR('u', 0xa1, int)
|
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
/* From /usr/src/linux/include/linux/usb.h */
|
|
|
|
typedef struct
|
|
|
|
{
|
2002-01-03 19:18:27 +00:00
|
|
|
unsigned char requesttype;
|
|
|
|
unsigned char request;
|
|
|
|
unsigned short value;
|
|
|
|
unsigned short index;
|
|
|
|
unsigned short length;
|
2002-07-03 14:07:44 +00:00
|
|
|
}
|
2005-08-07 15:53:03 +00:00
|
|
|
devrequest;
|
2002-01-03 19:18:27 +00:00
|
|
|
|
|
|
|
/* From /usr/src/linux/driver/usb/scanner.h */
|
2002-07-03 14:07:44 +00:00
|
|
|
struct ctrlmsg_ioctl
|
|
|
|
{
|
|
|
|
devrequest req;
|
|
|
|
void *data;
|
|
|
|
}
|
|
|
|
cmsg;
|
2005-07-15 21:59:25 +00:00
|
|
|
#elif defined(__BEOS__)
|
|
|
|
#include <drivers/USB_scanner.h>
|
|
|
|
#include <kernel/OS.h>
|
2002-01-03 19:18:27 +00:00
|
|
|
#endif /* __linux__ */
|
|
|
|
|
2008-04-28 00:48:48 +00:00
|
|
|
static time_t last_time = 0;
|
2001-08-11 13:12:39 +00:00
|
|
|
|
2003-04-02 18:05:01 +00:00
|
|
|
/* Debug level from sanei_init_debug */
|
|
|
|
static SANE_Int debug_level;
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_buffer (const SANE_Byte * buffer, SANE_Int size)
|
|
|
|
{
|
|
|
|
#define NUM_COLUMNS 16
|
|
|
|
#define PRINT_BUFFER_SIZE (6 + NUM_COLUMNS * (3 + 1) + 1 + 1)
|
2005-04-15 20:48:24 +00:00
|
|
|
char line_str[PRINT_BUFFER_SIZE];
|
2003-04-02 18:05:01 +00:00
|
|
|
char *pp;
|
|
|
|
int column;
|
|
|
|
int line;
|
|
|
|
|
|
|
|
memset (line_str, 0, PRINT_BUFFER_SIZE);
|
|
|
|
|
|
|
|
for (line = 0; line < ((size + NUM_COLUMNS - 1) / NUM_COLUMNS); line++)
|
|
|
|
{
|
|
|
|
pp = line_str;
|
|
|
|
sprintf (pp, "%04X: ", line * NUM_COLUMNS);
|
|
|
|
pp += 6;
|
|
|
|
for (column = 0; column < NUM_COLUMNS; column++)
|
|
|
|
{
|
|
|
|
if ((line * NUM_COLUMNS + column) < size)
|
2005-04-15 20:48:24 +00:00
|
|
|
sprintf (pp, "%02X ", buffer[line * NUM_COLUMNS + column]);
|
2003-04-02 18:05:01 +00:00
|
|
|
else
|
|
|
|
sprintf (pp, " ");
|
|
|
|
pp += 3;
|
|
|
|
}
|
|
|
|
for (column = 0; column < NUM_COLUMNS; column++)
|
|
|
|
{
|
|
|
|
if ((line * NUM_COLUMNS + column) < size)
|
|
|
|
sprintf (pp, "%c",
|
2005-04-15 20:48:24 +00:00
|
|
|
(buffer[line * NUM_COLUMNS + column] < 127) &&
|
|
|
|
(buffer[line * NUM_COLUMNS + column] > 31) ?
|
|
|
|
buffer[line * NUM_COLUMNS + column] : '.');
|
2003-04-02 18:05:01 +00:00
|
|
|
else
|
|
|
|
sprintf (pp, ".");
|
|
|
|
pp += 1;
|
|
|
|
}
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (11, "%s\n", line_str);
|
2003-04-02 18:05:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
static void
|
2005-11-01 20:57:03 +00:00
|
|
|
kernel_get_vendor_product (int fd, const char *name, int *vendorID, int *productID)
|
2003-01-22 16:54:14 +00:00
|
|
|
{
|
|
|
|
#if defined (__linux__)
|
|
|
|
/* read the vendor and product IDs via the IOCTLs */
|
|
|
|
if (ioctl (fd, SCANNER_IOCTL_VENDOR, vendorID) == -1)
|
|
|
|
{
|
|
|
|
if (ioctl (fd, SCANNER_IOCTL_VENDOR_OLD, vendorID) == -1)
|
|
|
|
DBG (3, "kernel_get_vendor_product: ioctl (vendor) "
|
2005-11-01 20:57:03 +00:00
|
|
|
"of device %s failed: %s\n", name, strerror (errno));
|
2003-01-22 16:54:14 +00:00
|
|
|
}
|
|
|
|
if (ioctl (fd, SCANNER_IOCTL_PRODUCT, productID) == -1)
|
|
|
|
{
|
|
|
|
if (ioctl (fd, SCANNER_IOCTL_PRODUCT_OLD, productID) == -1)
|
|
|
|
DBG (3, "sanei_usb_get_vendor_product: ioctl (product) "
|
2005-11-01 20:57:03 +00:00
|
|
|
"of device %s failed: %s\n", name, strerror (errno));
|
2003-01-22 16:54:14 +00:00
|
|
|
}
|
2005-07-15 21:59:25 +00:00
|
|
|
#elif defined(__BEOS__)
|
|
|
|
{
|
|
|
|
uint16 vendor, product;
|
|
|
|
if (ioctl (fd, B_SCANNER_IOCTL_VENDOR, &vendor) != B_OK)
|
|
|
|
DBG (3, "kernel_get_vendor_product: ioctl (vendor) "
|
|
|
|
"of device %d failed: %s\n", fd, strerror (errno));
|
|
|
|
if (ioctl (fd, B_SCANNER_IOCTL_PRODUCT, &product) != B_OK)
|
|
|
|
DBG (3, "sanei_usb_get_vendor_product: ioctl (product) "
|
|
|
|
"of device %d failed: %s\n", fd, strerror (errno));
|
|
|
|
/* copy from 16 to 32 bit value */
|
|
|
|
*vendorID = vendor;
|
|
|
|
*productID = product;
|
|
|
|
}
|
2006-03-11 12:56:34 +00:00
|
|
|
#elif defined (__FreeBSD__) || defined (__DragonFly__)
|
2005-11-01 20:57:03 +00:00
|
|
|
{
|
|
|
|
int controller;
|
|
|
|
int ctrl_fd;
|
|
|
|
char buf[40];
|
|
|
|
int dev;
|
|
|
|
|
|
|
|
for (controller = 0; ; controller++ )
|
|
|
|
{
|
|
|
|
snprintf (buf, sizeof (buf) - 1, "/dev/usb%d", controller);
|
|
|
|
ctrl_fd = open (buf, O_RDWR);
|
|
|
|
|
|
|
|
/* If we can not open the usb controller device, treat it
|
|
|
|
as the end of controller devices */
|
|
|
|
if (ctrl_fd < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Search for the scanner device on this bus */
|
|
|
|
for (dev = 1; dev < USB_MAX_DEVICES; dev++)
|
|
|
|
{
|
|
|
|
struct usb_device_info devInfo;
|
|
|
|
devInfo.udi_addr = dev;
|
|
|
|
|
|
|
|
if (ioctl (ctrl_fd, USB_DEVICEINFO, &devInfo) == -1)
|
|
|
|
break; /* Treat this as the end of devices for this controller */
|
|
|
|
|
|
|
|
snprintf (buf, sizeof (buf), "/dev/%s", devInfo.udi_devnames[0]);
|
|
|
|
if (strncmp (buf, name, sizeof (buf)) == 0)
|
|
|
|
{
|
|
|
|
*vendorID = (int) devInfo.udi_vendorNo;
|
|
|
|
*productID = (int) devInfo.udi_productNo;
|
|
|
|
close (ctrl_fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close (ctrl_fd);
|
|
|
|
}
|
|
|
|
DBG (3, "kernel_get_vendor_product: Could not retrieve "
|
|
|
|
"vendor/product ID from device %s\n", name);
|
|
|
|
}
|
|
|
|
#endif /* defined (__linux__), defined(__BEOS__), ... */
|
2005-04-15 20:48:24 +00:00
|
|
|
/* put more os-dependant stuff ... */
|
2003-01-22 16:54:14 +00:00
|
|
|
}
|
|
|
|
|
2001-08-11 13:12:39 +00:00
|
|
|
void
|
|
|
|
sanei_usb_init (void)
|
|
|
|
{
|
2003-01-22 16:54:14 +00:00
|
|
|
SANE_String *prefix;
|
|
|
|
SANE_String prefixlist[] = {
|
|
|
|
#if defined(__linux__)
|
|
|
|
"/dev/", "usbscanner",
|
|
|
|
"/dev/usb/", "scanner",
|
2006-03-11 12:56:34 +00:00
|
|
|
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined (__DragonFly__)
|
2003-01-22 16:54:14 +00:00
|
|
|
"/dev/", "uscanner",
|
2005-07-15 21:59:25 +00:00
|
|
|
#elif defined(__BEOS__)
|
|
|
|
"/dev/scanner/usb/", "",
|
2003-01-22 16:54:14 +00:00
|
|
|
#endif
|
|
|
|
0, 0
|
|
|
|
};
|
|
|
|
SANE_Int vendor, product;
|
|
|
|
SANE_Char devname[1024];
|
|
|
|
SANE_Int dn = 0;
|
|
|
|
int fd;
|
2008-04-28 00:48:48 +00:00
|
|
|
time_t curr_time = time(NULL);
|
2003-01-22 16:54:14 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
struct usb_bus *bus;
|
|
|
|
struct usb_device *dev;
|
|
|
|
#endif /* HAVE_LIBUSB */
|
2002-07-03 14:07:44 +00:00
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
DBG_INIT ();
|
2003-04-02 18:05:01 +00:00
|
|
|
#ifdef DBG_LEVEL
|
|
|
|
debug_level = DBG_LEVEL;
|
|
|
|
#else
|
|
|
|
debug_level = 0;
|
|
|
|
#endif
|
|
|
|
|
2008-04-28 00:48:48 +00:00
|
|
|
/* init only once per second */
|
|
|
|
if (last_time == curr_time){
|
|
|
|
DBG (4, "sanei_usb_init: skipping probe: %lu\n",(unsigned long)last_time);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_time = curr_time;
|
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
memset (devices, 0, sizeof (devices));
|
|
|
|
|
2006-01-07 18:04:17 +00:00
|
|
|
DBG (4, "sanei_usb_init: Looking for kernel scanner devices\n");
|
2003-01-22 16:54:14 +00:00
|
|
|
/* Check for devices using the kernel scanner driver */
|
|
|
|
|
|
|
|
for (prefix = prefixlist; *prefix; prefix += 2)
|
|
|
|
{
|
|
|
|
SANE_String dir_name = *prefix;
|
|
|
|
SANE_String base_name = *(prefix + 1);
|
|
|
|
struct stat stat_buf;
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *dir_entry;
|
|
|
|
|
|
|
|
if (stat (dir_name, &stat_buf) < 0)
|
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (5, "sanei_usb_init: can't stat %s: %s\n", dir_name,
|
|
|
|
strerror (errno));
|
2003-01-22 16:54:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!S_ISDIR (stat_buf.st_mode))
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_init: %s is not a directory\n", dir_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((dir = opendir (dir_name)) == 0)
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_init: cannot read directory %s: %s\n", dir_name,
|
2005-04-15 20:48:24 +00:00
|
|
|
strerror (errno));
|
2003-01-22 16:54:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
2005-04-15 20:48:24 +00:00
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
while ((dir_entry = readdir (dir)) != 0)
|
|
|
|
{
|
2005-07-15 21:59:25 +00:00
|
|
|
/* skip standard dir entries */
|
|
|
|
if (strcmp (dir_entry->d_name, ".") == 0 || strcmp (dir_entry->d_name, "..") == 0)
|
|
|
|
continue;
|
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
if (strncmp (base_name, dir_entry->d_name, strlen (base_name)) == 0)
|
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
if (strlen (dir_name) + strlen (dir_entry->d_name) + 1 >
|
|
|
|
sizeof (devname))
|
|
|
|
continue;
|
2003-01-22 16:54:14 +00:00
|
|
|
sprintf (devname, "%s%s", dir_name, dir_entry->d_name);
|
2004-07-26 15:15:39 +00:00
|
|
|
fd = -1;
|
|
|
|
#ifdef HAVE_RESMGR
|
|
|
|
fd = rsm_open_device (devname, O_RDWR);
|
|
|
|
#endif
|
|
|
|
if (fd == -1)
|
2005-04-15 20:48:24 +00:00
|
|
|
fd = open (devname, O_RDWR);
|
2003-01-22 16:54:14 +00:00
|
|
|
if (fd < 0)
|
|
|
|
{
|
2003-02-22 15:45:51 +00:00
|
|
|
DBG (5, "sanei_usb_init: couldn't open %s: %s\n", devname,
|
2005-04-15 20:48:24 +00:00
|
|
|
strerror (errno));
|
2003-01-22 16:54:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
vendor = -1;
|
|
|
|
product = -1;
|
2005-11-01 20:57:03 +00:00
|
|
|
kernel_get_vendor_product (fd, devname, &vendor, &product);
|
2003-01-22 16:54:14 +00:00
|
|
|
close (fd);
|
|
|
|
devices[dn].devname = strdup (devname);
|
2005-04-15 20:48:24 +00:00
|
|
|
if (!devices[dn].devname)
|
|
|
|
{
|
2004-08-30 11:52:15 +00:00
|
|
|
closedir (dir);
|
|
|
|
return;
|
2005-04-15 20:48:24 +00:00
|
|
|
}
|
2003-01-22 16:54:14 +00:00
|
|
|
devices[dn].vendor = vendor;
|
|
|
|
devices[dn].product = product;
|
|
|
|
devices[dn].method = sanei_usb_method_scanner_driver;
|
|
|
|
devices[dn].open = SANE_FALSE;
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (4,
|
|
|
|
"sanei_usb_init: found kernel scanner device (0x%04x/0x%04x) at %s\n",
|
2003-01-22 16:54:14 +00:00
|
|
|
vendor, product, devname);
|
|
|
|
dn++;
|
|
|
|
if (dn >= MAX_DEVICES)
|
2005-04-15 20:48:24 +00:00
|
|
|
{
|
2004-08-30 11:52:15 +00:00
|
|
|
closedir (dir);
|
|
|
|
return;
|
2005-04-15 20:48:24 +00:00
|
|
|
}
|
2003-01-22 16:54:14 +00:00
|
|
|
}
|
|
|
|
}
|
2004-08-30 11:52:15 +00:00
|
|
|
closedir (dir);
|
2003-01-22 16:54:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for devices using libusb */
|
2002-07-03 14:07:44 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
2006-01-07 18:04:17 +00:00
|
|
|
DBG (4, "sanei_usb_init: Looking for libusb devices\n");
|
2002-07-03 14:07:44 +00:00
|
|
|
usb_init ();
|
|
|
|
#ifdef DBG_LEVEL
|
|
|
|
if (DBG_LEVEL > 4)
|
|
|
|
usb_set_debug (255);
|
|
|
|
#endif /* DBG_LEVEL */
|
2008-04-28 00:48:48 +00:00
|
|
|
|
|
|
|
usb_find_busses ();
|
|
|
|
usb_find_devices ();
|
2003-01-22 16:54:14 +00:00
|
|
|
|
|
|
|
/* Check for the matching device */
|
|
|
|
for (bus = usb_get_busses (); bus; bus = bus->next)
|
|
|
|
{
|
|
|
|
for (dev = bus->devices; dev; dev = dev->next)
|
|
|
|
{
|
2003-02-19 19:38:26 +00:00
|
|
|
int interface;
|
|
|
|
SANE_Bool found;
|
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
if (!dev->config)
|
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_init: device 0x%04x/0x%04x is not configured\n",
|
2003-01-22 16:54:14 +00:00
|
|
|
dev->descriptor.idVendor, dev->descriptor.idProduct);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (dev->descriptor.idVendor == 0 || dev->descriptor.idProduct == 0)
|
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (5,
|
|
|
|
"sanei_usb_init: device 0x%04x/0x%04x looks like a root hub\n",
|
2003-01-22 16:54:14 +00:00
|
|
|
dev->descriptor.idVendor, dev->descriptor.idProduct);
|
|
|
|
continue;
|
|
|
|
}
|
2003-02-19 19:38:26 +00:00
|
|
|
found = SANE_FALSE;
|
2005-04-15 20:48:24 +00:00
|
|
|
for (interface = 0;
|
|
|
|
interface < dev->config[0].bNumInterfaces && !found;
|
|
|
|
interface++)
|
2003-01-22 16:54:14 +00:00
|
|
|
{
|
2003-02-19 19:38:26 +00:00
|
|
|
switch (dev->descriptor.bDeviceClass)
|
2003-01-22 16:54:14 +00:00
|
|
|
{
|
|
|
|
case USB_CLASS_VENDOR_SPEC:
|
2003-02-19 19:38:26 +00:00
|
|
|
found = SANE_TRUE;
|
|
|
|
break;
|
2003-01-22 16:54:14 +00:00
|
|
|
case USB_CLASS_PER_INTERFACE:
|
2006-01-22 16:52:13 +00:00
|
|
|
if (dev->config[0].interface[interface].num_altsetting == 0 ||
|
|
|
|
!dev->config[0].interface[interface].altsetting)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_init: device 0x%04x/0x%04x doesn't "
|
|
|
|
"have an altsetting for interface %d\n",
|
|
|
|
dev->descriptor.idVendor, dev->descriptor.idProduct,
|
|
|
|
interface);
|
|
|
|
continue;
|
|
|
|
}
|
2005-04-15 20:48:24 +00:00
|
|
|
switch (dev->config[0].interface[interface].altsetting[0].
|
|
|
|
bInterfaceClass)
|
2003-02-19 19:38:26 +00:00
|
|
|
{
|
|
|
|
case USB_CLASS_VENDOR_SPEC:
|
|
|
|
case USB_CLASS_PER_INTERFACE:
|
2008-03-28 14:13:23 +00:00
|
|
|
case 6: /* imaging? */
|
2005-04-15 20:48:24 +00:00
|
|
|
case 16: /* data? */
|
2003-02-19 19:38:26 +00:00
|
|
|
found = SANE_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
2003-01-22 16:54:14 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-02-19 19:38:26 +00:00
|
|
|
if (!found)
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (5,
|
|
|
|
"sanei_usb_init: device 0x%04x/0x%04x, interface %d doesn't look like a "
|
2003-02-19 19:38:26 +00:00
|
|
|
"scanner (%d/%d)\n", dev->descriptor.idVendor,
|
2005-04-15 20:48:24 +00:00
|
|
|
dev->descriptor.idProduct, interface,
|
|
|
|
dev->descriptor.bDeviceClass,
|
2006-01-22 16:52:13 +00:00
|
|
|
dev->config[0].interface[interface].altsetting != 0 ? dev->config[0].interface[interface].altsetting[0].
|
|
|
|
bInterfaceClass : -1);
|
2003-02-19 19:38:26 +00:00
|
|
|
}
|
|
|
|
interface--;
|
|
|
|
if (!found)
|
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (5,
|
|
|
|
"sanei_usb_init: device 0x%04x/0x%04x: no suitable interfaces\n",
|
2003-02-19 19:38:26 +00:00
|
|
|
dev->descriptor.idVendor, dev->descriptor.idProduct);
|
2003-01-22 16:54:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
2005-04-15 20:48:24 +00:00
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
devices[dn].libusb_device = dev;
|
|
|
|
snprintf (devname, sizeof (devname), "libusb:%s:%s",
|
|
|
|
dev->bus->dirname, dev->filename);
|
|
|
|
devices[dn].devname = strdup (devname);
|
|
|
|
if (!devices[dn].devname)
|
|
|
|
return;
|
|
|
|
devices[dn].vendor = dev->descriptor.idVendor;
|
|
|
|
devices[dn].product = dev->descriptor.idProduct;
|
|
|
|
devices[dn].method = sanei_usb_method_libusb;
|
|
|
|
devices[dn].open = SANE_FALSE;
|
2003-02-19 19:38:26 +00:00
|
|
|
devices[dn].interface_nr = interface;
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (4,
|
|
|
|
"sanei_usb_init: found libusb device (0x%04x/0x%04x) interface %d at %s\n",
|
|
|
|
dev->descriptor.idVendor, dev->descriptor.idProduct, interface,
|
|
|
|
devname);
|
2003-01-22 16:54:14 +00:00
|
|
|
dn++;
|
|
|
|
if (dn >= MAX_DEVICES)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2006-01-07 18:04:17 +00:00
|
|
|
#else /* HAVE_LIBUSB */
|
|
|
|
DBG (4, "sanei_usb_init: SANE is built without support for libusb\n");
|
2002-07-03 14:07:44 +00:00
|
|
|
#endif /* HAVE_LIBUSB */
|
2006-01-07 18:04:17 +00:00
|
|
|
|
2005-08-07 14:26:33 +00:00
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
/* Check for devices using OS/2 USBCALLS Interface */
|
|
|
|
|
|
|
|
CHAR ucData[2048];
|
|
|
|
struct usb_device_descriptor *pDevDesc;
|
|
|
|
struct usb_config_descriptor *pCfgDesc;
|
|
|
|
struct usb_interface_descriptor *intf;
|
|
|
|
struct usb_endpoint_descriptor *ep;
|
|
|
|
struct usb_descriptor_header *pDescHead;
|
|
|
|
|
|
|
|
APIRET rc;
|
|
|
|
ULONG ulNumDev, ulDev, ulBufLen;
|
|
|
|
|
|
|
|
ulBufLen = sizeof(ucData);
|
|
|
|
memset(&ucData,0,sizeof(ucData));
|
|
|
|
rc = UsbQueryNumberDevices( &ulNumDev);
|
|
|
|
|
|
|
|
if(rc==0 && ulNumDev)
|
|
|
|
{
|
|
|
|
for (ulDev=1; ulDev<=ulNumDev; ulDev++)
|
|
|
|
{
|
|
|
|
rc = UsbQueryDeviceReport( ulDev,
|
|
|
|
&ulBufLen,
|
|
|
|
ucData);
|
|
|
|
|
|
|
|
pDevDesc = (struct usb_device_descriptor*)ucData;
|
|
|
|
pCfgDesc = (struct usb_config_descriptor*) (ucData+sizeof(struct usb_device_descriptor));
|
|
|
|
int interface=0;
|
|
|
|
SANE_Bool found;
|
|
|
|
if (!pCfgDesc->bConfigurationValue)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_init: device 0x%04x/0x%04x is not configured\n",
|
|
|
|
pDevDesc->idVendor, pDevDesc->idProduct);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (pDevDesc->idVendor == 0 || pDevDesc->idProduct == 0)
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_init: device 0x%04x/0x%04x looks like a root hub\n",
|
|
|
|
pDevDesc->idVendor, pDevDesc->idProduct);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
found = SANE_FALSE;
|
|
|
|
|
|
|
|
if (pDevDesc->bDeviceClass = USB_CLASS_VENDOR_SPEC)
|
|
|
|
{
|
|
|
|
found = SANE_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_init: device 0x%04x/0x%04x: no suitable interfaces\n",
|
|
|
|
pDevDesc->idVendor, pDevDesc->idProduct);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf (devname, sizeof (devname), "usbcalls:%d",
|
|
|
|
ulDev);
|
|
|
|
devices[dn].devname = strdup (devname);
|
|
|
|
devices[dn].fd = ulDev; /* store usbcalls device number */
|
|
|
|
devices[dn].vendor = pDevDesc->idVendor;
|
|
|
|
devices[dn].product = pDevDesc->idProduct;
|
|
|
|
devices[dn].method = sanei_usb_method_usbcalls;
|
|
|
|
devices[dn].open = SANE_FALSE;
|
|
|
|
devices[dn].interface_nr = interface;
|
|
|
|
DBG (4, "sanei_usb_init: found usbcalls device (0x%04x/0x%04x) as device number %s\n",
|
|
|
|
pDevDesc->idVendor, pDevDesc->idProduct,devices[dn].devname);
|
|
|
|
dn++;
|
|
|
|
if (dn >= MAX_DEVICES)
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_USBCALLS */
|
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
DBG (5, "sanei_usb_init: found %d devices\n", dn);
|
2001-08-11 13:12:39 +00:00
|
|
|
}
|
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
|
2001-09-05 19:48:24 +00:00
|
|
|
/* This logically belongs to sanei_config.c but not every backend that
|
|
|
|
uses sanei_config() wants to depend on sanei_usb. */
|
|
|
|
void
|
|
|
|
sanei_usb_attach_matching_devices (const char *name,
|
|
|
|
SANE_Status (*attach) (const char *dev))
|
|
|
|
{
|
|
|
|
char *vendor, *product;
|
|
|
|
|
|
|
|
if (strncmp (name, "usb", 3) == 0)
|
|
|
|
{
|
|
|
|
SANE_Word vendorID = 0, productID = 0;
|
|
|
|
|
|
|
|
name += 3;
|
|
|
|
|
|
|
|
name = sanei_config_skip_whitespace (name);
|
|
|
|
if (*name)
|
|
|
|
{
|
|
|
|
name = sanei_config_get_string (name, &vendor);
|
|
|
|
if (vendor)
|
|
|
|
{
|
|
|
|
vendorID = strtol (vendor, 0, 0);
|
|
|
|
free (vendor);
|
|
|
|
}
|
|
|
|
name = sanei_config_skip_whitespace (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
name = sanei_config_skip_whitespace (name);
|
|
|
|
if (*name)
|
|
|
|
{
|
|
|
|
name = sanei_config_get_string (name, &product);
|
|
|
|
if (product)
|
|
|
|
{
|
|
|
|
productID = strtol (product, 0, 0);
|
|
|
|
free (product);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sanei_usb_find_devices (vendorID, productID, attach);
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
else
|
2001-09-05 19:48:24 +00:00
|
|
|
(*attach) (name);
|
|
|
|
}
|
|
|
|
|
2008-03-28 20:39:02 +00:00
|
|
|
SANE_Status
|
|
|
|
sanei_usb_get_vendor_product_byname (SANE_String_Const devname,
|
|
|
|
SANE_Word * vendor, SANE_Word * product)
|
|
|
|
{
|
|
|
|
int devcount;
|
|
|
|
SANE_Bool found = SANE_FALSE;
|
|
|
|
|
|
|
|
for (devcount = 0; devcount < MAX_DEVICES && devices[devcount].devname != 0;
|
|
|
|
devcount++)
|
|
|
|
{
|
|
|
|
if (strcmp (devices[devcount].devname, devname) == 0)
|
|
|
|
{
|
|
|
|
found = SANE_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_get_vendor_product_byname: can't find device `%s' in list\n", devname);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((devices[devcount].vendor == 0) && (devices[devcount].product == 0))
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_get_vendor_product_byname: not support for this method\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vendor)
|
|
|
|
*vendor = devices[devcount].vendor;
|
|
|
|
|
|
|
|
if (product)
|
|
|
|
*product = devices[devcount].product;
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
|
2001-08-11 13:12:39 +00:00
|
|
|
SANE_Status
|
2002-07-03 19:48:45 +00:00
|
|
|
sanei_usb_get_vendor_product (SANE_Int dn, SANE_Word * vendor,
|
2001-08-11 13:12:39 +00:00
|
|
|
SANE_Word * product)
|
|
|
|
{
|
2002-05-30 19:23:22 +00:00
|
|
|
SANE_Word vendorID = 0;
|
|
|
|
SANE_Word productID = 0;
|
2001-08-11 13:12:39 +00:00
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
DBG (1, "sanei_usb_get_vendor_product: dn >= MAX_DEVICES || dn < 0\n");
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
2005-11-01 20:57:03 +00:00
|
|
|
kernel_get_vendor_product (devices[dn].fd, devices[dn].devname, &vendorID, &productID);
|
2002-07-03 19:48:45 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2002-07-03 14:07:44 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
2002-07-03 19:48:45 +00:00
|
|
|
vendorID = usb_device (devices[dn].libusb_handle)->descriptor.idVendor;
|
2002-07-03 14:07:44 +00:00
|
|
|
productID =
|
2002-07-03 19:48:45 +00:00
|
|
|
usb_device (devices[dn].libusb_handle)->descriptor.idProduct;
|
2002-07-03 14:07:44 +00:00
|
|
|
#else
|
|
|
|
DBG (1, "sanei_usb_get_vendor_product: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* HAVE_LIBUSB */
|
2001-08-11 13:12:39 +00:00
|
|
|
}
|
2005-08-07 14:26:33 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_usbcalls)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
vendorID = devices[dn].vendor;
|
|
|
|
productID = devices[dn].product;
|
|
|
|
#else
|
|
|
|
DBG (1, "sanei_usb_get_vendor_product: usbcalls support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* HAVE_USBCALLS */
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
else
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2002-07-03 14:07:44 +00:00
|
|
|
DBG (1, "sanei_usb_get_vendor_product: access method %d not "
|
2002-07-03 19:48:45 +00:00
|
|
|
"implemented\n", devices[dn].method);
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
2001-08-11 13:12:39 +00:00
|
|
|
}
|
|
|
|
if (vendor)
|
|
|
|
*vendor = vendorID;
|
|
|
|
if (product)
|
|
|
|
*product = productID;
|
|
|
|
|
|
|
|
if (!vendorID || !productID)
|
|
|
|
{
|
2002-07-03 14:07:44 +00:00
|
|
|
DBG (3, "sanei_usb_get_vendor_product: device %d: Your OS doesn't "
|
2002-07-03 19:48:45 +00:00
|
|
|
"seem to support detection of vendor+product ids\n", dn);
|
2001-08-11 13:12:39 +00:00
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-07-03 14:07:44 +00:00
|
|
|
DBG (3, "sanei_usb_get_vendor_product: device %d: vendorID: 0x%04x, "
|
2002-07-03 19:48:45 +00:00
|
|
|
"productID: 0x%04x\n", dn, vendorID, productID);
|
2001-08-11 13:12:39 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SANE_Status
|
|
|
|
sanei_usb_find_devices (SANE_Int vendor, SANE_Int product,
|
|
|
|
SANE_Status (*attach) (SANE_String_Const dev))
|
|
|
|
{
|
2003-01-22 16:54:14 +00:00
|
|
|
SANE_Int dn = 0;
|
2001-08-11 13:12:39 +00:00
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
DBG (3,
|
2003-07-17 15:05:14 +00:00
|
|
|
"sanei_usb_find_devices: vendor=0x%04x, product=0x%04x\n",
|
|
|
|
vendor, product);
|
2001-08-11 13:12:39 +00:00
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
while (devices[dn].devname && dn < MAX_DEVICES)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2003-01-22 16:54:14 +00:00
|
|
|
if (devices[dn].vendor == vendor && devices[dn].product == product)
|
|
|
|
if (attach)
|
|
|
|
attach (devices[dn].devname);
|
|
|
|
dn++;
|
2001-08-11 13:12:39 +00:00
|
|
|
}
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
SANE_Status
|
2002-07-03 19:48:45 +00:00
|
|
|
sanei_usb_open (SANE_String_Const devname, SANE_Int * dn)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2002-07-03 14:07:44 +00:00
|
|
|
int devcount;
|
2003-01-22 16:54:14 +00:00
|
|
|
SANE_Bool found = SANE_FALSE;
|
2005-04-15 20:48:24 +00:00
|
|
|
int c, i, a;
|
2002-07-03 14:07:44 +00:00
|
|
|
|
2002-07-14 16:31:14 +00:00
|
|
|
DBG (5, "sanei_usb_open: trying to open device `%s'\n", devname);
|
2002-07-03 19:48:45 +00:00
|
|
|
if (!dn)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
DBG (1, "sanei_usb_open: can't open `%s': dn == NULL\n", devname);
|
2001-08-11 13:12:39 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
|
2005-04-15 20:48:24 +00:00
|
|
|
for (devcount = 0; devcount < MAX_DEVICES && devices[devcount].devname != 0;
|
|
|
|
devcount++)
|
2002-07-14 16:31:14 +00:00
|
|
|
{
|
2003-01-22 16:54:14 +00:00
|
|
|
if (strcmp (devices[devcount].devname, devname) == 0)
|
2002-07-14 16:31:14 +00:00
|
|
|
{
|
2003-01-22 16:54:14 +00:00
|
|
|
if (devices[devcount].open)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_open: device `%s' already open\n", devname);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
found = SANE_TRUE;
|
|
|
|
break;
|
2002-07-14 16:31:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
if (!found)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2003-01-22 16:54:14 +00:00
|
|
|
DBG (1, "sanei_usb_open: can't find device `%s' in list\n", devname);
|
|
|
|
return SANE_STATUS_INVAL;
|
2002-07-03 14:07:44 +00:00
|
|
|
}
|
|
|
|
|
2003-01-22 16:54:14 +00:00
|
|
|
if (devices[devcount].method == sanei_usb_method_libusb)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
struct usb_device *dev;
|
|
|
|
struct usb_interface_descriptor *interface;
|
2003-01-22 16:54:14 +00:00
|
|
|
int result, num;
|
|
|
|
|
2005-04-15 20:48:24 +00:00
|
|
|
devices[devcount].libusb_handle =
|
|
|
|
usb_open (devices[devcount].libusb_device);
|
2002-07-14 16:31:14 +00:00
|
|
|
if (!devices[devcount].libusb_handle)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_INVAL;
|
2002-07-03 14:07:44 +00:00
|
|
|
|
2002-07-14 16:31:14 +00:00
|
|
|
DBG (1, "sanei_usb_open: can't open device `%s': %s\n",
|
|
|
|
devname, strerror (errno));
|
|
|
|
if (errno == EPERM)
|
|
|
|
{
|
|
|
|
DBG (1, "Make sure you run as root or set appropriate "
|
|
|
|
"permissions\n");
|
|
|
|
status = SANE_STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
else if (errno == EBUSY)
|
|
|
|
{
|
|
|
|
DBG (1, "Maybe the kernel scanner driver claims the "
|
|
|
|
"scanner's interface?\n");
|
|
|
|
status = SANE_STATUS_DEVICE_BUSY;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
dev = usb_device (devices[devcount].libusb_handle);
|
|
|
|
|
2002-12-30 13:51:10 +00:00
|
|
|
/* Set the configuration */
|
2002-07-14 16:31:14 +00:00
|
|
|
if (!dev->config)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_open: device `%s' not configured?\n", devname);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
if (dev->descriptor.bNumConfigurations > 1)
|
|
|
|
{
|
|
|
|
DBG (3, "sanei_usb_open: more than one "
|
2002-12-30 13:51:10 +00:00
|
|
|
"configuration (%d), choosing first config (%d)\n",
|
2005-04-15 20:48:24 +00:00
|
|
|
dev->descriptor.bNumConfigurations,
|
2002-12-30 13:51:10 +00:00
|
|
|
dev->config[0].bConfigurationValue);
|
2002-07-03 14:07:44 +00:00
|
|
|
}
|
2002-12-30 13:51:10 +00:00
|
|
|
result = usb_set_configuration (devices[devcount].libusb_handle,
|
|
|
|
dev->config[0].bConfigurationValue);
|
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_INVAL;
|
|
|
|
|
|
|
|
DBG (1, "sanei_usb_open: libusb complained: %s\n", usb_strerror ());
|
|
|
|
if (errno == EPERM)
|
|
|
|
{
|
|
|
|
DBG (1, "Make sure you run as root or set appropriate "
|
|
|
|
"permissions\n");
|
|
|
|
status = SANE_STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
else if (errno == EBUSY)
|
|
|
|
{
|
2005-09-23 12:52:35 +00:00
|
|
|
DBG (3, "Maybe the kernel scanner driver or usblp claims the "
|
|
|
|
"interface? Ignoring this error...\n");
|
|
|
|
status = SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
{
|
|
|
|
usb_close (devices[devcount].libusb_handle);
|
|
|
|
return status;
|
2002-12-30 13:51:10 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-15 20:48:24 +00:00
|
|
|
|
2002-12-30 13:51:10 +00:00
|
|
|
/* Claim the interface */
|
2005-04-15 20:48:24 +00:00
|
|
|
result = usb_claim_interface (devices[devcount].libusb_handle,
|
2002-12-30 13:51:10 +00:00
|
|
|
devices[devcount].interface_nr);
|
2002-07-03 14:07:44 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_INVAL;
|
|
|
|
|
|
|
|
DBG (1, "sanei_usb_open: libusb complained: %s\n", usb_strerror ());
|
|
|
|
if (errno == EPERM)
|
|
|
|
{
|
|
|
|
DBG (1, "Make sure you run as root or set appropriate "
|
|
|
|
"permissions\n");
|
|
|
|
status = SANE_STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
else if (errno == EBUSY)
|
|
|
|
{
|
|
|
|
DBG (1, "Maybe the kernel scanner driver claims the "
|
|
|
|
"scanner's interface?\n");
|
|
|
|
status = SANE_STATUS_DEVICE_BUSY;
|
|
|
|
}
|
|
|
|
usb_close (devices[devcount].libusb_handle);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2005-04-15 20:48:24 +00:00
|
|
|
/* Loop through all of the configurations */
|
|
|
|
for (c = 0; c < dev->descriptor.bNumConfigurations; c++)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
/* Loop through all of the interfaces */
|
|
|
|
for (i = 0; i < dev->config[c].bNumInterfaces; i++)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
/* Loop through all of the alternate settings */
|
|
|
|
for (a = 0; a < dev->config[c].interface[i].num_altsetting; a++)
|
|
|
|
{
|
|
|
|
|
|
|
|
DBG (5, "sanei_usb_open: configuration nr: %d\n", c);
|
|
|
|
DBG (5, "sanei_usb_open: interface nr: %d\n", i);
|
|
|
|
DBG (5, "sanei_usb_open: alt_setting nr: %d\n", a);
|
|
|
|
|
|
|
|
interface = &dev->config[c].interface[i].altsetting[a];
|
|
|
|
|
|
|
|
/* Now we look for usable endpoints */
|
|
|
|
for (num = 0; num < interface->bNumEndpoints; num++)
|
|
|
|
{
|
|
|
|
struct usb_endpoint_descriptor *endpoint;
|
|
|
|
int address, direction, transfer_type;
|
|
|
|
|
|
|
|
endpoint = &interface->endpoint[num];
|
2005-08-07 15:53:03 +00:00
|
|
|
DBG (5, "sanei_usb_open: endpoint nr: %d\n", num);
|
2005-04-15 20:48:24 +00:00
|
|
|
transfer_type =
|
|
|
|
endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK;
|
|
|
|
address =
|
|
|
|
endpoint->
|
|
|
|
bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
|
|
|
|
direction =
|
|
|
|
endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
|
|
|
|
|
2005-08-07 15:53:03 +00:00
|
|
|
DBG (5, "sanei_usb_open: direction: %d\n", direction);
|
2005-04-15 20:48:24 +00:00
|
|
|
transfer_type =
|
|
|
|
endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK;
|
|
|
|
|
|
|
|
DBG (5,
|
2005-08-07 15:53:03 +00:00
|
|
|
"sanei_usb_open: address: %d transfertype: %d\n",
|
2005-04-15 20:48:24 +00:00
|
|
|
address, transfer_type);
|
|
|
|
|
|
|
|
|
|
|
|
/* save the endpoints we need later */
|
|
|
|
if (transfer_type == USB_ENDPOINT_TYPE_INTERRUPT)
|
|
|
|
{
|
|
|
|
DBG (5,
|
|
|
|
"sanei_usb_open: found interrupt-%s endpoint (address 0x%02x)\n",
|
|
|
|
direction ? "in" : "out", address);
|
|
|
|
if (direction) /* in */
|
|
|
|
{
|
|
|
|
if (devices[devcount].int_in_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a int-in endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].int_in_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].int_in_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (devices[devcount].int_out_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a int-out endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].int_out_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].int_out_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (transfer_type == USB_ENDPOINT_TYPE_BULK)
|
|
|
|
{
|
|
|
|
DBG (5,
|
|
|
|
"sanei_usb_open: found bulk-%s endpoint (address 0x%02x)\n",
|
|
|
|
direction ? "in" : "out", address);
|
|
|
|
if (direction) /* in */
|
|
|
|
{
|
|
|
|
if (devices[devcount].bulk_in_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a bulk-in endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].bulk_in_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].bulk_in_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (devices[devcount].bulk_out_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a bulk-out endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].bulk_out_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].bulk_out_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (transfer_type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
|
|
|
|
{
|
|
|
|
DBG (5,
|
|
|
|
"sanei_usb_open: found isochronous-%s endpoint (address 0x%02x)\n",
|
|
|
|
direction ? "in" : "out", address);
|
|
|
|
if (direction) /* in */
|
|
|
|
{
|
|
|
|
if (devices[devcount].iso_in_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a isochronous-in endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].iso_in_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].iso_in_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (devices[devcount].iso_out_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a isochronous-out endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].iso_out_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].iso_out_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (transfer_type == USB_ENDPOINT_TYPE_CONTROL)
|
|
|
|
{
|
|
|
|
DBG (5,
|
|
|
|
"sanei_usb_open: found control-%s endpoint (address 0x%02x)\n",
|
|
|
|
direction ? "in" : "out", address);
|
|
|
|
if (direction) /* in */
|
|
|
|
{
|
|
|
|
if (devices[devcount].control_in_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a control-in endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].control_in_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].control_in_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (devices[devcount].control_out_ep)
|
|
|
|
DBG (3,
|
|
|
|
"sanei_usb_open: we already have a control-out endpoint "
|
|
|
|
"(address: 0x%02x), ignoring the new one\n",
|
|
|
|
devices[devcount].control_out_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].control_out_ep =
|
|
|
|
endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
DBG (1, "sanei_usb_open: can't open device `%s': "
|
|
|
|
"libusb support missing\n", devname);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
|
|
|
}
|
2003-01-22 16:54:14 +00:00
|
|
|
else if (devices[devcount].method == sanei_usb_method_scanner_driver)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2003-07-17 15:05:14 +00:00
|
|
|
long int flag;
|
2002-07-03 14:07:44 +00:00
|
|
|
/* Using kernel scanner driver */
|
2004-07-26 15:15:39 +00:00
|
|
|
devices[devcount].fd = -1;
|
|
|
|
#ifdef HAVE_RESMGR
|
|
|
|
devices[devcount].fd = rsm_open_device (devname, O_RDWR);
|
|
|
|
#endif
|
|
|
|
if (devices[devcount].fd == -1)
|
2005-04-15 20:48:24 +00:00
|
|
|
devices[devcount].fd = open (devname, O_RDWR);
|
2002-07-03 14:07:44 +00:00
|
|
|
if (devices[devcount].fd < 0)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_INVAL;
|
2001-08-11 13:12:39 +00:00
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
if (errno == EACCES)
|
|
|
|
status = SANE_STATUS_ACCESS_DENIED;
|
|
|
|
else if (errno == ENOENT)
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_open: open of `%s' failed: %s\n",
|
|
|
|
devname, strerror (errno));
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
DBG (1, "sanei_usb_open: open of `%s' failed: %s\n",
|
|
|
|
devname, strerror (errno));
|
|
|
|
return status;
|
|
|
|
}
|
2003-07-17 15:05:14 +00:00
|
|
|
flag = fcntl (devices[devcount].fd, F_GETFD);
|
|
|
|
if (flag >= 0)
|
|
|
|
{
|
|
|
|
if (fcntl (devices[devcount].fd, F_SETFD, flag | FD_CLOEXEC) < 0)
|
|
|
|
DBG (1, "sanei_usb_open: fcntl of `%s' failed: %s\n",
|
|
|
|
devname, strerror (errno));
|
|
|
|
}
|
2001-08-11 13:12:39 +00:00
|
|
|
}
|
2005-08-07 14:26:33 +00:00
|
|
|
else if (devices[devcount].method == sanei_usb_method_usbcalls)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
CHAR ucData[2048];
|
|
|
|
struct usb_device_descriptor *pDevDesc;
|
|
|
|
struct usb_config_descriptor *pCfgDesc;
|
|
|
|
struct usb_interface_descriptor *interface;
|
|
|
|
struct usb_endpoint_descriptor *endpoint;
|
|
|
|
struct usb_descriptor_header *pDescHead;
|
|
|
|
|
|
|
|
ULONG ulBufLen;
|
|
|
|
ulBufLen = sizeof(ucData);
|
|
|
|
memset(&ucData,0,sizeof(ucData));
|
|
|
|
|
|
|
|
int result, num,rc;
|
|
|
|
int address, direction, transfer_type;
|
|
|
|
|
|
|
|
DBG (5, "devname = %s, devcount = %d\n",devices[devcount].devname,devcount);
|
|
|
|
DBG (5, "USBCalls device number to open = %d\n",devices[devcount].fd);
|
|
|
|
DBG (5, "USBCalls Vendor/Product to open = 0x%04x/0x%04x\n",
|
|
|
|
devices[devcount].vendor,devices[devcount].product);
|
|
|
|
|
|
|
|
rc = UsbOpen (&dh,
|
|
|
|
devices[devcount].vendor,
|
|
|
|
devices[devcount].product,
|
|
|
|
USB_ANY_PRODUCTVERSION,
|
|
|
|
USB_OPEN_FIRST_UNUSED);
|
|
|
|
DBG (1, "sanei_usb_open: UsbOpen rc = %d\n",rc);
|
|
|
|
if (rc!=0)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_INVAL;
|
|
|
|
DBG (1, "sanei_usb_open: can't open device `%s': %s\n",
|
|
|
|
devname, strerror (rc));
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
rc = UsbQueryDeviceReport( devices[devcount].fd,
|
|
|
|
&ulBufLen,
|
|
|
|
ucData);
|
|
|
|
DBG (1, "sanei_usb_open: UsbQueryDeviceReport rc = %d\n",rc);
|
|
|
|
pDevDesc = (struct usb_device_descriptor*)ucData;
|
|
|
|
pCfgDesc = (struct usb_config_descriptor*) (ucData+sizeof(struct usb_device_descriptor));
|
|
|
|
UCHAR *pCurPtr = (UCHAR*) pCfgDesc;
|
|
|
|
UCHAR *pEndPtr = pCurPtr+ pCfgDesc->wTotalLength;
|
|
|
|
pDescHead = (struct usb_descriptor_header *) (pCurPtr+pCfgDesc->bLength);
|
|
|
|
/* Set the configuration */
|
|
|
|
if (pDevDesc->bNumConfigurations > 1)
|
|
|
|
{
|
|
|
|
DBG (3, "sanei_usb_open: more than one "
|
|
|
|
"configuration (%d), choosing first config (%d)\n",
|
|
|
|
pDevDesc->bNumConfigurations,
|
|
|
|
pCfgDesc->bConfigurationValue);
|
|
|
|
}
|
|
|
|
DBG (5, "UsbDeviceSetConfiguration parameters: dh = %p, bConfigurationValue = %d\n",
|
|
|
|
dh,pCfgDesc->bConfigurationValue);
|
|
|
|
result = UsbDeviceSetConfiguration (dh,
|
|
|
|
pCfgDesc->bConfigurationValue);
|
|
|
|
DBG (1, "sanei_usb_open: UsbDeviceSetConfiguration rc = %d\n",result);
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
SANE_Status status = SANE_STATUS_INVAL;
|
|
|
|
DBG (1, "sanei_usb_open: usbcalls complained on UsbDeviceSetConfiguration, rc= %d\n", result);
|
|
|
|
status = SANE_STATUS_ACCESS_DENIED;
|
|
|
|
UsbClose (dh);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now we look for usable endpoints */
|
|
|
|
|
|
|
|
for (pDescHead = (struct usb_descriptor_header *) (pCurPtr+pCfgDesc->bLength);
|
|
|
|
pDescHead;pDescHead = GetNextDescriptor(pDescHead,pEndPtr) )
|
|
|
|
{
|
|
|
|
switch(pDescHead->bDescriptorType)
|
|
|
|
{
|
|
|
|
case USB_DT_INTERFACE:
|
|
|
|
interface = (struct usb_interface_descriptor *) pDescHead;
|
|
|
|
DBG (5, "Found %d endpoints\n",interface->bNumEndpoints);
|
2005-08-09 16:28:38 +00:00
|
|
|
DBG (5, "bAlternateSetting = %d\n",interface->bAlternateSetting);
|
2005-08-07 14:26:33 +00:00
|
|
|
break;
|
|
|
|
case USB_DT_ENDPOINT:
|
|
|
|
endpoint = (struct usb_endpoint_descriptor*)pDescHead;
|
|
|
|
address = endpoint->bEndpointAddress;
|
|
|
|
direction = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
|
|
|
|
transfer_type = endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK;
|
|
|
|
/* save the endpoints we need later */
|
|
|
|
if (transfer_type == USB_ENDPOINT_TYPE_INTERRUPT)
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_open: found interupt-%s endpoint (address %2x)\n",
|
|
|
|
direction ? "in" : "out", address);
|
|
|
|
if (direction) /* in */
|
|
|
|
{
|
|
|
|
if (devices[devcount].int_in_ep)
|
|
|
|
DBG (3, "sanei_usb_open: we already have a int-in endpoint "
|
|
|
|
"(address: %d), ignoring the new one\n",
|
|
|
|
devices[devcount].int_in_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].int_in_ep = endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (devices[devcount].int_out_ep)
|
|
|
|
DBG (3, "sanei_usb_open: we already have a int-out endpoint "
|
|
|
|
"(address: %d), ignoring the new one\n",
|
|
|
|
devices[devcount].int_out_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].int_out_ep = endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
else if (transfer_type == USB_ENDPOINT_TYPE_BULK)
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_open: found bulk-%s endpoint (address %2x)\n",
|
|
|
|
direction ? "in" : "out", address);
|
|
|
|
if (direction) /* in */
|
|
|
|
{
|
|
|
|
if (devices[devcount].bulk_in_ep)
|
|
|
|
DBG (3, "sanei_usb_open: we already have a bulk-in endpoint "
|
|
|
|
"(address: %d), ignoring the new one\n",
|
|
|
|
devices[devcount].bulk_in_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].bulk_in_ep = endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (devices[devcount].bulk_out_ep)
|
|
|
|
DBG (3, "sanei_usb_open: we already have a bulk-out endpoint "
|
|
|
|
"(address: %d), ignoring the new one\n",
|
|
|
|
devices[devcount].bulk_out_ep);
|
|
|
|
else
|
|
|
|
devices[devcount].bulk_out_ep = endpoint->bEndpointAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* ignore currently unsupported endpoints */
|
|
|
|
else {
|
|
|
|
DBG (5, "sanei_usb_open: ignoring %s-%s endpoint "
|
|
|
|
"(address: %d)\n",
|
|
|
|
transfer_type == USB_ENDPOINT_TYPE_CONTROL ? "control" :
|
|
|
|
transfer_type == USB_ENDPOINT_TYPE_ISOCHRONOUS
|
|
|
|
? "isochronous" : "interrupt",
|
|
|
|
direction ? "in" : "out", address);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
DBG (1, "sanei_usb_open: can't open device `%s': "
|
|
|
|
"usbcalls support missing\n", devname);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* HAVE_USBCALLS */
|
|
|
|
}
|
2003-01-22 16:54:14 +00:00
|
|
|
else
|
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (1, "sanei_usb_open: access method %d not implemented\n",
|
|
|
|
devices[devcount].method);
|
2003-01-22 16:54:14 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2002-07-03 14:07:44 +00:00
|
|
|
devices[devcount].open = SANE_TRUE;
|
2002-07-03 19:48:45 +00:00
|
|
|
*dn = devcount;
|
|
|
|
DBG (3, "sanei_usb_open: opened usb device `%s' (*dn=%d)\n",
|
2002-07-03 14:07:44 +00:00
|
|
|
devname, devcount);
|
2001-08-11 13:12:39 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-07-03 19:48:45 +00:00
|
|
|
sanei_usb_close (SANE_Int dn)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
DBG (5, "sanei_usb_close: closing device %d\n", dn);
|
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
DBG (1, "sanei_usb_close: dn >= MAX_DEVICES || dn < 0\n");
|
2002-07-03 14:07:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2002-07-17 17:56:26 +00:00
|
|
|
if (!devices[dn].open)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_close: device %d already closed or never opened\n",
|
|
|
|
dn);
|
|
|
|
return;
|
|
|
|
}
|
2002-07-03 19:48:45 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
close (devices[dn].fd);
|
2005-08-07 14:26:33 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_usbcalls)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
int rc;
|
|
|
|
rc=UsbClose (dh);
|
|
|
|
DBG (5,"rc of UsbClose = %d\n",rc);
|
|
|
|
#else
|
|
|
|
DBG (1, "sanei_usb_close: usbcalls support missing\n");
|
|
|
|
#endif
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
else
|
|
|
|
#ifdef HAVE_LIBUSB
|
2002-12-30 13:51:10 +00:00
|
|
|
{
|
2003-01-15 14:27:54 +00:00
|
|
|
#if 0
|
|
|
|
/* Should only be done in case of a stall */
|
2002-12-30 13:51:10 +00:00
|
|
|
usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_in_ep);
|
|
|
|
usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_out_ep);
|
2005-04-15 20:48:24 +00:00
|
|
|
usb_clear_halt (devices[dn].libusb_handle, devices[dn].iso_in_ep);
|
2003-01-15 14:27:54 +00:00
|
|
|
/* be careful, we don't know if we are in DATA0 stage now */
|
2005-04-15 20:48:24 +00:00
|
|
|
usb_resetep (devices[dn].libusb_handle, devices[dn].bulk_in_ep);
|
|
|
|
usb_resetep (devices[dn].libusb_handle, devices[dn].bulk_out_ep);
|
|
|
|
usb_resetep (devices[dn].libusb_handle, devices[dn].iso_in_ep);
|
2003-01-15 14:27:54 +00:00
|
|
|
#endif
|
2005-04-15 20:48:24 +00:00
|
|
|
usb_release_interface (devices[dn].libusb_handle,
|
2002-12-30 13:51:10 +00:00
|
|
|
devices[dn].interface_nr);
|
|
|
|
usb_close (devices[dn].libusb_handle);
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
#else
|
|
|
|
DBG (1, "sanei_usb_close: libusb support missing\n");
|
|
|
|
#endif
|
2002-07-03 19:48:45 +00:00
|
|
|
devices[dn].open = SANE_FALSE;
|
2001-08-11 13:12:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-07-15 09:02:02 +00:00
|
|
|
void
|
|
|
|
sanei_usb_set_timeout (SANE_Int timeout)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
libusb_timeout = timeout;
|
|
|
|
#else
|
2005-08-09 16:28:38 +00:00
|
|
|
DBG (1, "sanei_usb_set_timeout: libusb support missing\n");
|
2005-07-15 09:02:02 +00:00
|
|
|
#endif /* HAVE_LIBUSB */
|
|
|
|
}
|
|
|
|
|
2001-08-11 13:12:39 +00:00
|
|
|
SANE_Status
|
2002-07-03 19:48:45 +00:00
|
|
|
sanei_usb_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2002-07-03 14:07:44 +00:00
|
|
|
ssize_t read_size = 0;
|
2001-08-11 13:12:39 +00:00
|
|
|
|
|
|
|
if (!size)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_bulk: size == NULL\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
DBG (1, "sanei_usb_read_bulk: dn >= MAX_DEVICES || dn < 0\n");
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2003-04-02 18:05:01 +00:00
|
|
|
DBG (5, "sanei_usb_read_bulk: trying to read %lu bytes\n",
|
|
|
|
(unsigned long) *size);
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
read_size = read (devices[dn].fd, buffer, *size);
|
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
2002-07-03 14:07:44 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
if (devices[dn].bulk_in_ep)
|
|
|
|
read_size = usb_bulk_read (devices[dn].libusb_handle,
|
|
|
|
devices[dn].bulk_in_ep, (char *) buffer,
|
2002-07-03 14:07:44 +00:00
|
|
|
(int) *size, libusb_timeout);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in "
|
|
|
|
"endpoint\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_bulk: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
2005-08-07 14:26:33 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_usbcalls)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
int rc;
|
2005-11-02 19:22:06 +00:00
|
|
|
char* buffer_ptr = (char*) buffer;
|
2005-08-07 14:26:33 +00:00
|
|
|
while (*size)
|
|
|
|
{
|
|
|
|
ULONG ulToRead = (*size>MAX_RW)?MAX_RW:*size;
|
|
|
|
ULONG ulNum = ulToRead;
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkRead with dn = %d\n",dn);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkRead with dh = %p\n",dh);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkRead with bulk_in_ep = 0x%02x\n",devices[dn].bulk_in_ep);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkRead with interface_nr = %d\n",devices[dn].interface_nr);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkRead with usbcalls_timeout = %d\n",usbcalls_timeout);
|
|
|
|
|
|
|
|
if (devices[dn].bulk_in_ep){
|
|
|
|
rc = UsbBulkRead (dh, devices[dn].bulk_in_ep, devices[dn].interface_nr,
|
2005-11-02 19:22:06 +00:00
|
|
|
&ulToRead, buffer_ptr, usbcalls_timeout);
|
2005-08-07 14:26:33 +00:00
|
|
|
DBG (1, "sanei_usb_read_bulk: rc = %d\n",rc);}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in endpoint\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
if (rc || (ulNum!=ulToRead)) return SANE_STATUS_INVAL;
|
|
|
|
*size -=ulToRead;
|
2005-11-02 19:22:06 +00:00
|
|
|
buffer_ptr += ulToRead;
|
2005-08-07 14:26:33 +00:00
|
|
|
read_size += ulToRead;
|
|
|
|
}
|
|
|
|
#else /* not HAVE_USBCALLS */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_bulk: usbcalls support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_USBCALLS */
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_bulk: access method %d not implemented\n",
|
2002-07-03 19:48:45 +00:00
|
|
|
devices[dn].method);
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2001-08-11 13:12:39 +00:00
|
|
|
if (read_size < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_bulk: read failed: %s\n", strerror (errno));
|
2002-12-30 13:51:10 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
2003-02-18 20:14:08 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_libusb)
|
|
|
|
usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_in_ep);
|
2002-12-30 13:51:10 +00:00
|
|
|
#endif
|
2001-08-11 13:12:39 +00:00
|
|
|
*size = 0;
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
if (read_size == 0)
|
|
|
|
{
|
|
|
|
DBG (3, "sanei_usb_read_bulk: read returned EOF\n");
|
|
|
|
*size = 0;
|
|
|
|
return SANE_STATUS_EOF;
|
|
|
|
}
|
2003-04-02 18:05:01 +00:00
|
|
|
if (debug_level > 10)
|
|
|
|
print_buffer (buffer, read_size);
|
2001-08-26 10:39:54 +00:00
|
|
|
DBG (5, "sanei_usb_read_bulk: wanted %lu bytes, got %ld bytes\n",
|
2002-07-03 14:07:44 +00:00
|
|
|
(unsigned long) *size, (unsigned long) read_size);
|
2001-08-11 13:12:39 +00:00
|
|
|
*size = read_size;
|
2005-04-15 20:48:24 +00:00
|
|
|
|
2001-08-11 13:12:39 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
SANE_Status
|
2002-07-14 16:31:14 +00:00
|
|
|
sanei_usb_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size)
|
2001-08-11 13:12:39 +00:00
|
|
|
{
|
2002-07-03 14:07:44 +00:00
|
|
|
ssize_t write_size = 0;
|
2001-08-11 13:12:39 +00:00
|
|
|
|
|
|
|
if (!size)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_write_bulk: size == NULL\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
DBG (1, "sanei_usb_write_bulk: dn >= MAX_DEVICES || dn < 0\n");
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2003-04-02 18:05:01 +00:00
|
|
|
DBG (5, "sanei_usb_write_bulk: trying to write %lu bytes\n",
|
|
|
|
(unsigned long) *size);
|
|
|
|
if (debug_level > 10)
|
|
|
|
print_buffer (buffer, *size);
|
2002-07-03 14:07:44 +00:00
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
write_size = write (devices[dn].fd, buffer, *size);
|
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
2002-07-03 14:07:44 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
2002-10-15 08:42:42 +00:00
|
|
|
if (devices[dn].bulk_out_ep)
|
2002-07-03 19:48:45 +00:00
|
|
|
write_size = usb_bulk_write (devices[dn].libusb_handle,
|
2002-07-14 16:31:14 +00:00
|
|
|
devices[dn].bulk_out_ep,
|
|
|
|
(const char *) buffer,
|
2002-07-03 14:07:44 +00:00
|
|
|
(int) *size, libusb_timeout);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_write_bulk: can't write without a bulk-out "
|
|
|
|
"endpoint\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_write_bulk: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
2005-08-07 14:26:33 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_usbcalls)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
int rc;
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkWrite with dn = %d\n",dn);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkWrite with dh = %p\n",dh);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkWrite with bulk_out_ep = 0x%02x\n",devices[dn].bulk_out_ep);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkWrite with interface_nr = %d\n",devices[dn].interface_nr);
|
|
|
|
DBG (5, "Entered usbcalls UsbBulkWrite with usbcalls_timeout = %d\n",usbcalls_timeout);
|
|
|
|
while (*size)
|
|
|
|
{
|
|
|
|
ULONG ulToWrite = (*size>MAX_RW)?MAX_RW:*size;
|
|
|
|
|
|
|
|
DBG (5, "size requested to write = %lu, ulToWrite = %lu\n",(unsigned long) *size,ulToWrite);
|
|
|
|
if (devices[dn].bulk_out_ep){
|
|
|
|
rc = UsbBulkWrite (dh, devices[dn].bulk_out_ep, devices[dn].interface_nr,
|
|
|
|
ulToWrite, (char*) buffer, usbcalls_timeout);
|
|
|
|
DBG (1, "sanei_usb_write_bulk: rc = %d\n",rc);}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_write_bulk: can't read without a bulk-out endpoint\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
if (rc) return SANE_STATUS_INVAL;
|
|
|
|
*size -=ulToWrite;
|
|
|
|
buffer += ulToWrite;
|
|
|
|
write_size += ulToWrite;
|
|
|
|
DBG (5, "size = %d, write_size = %d\n",*size, write_size);
|
|
|
|
}
|
|
|
|
#else /* not HAVE_USBCALLS */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_write_bulk: usbcalls support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_USBCALLS */
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
else
|
|
|
|
{
|
2004-02-04 20:27:58 +00:00
|
|
|
DBG (1, "sanei_usb_write_bulk: access method %d not implemented\n",
|
2002-07-03 19:48:45 +00:00
|
|
|
devices[dn].method);
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2001-08-11 13:12:39 +00:00
|
|
|
if (write_size < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_write_bulk: write failed: %s\n", strerror (errno));
|
|
|
|
*size = 0;
|
2002-12-30 13:51:10 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
2003-02-18 20:14:08 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_libusb)
|
|
|
|
usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_out_ep);
|
2002-12-30 13:51:10 +00:00
|
|
|
#endif
|
2001-08-11 13:12:39 +00:00
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
2001-08-26 10:39:54 +00:00
|
|
|
DBG (5, "sanei_usb_write_bulk: wanted %lu bytes, wrote %ld bytes\n",
|
2002-07-03 14:07:44 +00:00
|
|
|
(unsigned long) *size, (unsigned long) write_size);
|
2001-08-11 13:12:39 +00:00
|
|
|
*size = write_size;
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
2002-01-03 19:18:27 +00:00
|
|
|
|
|
|
|
SANE_Status
|
2002-07-03 19:48:45 +00:00
|
|
|
sanei_usb_control_msg (SANE_Int dn, SANE_Int rtype, SANE_Int req,
|
2002-07-03 14:07:44 +00:00
|
|
|
SANE_Int value, SANE_Int index, SANE_Int len,
|
|
|
|
SANE_Byte * data)
|
2002-01-03 19:18:27 +00:00
|
|
|
{
|
2002-07-03 19:48:45 +00:00
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2005-04-15 20:48:24 +00:00
|
|
|
DBG (1, "sanei_usb_control_msg: dn >= MAX_DEVICES || dn < 0, dn=%d\n",
|
|
|
|
dn);
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2003-04-02 18:05:01 +00:00
|
|
|
DBG (5, "sanei_usb_control_msg: rtype = 0x%02x, req = %d, value = %d, "
|
|
|
|
"index = %d, len = %d\n", rtype, req, value, index, len);
|
|
|
|
if (!(rtype & 0x80) && debug_level > 10)
|
|
|
|
print_buffer (data, len);
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
2002-01-03 19:18:27 +00:00
|
|
|
#if defined(__linux__)
|
2002-07-03 14:07:44 +00:00
|
|
|
struct ctrlmsg_ioctl c;
|
|
|
|
|
|
|
|
c.req.requesttype = rtype;
|
|
|
|
c.req.request = req;
|
|
|
|
c.req.value = value;
|
|
|
|
c.req.index = index;
|
|
|
|
c.req.length = len;
|
|
|
|
c.data = data;
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
if (ioctl (devices[dn].fd, SCANNER_IOCTL_CTRLMSG, &c) < 0)
|
2002-07-03 14:07:44 +00:00
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n",
|
|
|
|
strerror (errno));
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
2003-04-02 18:05:01 +00:00
|
|
|
if ((rtype & 0x80) && debug_level > 10)
|
|
|
|
print_buffer (data, len);
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
2005-07-15 21:59:25 +00:00
|
|
|
#elif defined(__BEOS__)
|
|
|
|
struct usb_scanner_ioctl_ctrlmsg c;
|
|
|
|
|
|
|
|
c.req.request_type = rtype;
|
|
|
|
c.req.request = req;
|
|
|
|
c.req.value = value;
|
|
|
|
c.req.index = index;
|
|
|
|
c.req.length = len;
|
|
|
|
c.data = data;
|
|
|
|
|
|
|
|
if (ioctl (devices[dn].fd, B_SCANNER_IOCTL_CTRLMSG, &c) < 0)
|
|
|
|
{
|
|
|
|
DBG (5, "sanei_usb_control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n",
|
|
|
|
strerror (errno));
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
if ((rtype & 0x80) && debug_level > 10)
|
|
|
|
print_buffer (data, len);
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
2002-07-03 14:07:44 +00:00
|
|
|
#else /* not __linux__ */
|
|
|
|
DBG (5, "sanei_usb_control_msg: not supported on this OS\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* not __linux__ */
|
|
|
|
}
|
2002-07-03 19:48:45 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
2002-07-03 14:07:44 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
2002-07-03 19:48:45 +00:00
|
|
|
result = usb_control_msg (devices[dn].libusb_handle, rtype, req,
|
2002-07-03 14:07:44 +00:00
|
|
|
value, index, (char *) data, len,
|
|
|
|
libusb_timeout);
|
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_control_msg: libusb complained: %s\n",
|
|
|
|
usb_strerror ());
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2003-04-02 18:05:01 +00:00
|
|
|
if ((rtype & 0x80) && debug_level > 10)
|
|
|
|
print_buffer (data, len);
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_control_msg: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
2005-08-07 14:26:33 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_usbcalls)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = UsbCtrlMessage (dh, rtype, req,
|
|
|
|
value, index, len, (char *) data,
|
|
|
|
usbcalls_timeout);
|
|
|
|
DBG (5, "rc of usb_control_msg = %d\n",result);
|
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_control_msg: usbcalls complained: %d\n",result);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
if ((rtype & 0x80) && debug_level > 10)
|
|
|
|
print_buffer (data, len);
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
#else /* not HAVE_USBCALLS */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_control_msg: usbcalls support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_USBCALLS */
|
|
|
|
}
|
2002-07-03 14:07:44 +00:00
|
|
|
else
|
|
|
|
{
|
2003-04-02 18:05:01 +00:00
|
|
|
DBG (1, "sanei_usb_control_msg: access method %d not implemented\n",
|
2002-07-03 19:48:45 +00:00
|
|
|
devices[dn].method);
|
2002-07-03 14:07:44 +00:00
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
2002-01-03 19:18:27 +00:00
|
|
|
}
|
|
|
|
}
|
2003-03-24 01:36:27 +00:00
|
|
|
|
|
|
|
SANE_Status
|
|
|
|
sanei_usb_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size)
|
|
|
|
{
|
|
|
|
ssize_t read_size = 0;
|
2006-05-26 07:58:15 +00:00
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
SANE_Bool stalled = SANE_FALSE;
|
|
|
|
#endif
|
2003-03-24 01:36:27 +00:00
|
|
|
|
|
|
|
if (!size)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: size == NULL\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: dn >= MAX_DEVICES || dn < 0\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2005-04-15 20:48:24 +00:00
|
|
|
|
2004-11-19 16:44:32 +00:00
|
|
|
DBG (5, "sanei_usb_read_int: trying to read %lu bytes\n",
|
|
|
|
(unsigned long) *size);
|
2005-04-15 20:48:24 +00:00
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: access method %d not implemented\n",
|
2003-03-24 01:36:27 +00:00
|
|
|
devices[dn].method);
|
2005-04-15 20:48:24 +00:00
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2003-03-24 01:36:27 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
|
|
|
if (devices[dn].int_in_ep)
|
2004-11-19 16:44:32 +00:00
|
|
|
read_size = usb_interrupt_read (devices[dn].libusb_handle,
|
2005-04-15 20:48:24 +00:00
|
|
|
devices[dn].int_in_ep,
|
|
|
|
(char *) buffer, (int) *size,
|
|
|
|
libusb_timeout);
|
2003-03-24 01:36:27 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: can't read without an int "
|
|
|
|
"endpoint\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
2006-05-26 07:58:15 +00:00
|
|
|
stalled = (read_size == -EPIPE);
|
2003-03-24 01:36:27 +00:00
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
2005-08-07 14:26:33 +00:00
|
|
|
else if (devices[dn].method == sanei_usb_method_usbcalls)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_USBCALLS
|
|
|
|
int rc;
|
|
|
|
USHORT usNumBytes=*size;
|
2005-08-09 16:28:38 +00:00
|
|
|
DBG (5, "Entered usbcalls UsbIrqStart with dn = %d\n",dn);
|
|
|
|
DBG (5, "Entered usbcalls UsbIrqStart with dh = %p\n",dh);
|
|
|
|
DBG (5, "Entered usbcalls UsbIrqStart with int_in_ep = 0x%02x\n",devices[dn].int_in_ep);
|
|
|
|
DBG (5, "Entered usbcalls UsbIrqStart with interface_nr = %d\n",devices[dn].interface_nr);
|
|
|
|
DBG (5, "Entered usbcalls UsbIrqStart with bytes to read = %u\n",usNumBytes);
|
2005-08-07 14:26:33 +00:00
|
|
|
|
|
|
|
if (devices[dn].int_in_ep){
|
|
|
|
rc = UsbIrqStart (dh,devices[dn].int_in_ep,devices[dn].interface_nr,
|
2005-08-09 16:28:38 +00:00
|
|
|
usNumBytes, (char *) buffer, pUsbIrqStartHev);
|
2005-08-07 14:26:33 +00:00
|
|
|
DBG (5, "rc of UsbIrqStart = %d\n",rc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: can't read without an int "
|
|
|
|
"endpoint\n");
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
if (rc) return SANE_STATUS_INVAL;
|
|
|
|
read_size += usNumBytes;
|
|
|
|
#else
|
|
|
|
DBG (1, "sanei_usb_read_int: usbcalls support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* HAVE_USBCALLS */
|
|
|
|
}
|
2003-03-24 01:36:27 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: access method %d not implemented\n",
|
|
|
|
devices[dn].method);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (read_size < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_read_int: read failed: %s\n", strerror (errno));
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
if (devices[dn].method == sanei_usb_method_libusb)
|
2006-05-26 07:58:15 +00:00
|
|
|
if (stalled)
|
|
|
|
usb_clear_halt (devices[dn].libusb_handle, devices[dn].int_in_ep);
|
2003-03-24 01:36:27 +00:00
|
|
|
#endif
|
|
|
|
*size = 0;
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
if (read_size == 0)
|
|
|
|
{
|
|
|
|
DBG (3, "sanei_usb_read_int: read returned EOF\n");
|
|
|
|
*size = 0;
|
|
|
|
return SANE_STATUS_EOF;
|
|
|
|
}
|
|
|
|
DBG (5, "sanei_usb_read_int: wanted %lu bytes, got %ld bytes\n",
|
|
|
|
(unsigned long) *size, (unsigned long) read_size);
|
|
|
|
*size = read_size;
|
2003-04-02 18:05:01 +00:00
|
|
|
if (debug_level > 10)
|
|
|
|
print_buffer (buffer, read_size);
|
2005-04-15 20:48:24 +00:00
|
|
|
|
2003-03-24 01:36:27 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
2005-04-15 20:48:24 +00:00
|
|
|
|
|
|
|
SANE_Status
|
|
|
|
sanei_usb_set_configuration (SANE_Int dn, SANE_Int configuration)
|
|
|
|
{
|
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_set_configuration: dn >= MAX_DEVICES || dn < 0, dn=%d\n",
|
|
|
|
dn);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG (5, "sanei_usb_set_configuration: configuration = %d\n", configuration);
|
|
|
|
|
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
{
|
|
|
|
#if defined(__linux__)
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
#else /* not __linux__ */
|
|
|
|
DBG (5, "sanei_usb_set_configuration: not supported on this OS\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* not __linux__ */
|
|
|
|
}
|
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result =
|
|
|
|
usb_set_configuration (devices[dn].libusb_handle, configuration);
|
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_set_configuration: libusb complained: %s\n",
|
|
|
|
usb_strerror ());
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_set_configuration: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_set_configuration: access method %d not implemented\n",
|
|
|
|
devices[dn].method);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SANE_Status
|
2006-02-04 20:51:07 +00:00
|
|
|
sanei_usb_claim_interface (SANE_Int dn, SANE_Int interface_number)
|
2005-04-15 20:48:24 +00:00
|
|
|
{
|
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_claim_interface: dn >= MAX_DEVICES || dn < 0, dn=%d\n",
|
|
|
|
dn);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2006-02-04 20:51:07 +00:00
|
|
|
DBG (5, "sanei_usb_claim_interface: interface_number = %d\n", interface_number);
|
2005-04-15 20:48:24 +00:00
|
|
|
|
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
{
|
|
|
|
#if defined(__linux__)
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
#else /* not __linux__ */
|
|
|
|
DBG (5, "sanei_usb_claim_interface: not supported on this OS\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* not __linux__ */
|
|
|
|
}
|
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
2006-02-04 20:51:07 +00:00
|
|
|
result = usb_claim_interface (devices[dn].libusb_handle, interface_number);
|
2005-04-15 20:48:24 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_claim_interface: libusb complained: %s\n",
|
|
|
|
usb_strerror ());
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_claim_interface: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_claim_interface: access method %d not implemented\n",
|
|
|
|
devices[dn].method);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SANE_Status
|
2006-02-04 20:51:07 +00:00
|
|
|
sanei_usb_release_interface (SANE_Int dn, SANE_Int interface_number)
|
2005-04-15 20:48:24 +00:00
|
|
|
{
|
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_release_interface: dn >= MAX_DEVICES || dn < 0, dn=%d\n",
|
|
|
|
dn);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
2006-02-04 20:51:07 +00:00
|
|
|
DBG (5, "sanei_usb_release_interface: interface_number = %d\n", interface_number);
|
2005-04-15 20:48:24 +00:00
|
|
|
|
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
{
|
|
|
|
#if defined(__linux__)
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
#else /* not __linux__ */
|
|
|
|
DBG (5, "sanei_usb_release_interface: not supported on this OS\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* not __linux__ */
|
|
|
|
}
|
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
2006-02-04 20:51:07 +00:00
|
|
|
result = usb_release_interface (devices[dn].libusb_handle, interface_number);
|
2005-04-15 20:48:24 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_release_interface: libusb complained: %s\n",
|
|
|
|
usb_strerror ());
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_release_interface: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_release_interface: access method %d not implemented\n",
|
|
|
|
devices[dn].method);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SANE_Status
|
|
|
|
sanei_usb_set_altinterface (SANE_Int dn, SANE_Int alternate)
|
|
|
|
{
|
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_set_altinterface: dn >= MAX_DEVICES || dn < 0, dn=%d\n",
|
|
|
|
dn);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG (5, "sanei_usb_set_altinterface: alternate = %d\n", alternate);
|
|
|
|
|
|
|
|
if (devices[dn].method == sanei_usb_method_scanner_driver)
|
|
|
|
{
|
|
|
|
#if defined(__linux__)
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
#else /* not __linux__ */
|
|
|
|
DBG (5, "sanei_usb_set_altinterface: not supported on this OS\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
#endif /* not __linux__ */
|
|
|
|
}
|
|
|
|
else if (devices[dn].method == sanei_usb_method_libusb)
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = usb_set_altinterface (devices[dn].libusb_handle, alternate);
|
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_set_altinterface: libusb complained: %s\n",
|
|
|
|
usb_strerror ());
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_set_altinterface: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_set_altinterface: access method %d not implemented\n",
|
|
|
|
devices[dn].method);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
2007-11-16 08:46:32 +00:00
|
|
|
|
|
|
|
extern SANE_Status
|
|
|
|
sanei_usb_get_descriptor( SANE_Int dn, struct sanei_usb_dev_descriptor *desc )
|
|
|
|
{
|
|
|
|
if (dn >= MAX_DEVICES || dn < 0)
|
|
|
|
{
|
|
|
|
DBG (1,
|
|
|
|
"sanei_usb_get_descriptor: dn >= MAX_DEVICES || dn < 0, dn=%d\n",
|
|
|
|
dn);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG (5, "sanei_usb_get_descriptor\n");
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
{
|
|
|
|
struct usb_device_descriptor *usb_descr;
|
|
|
|
|
|
|
|
usb_descr = &(devices[dn].libusb_device->descriptor);
|
|
|
|
desc->desc_type = usb_descr->bDescriptorType;
|
|
|
|
desc->bcd_usb = usb_descr->bcdUSB;
|
|
|
|
desc->bcd_dev = usb_descr->bcdDevice;
|
|
|
|
desc->dev_class = usb_descr->bDeviceClass;
|
|
|
|
|
|
|
|
desc->dev_sub_class = usb_descr->bDeviceSubClass;
|
|
|
|
desc->dev_protocol = usb_descr->bDeviceProtocol;
|
|
|
|
desc->max_packet_size = usb_descr->bMaxPacketSize0;
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
#else /* not HAVE_LIBUSB */
|
|
|
|
{
|
|
|
|
DBG (1, "sanei_usb_get_descriptor: libusb support missing\n");
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
#endif /* not HAVE_LIBUSB */
|
|
|
|
}
|