Added support for libusb.

Henning Meier-Geinitz <henning@meier-geinitz.de>
DEVEL_2_0_BRANCH-1
Henning Geinitz 2002-07-03 14:07:44 +00:00
rodzic a8c8969925
commit e3476bd389
2 zmienionych plików z 578 dodań i 102 usunięć

Wyświetl plik

@ -1,5 +1,5 @@
/* sane - Scanner Access Now Easy. /* sane - Scanner Access Now Easy.
Copyright (C) 2001 Henning Meier-Geinitz Copyright (C) 2001, 2002 Henning Meier-Geinitz
This file is part of the SANE package. This file is part of the SANE package.
SANE is free software; you can redistribute it and/or modify it SANE is free software; you can redistribute it and/or modify it
@ -20,10 +20,12 @@
/** @file sanei_usb.h /** @file sanei_usb.h
* This file provides a generic USB interface. * This file provides a generic USB interface.
* *
* Currently, only access to device files as provided by the Linux USB * Currently, two access methods to USB devices are provided:
* scanner driver is supported. FreeBSD and OpenBSD with their uscanner * - Access to device
* drivers also work. However, detection and control messages aren't * files as used by the Linux kernel USB scanner driver is supported. FreeBSD
* supported on these platforms. * and OpenBSD with their uscanner drivers also work this way. However,
* detection and control messages aren't supported on these platforms.
* - Access using libusb (where available).
* *
* @sa sanei_lm983x.h, sanei_pa4s2.h, sanei_pio.h, sanei_scsi.h, and <a * @sa sanei_lm983x.h, sanei_pa4s2.h, sanei_pio.h, sanei_scsi.h, and <a
* href="http://www.mostang.com/sane/man/sane-usb.5.html">man sane-usb(5)</a> * href="http://www.mostang.com/sane/man/sane-usb.5.html">man sane-usb(5)</a>
@ -36,12 +38,90 @@
#include "../include/sane/config.h" #include "../include/sane/config.h"
#include "../include/sane/sane.h" #include "../include/sane/sane.h"
/* USB spec defines */
#ifndef USB_CLASS_PER_INTERFACE
/* Also defined in libusb */
/* Device and/or interface class codes */
#define USB_CLASS_PER_INTERFACE 0x00
#define USB_CLASS_AUDIO 0x01
#define USB_CLASS_COMM 0x02
#define USB_CLASS_HID 0x03
#define USB_CLASS_PRINTER 0x07
#define USB_CLASS_MASS_STORAGE 0x08
#define USB_CLASS_HUB 0x09
#define USB_CLASS_DATA 0x0a
#define USB_CLASS_VENDOR_SPEC 0xff
/* USB descriptor types */
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_HID 0x21
#define USB_DT_REPORT 0x22
#define USB_DT_PHYSICAL 0x23
#define USB_DT_HUB 0x29
/* Descriptor sizes per descriptor type */
#define USB_DT_DEVICE_SIZE 18
#define USB_DT_CONFIG_SIZE 9
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9
#define USB_DT_HUB_NONVAR_SIZE 7
/* Endpoint descriptor values */
#define USB_ENDPOINT_ADDRESS_MASK 0x0f
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_ENDPOINT_TYPE_MASK 0x03
#define USB_ENDPOINT_TYPE_CONTROL 0
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
#define USB_ENDPOINT_TYPE_BULK 2
#define USB_ENDPOINT_TYPE_INTERRUPT 3
/* Standard requests */
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
/* USB types */
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
/* USB recipients */
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
#endif /* not USB_CLASS_PER_INTERFACE */
/* Not defined in libsub */
#define USB_TYPE_MASK (0x03 << 5)
#define USB_RECIP_MASK 0x1f
/* USB directions */
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
/** Initialize sanei_usb. /** Initialize sanei_usb.
* *
* Call this before any other sanei_usb function. * Call this before any other sanei_usb function.
*/ */
extern void extern void sanei_usb_init (void);
sanei_usb_init (void);
/** Get the vendor and product ids. /** Get the vendor and product ids.
* *
@ -89,15 +169,13 @@ sanei_usb_find_devices (SANE_Int vendor, SANE_Int product,
* permissions * permissions
* - SANE_STATUS_INVAL - on every other error * - SANE_STATUS_INVAL - on every other error
*/ */
extern SANE_Status extern SANE_Status sanei_usb_open (SANE_String_Const devname, SANE_Int * fd);
sanei_usb_open (SANE_String_Const devname, SANE_Int *fd);
/** Close a USB device. /** Close a USB device.
* *
* @param fd file descriptor of the device * @param fd file descriptor of the device
*/ */
extern void extern void sanei_usb_close (SANE_Int fd);
sanei_usb_close (SANE_Int fd);
/** Initiate a bulk transfer read. /** Initiate a bulk transfer read.
* *
@ -114,9 +192,9 @@ sanei_usb_close (SANE_Int fd);
* - SANE_STATUS_IO_ERROR - if an error occured during the read * - SANE_STATUS_IO_ERROR - if an error occured during the read
* - SANE_STATUS_INVAL - on every other error * - SANE_STATUS_INVAL - on every other error
* *
*/ */
extern SANE_Status extern SANE_Status
sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size); sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t * size);
/** Initiate a bulk transfer write. /** Initiate a bulk transfer write.
* *
@ -133,7 +211,7 @@ sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size);
* - SANE_STATUS_INVAL - on every other error * - SANE_STATUS_INVAL - on every other error
*/ */
extern SANE_Status extern SANE_Status
sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size); sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t * size);
/** Send/receive a control message to/from a USB device. /** Send/receive a control message to/from a USB device.
* *
@ -162,7 +240,7 @@ sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size);
extern SANE_Status extern SANE_Status
sanei_usb_control_msg (SANE_Int fd, SANE_Int rtype, SANE_Int req, sanei_usb_control_msg (SANE_Int fd, SANE_Int rtype, SANE_Int req,
SANE_Int value, SANE_Int index, SANE_Int len, SANE_Int value, SANE_Int index, SANE_Int len,
SANE_Byte *data); SANE_Byte * data);
/** Expand device name patterns into a list of devices. /** Expand device name patterns into a list of devices.
* *
@ -179,7 +257,7 @@ sanei_usb_control_msg (SANE_Int fd, SANE_Int rtype, SANE_Int req,
* @param attach attach function * @param attach attach function
* *
*/ */
extern void extern void
sanei_usb_attach_matching_devices (const char *name, sanei_usb_attach_matching_devices (const char *name,
SANE_Status (*attach) (const char *dev)); SANE_Status (*attach) (const char *dev));

Wyświetl plik

@ -1,5 +1,5 @@
/* sane - Scanner Access Now Easy. /* sane - Scanner Access Now Easy.
Copyright (C) 2001 Henning Meier-Geinitz Copyright (C) 2001, 2002 Henning Meier-Geinitz
Copyright (C) 2001 Frank Zago (sanei_usb_control_msg) Copyright (C) 2001 Frank Zago (sanei_usb_control_msg)
This file is part of the SANE package. This file is part of the SANE package.
@ -39,7 +39,7 @@
whether to permit this exception to apply to your modifications. whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice. If you do not wish that, delete this exception notice.
This file provides a generic (?) USB interface. */ This file provides a generic USB interface. */
#include "../include/sane/config.h" #include "../include/sane/config.h"
@ -53,14 +53,47 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <stdio.h> #include <stdio.h>
#ifdef HAVE_LIBUSB
#include <usb.h>
#endif /* HAVE_LIBUSB */
#define BACKEND_NAME sanei_usb #define BACKEND_NAME sanei_usb
#include "../include/sane/sane.h" #include "../include/sane/sane.h"
#include "../include/sane/sanei_debug.h" #include "../include/sane/sanei_debug.h"
#include "../include/sane/sanei_usb.h" #include "../include/sane/sanei_usb.h"
#include "../include/sane/sanei_config.h" #include "../include/sane/sanei_config.h"
#if defined (__linux__) typedef enum
{
sanei_usb_method_scanner_driver = 0, /* kernel scanner driver
(Linux, BSD) */
sanei_usb_method_libusb
}
sanei_usb_access_method_type;
typedef struct
{
SANE_Bool open;
sanei_usb_access_method_type method;
int fd;
SANE_Int bulk_in_ep;
SANE_Int bulk_out_ep;
#ifdef HAVE_LIBUSB
usb_dev_handle *libusb_handle;
#endif /* HAVE_LIBUSB */
}
device_list_type;
#define MAX_DEVICES 100
/* per-device information, using the functions fd as index */
static device_list_type devices[MAX_DEVICES];
#ifdef HAVE_LIBUSB
int libusb_timeout = 30 * 1000; /* 30 seconds */
#endif /* HAVE_LIBUSB */
#if defined (__linux__)
/* From /usr/src/linux/driver/usb/scanner.h */ /* From /usr/src/linux/driver/usb/scanner.h */
#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int) #define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int) #define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
@ -69,30 +102,46 @@
#define SCANNER_IOCTL_VENDOR_OLD _IOR('u', 0xa0, int) #define SCANNER_IOCTL_VENDOR_OLD _IOR('u', 0xa0, int)
#define SCANNER_IOCTL_PRODUCT_OLD _IOR('u', 0xa1, int) #define SCANNER_IOCTL_PRODUCT_OLD _IOR('u', 0xa1, int)
/* From /usr/src/linux/include/linux/usb.h */ /* From /usr/src/linux/include/linux/usb.h */
typedef struct { typedef struct
{
unsigned char requesttype; unsigned char requesttype;
unsigned char request; unsigned char request;
unsigned short value; unsigned short value;
unsigned short index; unsigned short index;
unsigned short length; unsigned short length;
} devrequest __attribute__ ((packed)); }
devrequest __attribute__ ((packed));
/* From /usr/src/linux/driver/usb/scanner.h */ /* From /usr/src/linux/driver/usb/scanner.h */
struct ctrlmsg_ioctl { struct ctrlmsg_ioctl
devrequest req; {
void *data; devrequest req;
} cmsg; void *data;
}
cmsg;
#endif /* __linux__ */ #endif /* __linux__ */
void void
sanei_usb_init (void) sanei_usb_init (void)
{ {
DBG_INIT(); DBG_INIT ();
memset (devices, 0, sizeof (devices));
#ifdef HAVE_LIBUSB
usb_init ();
#ifdef DBG_LEVEL
if (DBG_LEVEL > 4)
usb_set_debug (255);
#endif /* DBG_LEVEL */
usb_find_busses ();
usb_find_devices ();
#endif /* HAVE_LIBUSB */
} }
/* This logically belongs to sanei_config.c but not every backend that /* This logically belongs to sanei_config.c but not every backend that
uses sanei_config() wants to depend on sanei_usb. */ uses sanei_config() wants to depend on sanei_usb. */
void void
@ -131,7 +180,7 @@ sanei_usb_attach_matching_devices (const char *name,
} }
sanei_usb_find_devices (vendorID, productID, attach); sanei_usb_find_devices (vendorID, productID, attach);
} }
else else
(*attach) (name); (*attach) (name);
} }
@ -142,38 +191,66 @@ sanei_usb_get_vendor_product (SANE_Int fd, SANE_Word * vendor,
SANE_Word vendorID = 0; SANE_Word vendorID = 0;
SANE_Word productID = 0; SANE_Word productID = 0;
if (fd >= MAX_DEVICES || fd < 0)
{
DBG (1, "sanei_usb_get_vendor_product: fd >= MAX_DEVICES || fd < 0\n");
return SANE_STATUS_INVAL;
}
if (devices[fd].method == sanei_usb_method_scanner_driver)
{
#if defined (__linux__) #if defined (__linux__)
/* read the vendor and product IDs via the IOCTLs */ /* read the vendor and product IDs via the IOCTLs */
if (ioctl (fd, SCANNER_IOCTL_VENDOR , &vendorID) == -1) if (ioctl (devices[fd].fd, SCANNER_IOCTL_VENDOR, &vendorID) == -1)
{ {
if (ioctl (fd, SCANNER_IOCTL_VENDOR_OLD , &vendorID) == -1) if (ioctl (devices[fd].fd, SCANNER_IOCTL_VENDOR_OLD, &vendorID)
DBG (3, "sanei_usb_get_vendor_product: ioctl (vendor) of fd %d " == -1)
"failed: %s\n", fd, strerror (errno)); DBG (3, "sanei_usb_get_vendor_product: ioctl (vendor) "
"of device %d failed: %s\n", fd, strerror (errno));
}
if (ioctl (devices[fd].fd, SCANNER_IOCTL_PRODUCT, &productID) == -1)
{
if (ioctl (devices[fd].fd, SCANNER_IOCTL_PRODUCT_OLD,
&productID) == -1)
DBG (3, "sanei_usb_get_vendor_product: ioctl (product) "
"of device %d failed: %s\n", fd, strerror (errno));
}
#endif /* defined (__linux__) */
/* put more os-dependant stuff ... */
} }
if (ioctl (fd, SCANNER_IOCTL_PRODUCT , &productID) == -1) else if (devices[fd].method == sanei_usb_method_libusb)
{ {
if (ioctl (fd, SCANNER_IOCTL_PRODUCT_OLD , &productID) == -1) #ifdef HAVE_LIBUSB
DBG (3, "sanei_usb_get_vendor_product: ioctl (product) of fd %d " vendorID = usb_device (devices[fd].libusb_handle)->descriptor.idVendor;
"failed: %s\n", fd, strerror (errno)); productID =
usb_device (devices[fd].libusb_handle)->descriptor.idProduct;
#else
DBG (1, "sanei_usb_get_vendor_product: libusb support missing\n");
return SANE_STATUS_UNSUPPORTED;
#endif /* HAVE_LIBUSB */
} }
else
{
DBG (1, "sanei_usb_get_vendor_product: access method %d not "
"implemented\n", devices[fd].method);
return SANE_STATUS_INVAL;
}
if (vendor) if (vendor)
*vendor = vendorID; *vendor = vendorID;
if (product) if (product)
*product = productID; *product = productID;
#endif /* not defined (__linux__) */
if (!vendorID || !productID) if (!vendorID || !productID)
{ {
DBG (3, "sanei_usb_get_vendor_product: fd %d: Your OS doesn't seem to " DBG (3, "sanei_usb_get_vendor_product: device %d: Your OS doesn't "
"support detection of vendor+product ids\n", "seem to support detection of vendor+product ids\n", fd);
fd);
return SANE_STATUS_UNSUPPORTED; return SANE_STATUS_UNSUPPORTED;
} }
else else
{ {
DBG (3, "sanei_usb_get_vendor_product: fd %d: vendorID: 0x%x, " DBG (3, "sanei_usb_get_vendor_product: device %d: vendorID: 0x%04x, "
"productID: 0x%x\n", fd, vendorID, productID); "productID: 0x%04x\n", fd, vendorID, productID);
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }
} }
@ -217,68 +294,285 @@ sanei_usb_find_devices (SANE_Int vendor, SANE_Int product,
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
"/dev/uscanner", "/dev/uscanner",
#endif #endif
0}; 0
SANE_Char devname[30]; };
SANE_Char devname[1024];
int devcount; int devcount;
SANE_Status status; SANE_Status status;
#define SANEI_USB_MAX_DEVICES 16 #define SANEI_USB_MAX_DEVICE_FILES 16
DBG (3, "sanei_usb_find_devices: vendor=0x%x, product=0x%x, attach=%p\n", DBG (3,
"sanei_usb_find_devices: vendor=0x%04x, product=0x%04x, attach=%p\n",
vendor, product, attach); vendor, product, attach);
/* First we check the device files for access over the kernel scanner
drivers */
for (prefix = prefixlist; *prefix; prefix++) for (prefix = prefixlist; *prefix; prefix++)
{ {
status = check_vendor_product (*prefix, vendor, product, attach); status = check_vendor_product (*prefix, vendor, product, attach);
if (status == SANE_STATUS_UNSUPPORTED) if (status == SANE_STATUS_UNSUPPORTED)
return status; /* give up if we can't detect vendor/product */ break; /* give up if we can't detect vendor/product */
for (devcount = 0; devcount < SANEI_USB_MAX_DEVICES; for (devcount = 0; devcount < SANEI_USB_MAX_DEVICE_FILES; devcount++)
devcount++)
{ {
snprintf (devname, sizeof (devname), "%s%d", *prefix, snprintf (devname, sizeof (devname), "%s%d", *prefix, devcount);
devcount);
status = check_vendor_product (devname, vendor, product, attach); status = check_vendor_product (devname, vendor, product, attach);
if (status == SANE_STATUS_UNSUPPORTED) if (status == SANE_STATUS_UNSUPPORTED)
return status; /* give up if we can't detect vendor/product */ break; /* give up if we can't detect vendor/product */
} }
} }
/* Now we will check all the devices libusb finds (if available) */
#ifdef HAVE_LIBUSB
{
struct usb_bus *bus;
struct usb_device *dev;
for (bus = usb_get_busses (); bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if (dev->descriptor.idVendor == vendor
&& dev->descriptor.idProduct == product)
{
DBG (3,
"sanei_usb_find_devices: found matching libusb device "
"(bus=%s, filename=%s, vendor=0x%04x, product=0x%04x)\n",
bus->dirname, dev->filename, dev->descriptor.idVendor,
dev->descriptor.idProduct);
snprintf (devname, sizeof (devname), "libusb:%s:%s",
bus->dirname, dev->filename);
attach (devname);
}
else
DBG (5, "sanei_usb_find_devices: found libusb device "
"(bus=%s, filename=%s, vendor=0x%04x, product=0x%04x)\n",
bus->dirname, dev->filename, dev->descriptor.idVendor,
dev->descriptor.idProduct);
}
}
}
#endif /* HAVE_LIBUSB */
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }
SANE_Status SANE_Status
sanei_usb_open (SANE_String_Const devname, SANE_Int *fd) sanei_usb_open (SANE_String_Const devname, SANE_Int * fd)
{ {
int devcount;
if (!fd) if (!fd)
{ {
DBG (1, "sanei_usb_open: fd == NULL\n"); DBG (1, "sanei_usb_open: can't open `%s': fd == NULL\n", devname);
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
} }
*fd = open (devname, O_RDWR);
if (*fd < 0)
{
SANE_Status status = SANE_STATUS_INVAL;
DBG (1, "sanei_usb_open: open failed: %s\n", strerror (errno)); for (devcount = 0;
if (errno == EACCES) devcount < MAX_DEVICES && devices[devcount].open == SANE_TRUE;
status = SANE_STATUS_ACCESS_DENIED; devcount++)
return status; ;
if (devices[devcount].open)
{
DBG (1, "sanei_usb_open: can't open `%s': "
"maximum amount of devices (%d) reached\n", devname, MAX_DEVICES);
return SANE_STATUS_NO_MEM;
} }
DBG (5, "sanei_usb_open: fd %d opened\n", *fd);
memset (&devices[devcount], 0, sizeof (devices[devcount]));
if (strncmp (devname, "libusb:", 7) == 0)
{
/* Using libusb */
#ifdef HAVE_LIBUSB
SANE_String start, end, bus_string, dev_string;
struct usb_bus *bus;
struct usb_device *dev;
struct usb_interface_descriptor *interface;
SANE_Int result;
int num;
DBG (5, "sanei_usb_open: trying to open device `%s'\n", devname);
start = strchr (devname, ':');
if (!start)
return SANE_STATUS_INVAL;
start++;
end = strchr (start, ':');
if (!end)
return SANE_STATUS_INVAL;
bus_string = strndup (start, end - start);
if (!bus_string)
return SANE_STATUS_NO_MEM;
start = strchr (start, ':');
if (!start)
return SANE_STATUS_INVAL;
start++;
dev_string = strdup (start);
if (!dev_string)
return SANE_STATUS_NO_MEM;
for (bus = usb_get_busses (); bus; bus = bus->next)
{
if (strcmp (bus->dirname, bus_string) == 0)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if (strcmp (dev->filename, dev_string) == 0)
devices[devcount].libusb_handle = usb_open (dev);
}
}
}
if (!devices[devcount].libusb_handle)
{
DBG (1, "sanei_usb_open: can't open device `%s': "
"not found or libusb error (%s)\n", devname, strerror (errno));
return SANE_STATUS_INVAL;
}
devices[devcount].method = sanei_usb_method_libusb;
dev = usb_device (devices[devcount].libusb_handle);
if (dev->descriptor.bNumConfigurations > 1)
{
DBG (3, "sanei_usb_open: more than one "
"configuration (%d), choosing config 0\n",
dev->descriptor.bNumConfigurations);
}
if (dev->config[0].interface->num_altsetting > 1)
{
DBG (3, "sanei_usb_open: more than one "
"alternate setting (%d), choosing interface 0\n",
dev->config[0].interface->num_altsetting);
}
result = usb_claim_interface (devices[devcount].libusb_handle, 0);
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;
}
interface = &dev->config[0].interface->altsetting[0];
/* 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];
address = endpoint->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
direction = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
transfer_type = endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK;
if (transfer_type != USB_ENDPOINT_TYPE_BULK)
{
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;
}
DBG (5, "sanei_usb_open: found bulk-%s endpoint (address %d)\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 = address;
}
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 = address;
}
}
#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 */
}
else
{
/* Using kernel scanner driver */
devices[devcount].fd = open (devname, O_RDWR);
if (devices[devcount].fd < 0)
{
SANE_Status status = SANE_STATUS_INVAL;
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;
}
devices[devcount].method = sanei_usb_method_scanner_driver;
}
devices[devcount].open = SANE_TRUE;
*fd = devcount;
DBG (3, "sanei_usb_open: opened usb device `%s' (*fd=%d)\n",
devname, devcount);
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }
void void
sanei_usb_close (SANE_Int fd) sanei_usb_close (SANE_Int fd)
{ {
DBG (5, "sanei_usb_close: closing fd %d\n", fd); DBG (5, "sanei_usb_close: closing device %d\n", fd);
close (fd); if (fd >= MAX_DEVICES || fd < 0)
{
DBG (1, "sanei_usb_close: fd >= MAX_DEVICES || fd < 0\n");
return;
}
if (devices[fd].method == sanei_usb_method_scanner_driver)
close (devices[fd].fd);
else
#ifdef HAVE_LIBUSB
usb_close (devices[fd].libusb_handle);
#else
DBG (1, "sanei_usb_close: libusb support missing\n");
#endif
devices[fd].open = SANE_FALSE;
return; return;
} }
SANE_Status SANE_Status
sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size) sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t * size)
{ {
ssize_t read_size; ssize_t read_size = 0;
if (!size) if (!size)
{ {
@ -286,7 +580,40 @@ sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size)
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
} }
read_size = read (fd, buffer, *size); if (fd >= MAX_DEVICES || fd < 0)
{
DBG (1, "sanei_usb_read_bulk: fd >= MAX_DEVICES || fd < 0\n");
return SANE_STATUS_INVAL;
}
if (devices[fd].method == sanei_usb_method_scanner_driver)
read_size = read (devices[fd].fd, buffer, *size);
else if (devices[fd].method == sanei_usb_method_libusb)
#ifdef HAVE_LIBUSB
{
if (devices[fd].bulk_in_ep)
read_size = usb_bulk_read (devices[fd].libusb_handle,
devices[fd].bulk_in_ep, (char *) buffer,
(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 */
else
{
DBG (1, "sanei_usb_read_bulk: access method %d not implemented\n",
devices[fd].method);
return SANE_STATUS_INVAL;
}
if (read_size < 0) if (read_size < 0)
{ {
DBG (1, "sanei_usb_read_bulk: read failed: %s\n", strerror (errno)); DBG (1, "sanei_usb_read_bulk: read failed: %s\n", strerror (errno));
@ -300,15 +627,15 @@ sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size)
return SANE_STATUS_EOF; return SANE_STATUS_EOF;
} }
DBG (5, "sanei_usb_read_bulk: wanted %lu bytes, got %ld bytes\n", DBG (5, "sanei_usb_read_bulk: wanted %lu bytes, got %ld bytes\n",
(unsigned long) *size, (unsigned long) read_size); (unsigned long) *size, (unsigned long) read_size);
*size = read_size; *size = read_size;
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }
SANE_Status SANE_Status
sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size) sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t * size)
{ {
ssize_t write_size; ssize_t write_size = 0;
if (!size) if (!size)
{ {
@ -316,7 +643,41 @@ sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size)
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
} }
write_size = write (fd, buffer, *size); if (fd >= MAX_DEVICES || fd < 0)
{
DBG (1, "sanei_usb_write_bulk: fd >= MAX_DEVICES || fd < 0\n");
return SANE_STATUS_INVAL;
}
if (devices[fd].method == sanei_usb_method_scanner_driver)
write_size = write (devices[fd].fd, buffer, *size);
else if (devices[fd].method == sanei_usb_method_libusb)
#ifdef HAVE_LIBUSB
{
if (devices[fd].bulk_in_ep)
write_size = usb_bulk_write (devices[fd].libusb_handle,
devices[fd].bulk_out_ep, (char *) buffer,
(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 */
else
{
DBG (1, "sanei_usb_read_bulk: access method %d not implemented\n",
devices[fd].method);
return SANE_STATUS_INVAL;
}
if (write_size < 0) if (write_size < 0)
{ {
DBG (1, "sanei_usb_write_bulk: write failed: %s\n", strerror (errno)); DBG (1, "sanei_usb_write_bulk: write failed: %s\n", strerror (errno));
@ -324,38 +685,75 @@ sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size)
return SANE_STATUS_IO_ERROR; return SANE_STATUS_IO_ERROR;
} }
DBG (5, "sanei_usb_write_bulk: wanted %lu bytes, wrote %ld bytes\n", DBG (5, "sanei_usb_write_bulk: wanted %lu bytes, wrote %ld bytes\n",
(unsigned long) *size, (unsigned long) write_size); (unsigned long) *size, (unsigned long) write_size);
*size = write_size; *size = write_size;
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }
SANE_Status SANE_Status
sanei_usb_control_msg(SANE_Int fd, SANE_Int rtype, SANE_Int req, sanei_usb_control_msg (SANE_Int fd, SANE_Int rtype, SANE_Int req,
SANE_Int value, SANE_Int index, SANE_Int len, SANE_Int value, SANE_Int index, SANE_Int len,
SANE_Byte *data ) SANE_Byte * data)
{ {
#if defined(__linux__) if (fd >= MAX_DEVICES || fd < 0)
struct ctrlmsg_ioctl c;
c.req.requesttype = rtype;
c.req.request = req;
c.req.value = value;
c.req.index = index;
c.req.length = len;
c.data = data;
DBG(5, "sanei_usb_control_msg: rtype = 0x%02x, req = %d, value = %d, "
"index = %d, len = %d\n", rtype, req, value, index, len);
if (ioctl(fd, SCANNER_IOCTL_CTRLMSG, &c) < 0)
{ {
DBG(5, "sanei_usb_control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n", DBG (1, "sanei_usb_control_msg: fd >= MAX_DEVICES || fd < 0\n");
strerror(errno)); return SANE_STATUS_INVAL;
return SANE_STATUS_IO_ERROR; }
if (devices[fd].method == sanei_usb_method_scanner_driver)
{
#if defined(__linux__)
struct ctrlmsg_ioctl c;
c.req.requesttype = rtype;
c.req.request = req;
c.req.value = value;
c.req.index = index;
c.req.length = len;
c.data = data;
DBG (5, "sanei_usb_control_msg: rtype = 0x%02x, req = %d, value = %d, "
"index = %d, len = %d\n", rtype, req, value, index, len);
if (ioctl (devices[fd].fd, SCANNER_IOCTL_CTRLMSG, &c) < 0)
{
DBG (5, "sanei_usb_control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n",
strerror (errno));
return SANE_STATUS_IO_ERROR;
}
return SANE_STATUS_GOOD;
#else /* not __linux__ */
DBG (5, "sanei_usb_control_msg: not supported on this OS\n");
return SANE_STATUS_UNSUPPORTED;
#endif /* not __linux__ */
}
else if (devices[fd].method == sanei_usb_method_libusb)
#ifdef HAVE_LIBUSB
{
int result;
result = usb_control_msg (devices[fd].libusb_handle, rtype, req,
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;
}
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 */
else
{
DBG (1, "sanei_usb_read_bulk: access method %d not implemented\n",
devices[fd].method);
return SANE_STATUS_UNSUPPORTED;
} }
return SANE_STATUS_GOOD;
#else
DBG (5, "sanei_usb_control_msg: not supported on this OS\n");
return SANE_STATUS_UNSUPPORTED;
#endif /* __linux__ */
} }