kopia lustrzana https://gitlab.com/sane-project/backends
372 wiersze
9.8 KiB
C
372 wiersze
9.8 KiB
C
/* sane - Scanner Access Now Easy.
|
|
Copyright (C) 2001 Henning Meier-Geinitz
|
|
Copyright (C) 2001 Frank Zago (sanei_usb_control_msg)
|
|
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.
|
|
|
|
This file provides a generic (?) USB interface. */
|
|
|
|
#include "../include/sane/config.h"
|
|
|
|
#include <stdlib.h>
|
|
#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>
|
|
|
|
#define BACKEND_NAME sanei_usb
|
|
#include "../include/sane/sane.h"
|
|
#include "../include/sane/sanei_debug.h"
|
|
#include "../include/sane/sanei_usb.h"
|
|
#include "../include/sane/sanei_config.h"
|
|
|
|
#if defined (__linux__)
|
|
|
|
/* 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)
|
|
|
|
/* From /usr/src/linux/include/linux/usb.h */
|
|
typedef struct {
|
|
unsigned char requesttype;
|
|
unsigned char request;
|
|
unsigned short value;
|
|
unsigned short index;
|
|
unsigned short length;
|
|
} devrequest __attribute__ ((packed));
|
|
|
|
/* From /usr/src/linux/driver/usb/scanner.h */
|
|
struct ctrlmsg_ioctl {
|
|
devrequest req;
|
|
void *data;
|
|
} cmsg;
|
|
|
|
#endif /* __linux__ */
|
|
|
|
|
|
void
|
|
sanei_usb_init (void)
|
|
{
|
|
DBG_INIT();
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
else
|
|
(*attach) (name);
|
|
}
|
|
|
|
SANE_Status
|
|
sanei_usb_get_vendor_product (SANE_Int fd, SANE_Word * vendor,
|
|
SANE_Word * product)
|
|
{
|
|
SANE_Word vendorID, productID;
|
|
|
|
#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, "sanei_usb_get_vendor_product: ioctl (vendor) of fd %d "
|
|
"failed: %s\n", fd, strerror (errno));
|
|
/* just set the vendor ID to 0 */
|
|
vendorID = 0;
|
|
}
|
|
}
|
|
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) of fd %d "
|
|
"failed: %s\n", fd, strerror (errno));
|
|
/* just set the product ID to 0 */
|
|
productID = 0;
|
|
}
|
|
}
|
|
if (vendor)
|
|
*vendor = vendorID;
|
|
if (product)
|
|
*product = productID;
|
|
#else /* not defined (__linux__) */
|
|
vendorID = 0;
|
|
productID = 0;
|
|
#endif /* not defined (__linux__) */
|
|
|
|
if (!vendorID || !productID)
|
|
{
|
|
DBG (3, "sanei_usb_get_vendor_product: fd %d: Your OS doesn't seem to "
|
|
"support detection of vendor+product ids\n",
|
|
fd);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
DBG (3, "sanei_usb_get_vendor_product: fd %d: vendorID: 0x%x, "
|
|
"productID: 0x%x\n", fd, vendorID, productID);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
|
|
|
|
static SANE_Status
|
|
check_vendor_product (SANE_String_Const devname, SANE_Word vendor,
|
|
SANE_Word product,
|
|
SANE_Status (*attach) (SANE_String_Const dev))
|
|
{
|
|
SANE_Status status;
|
|
SANE_Word devvendor, devproduct;
|
|
SANE_Int fd;
|
|
|
|
status = sanei_usb_open (devname, &fd);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return status;
|
|
|
|
status = sanei_usb_get_vendor_product (fd, &devvendor, &devproduct);
|
|
sanei_usb_close (fd);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
if (devvendor == vendor && devproduct == product)
|
|
{
|
|
if (attach)
|
|
attach (devname);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
SANE_Status
|
|
sanei_usb_find_devices (SANE_Int vendor, SANE_Int product,
|
|
SANE_Status (*attach) (SANE_String_Const dev))
|
|
{
|
|
SANE_String *prefix;
|
|
SANE_String prefixlist[] = {
|
|
#if defined(__linux__)
|
|
"/dev/usbscanner",
|
|
"/dev/usb/scanner",
|
|
#elif defined(__FreeBSD__)
|
|
"/dev/uscanner",
|
|
#endif
|
|
0};
|
|
SANE_Char devname[30];
|
|
int devcount;
|
|
SANE_Status status;
|
|
|
|
#define SANEI_USB_MAX_DEVICES 16
|
|
|
|
DBG (3, "sanei_usb_find_devices: vendor=0x%x, product=0x%x, attach=%p\n",
|
|
vendor, product, attach);
|
|
|
|
for (prefix = prefixlist; *prefix; prefix++)
|
|
{
|
|
status = check_vendor_product (*prefix, vendor, product, attach);
|
|
if (status == SANE_STATUS_UNSUPPORTED)
|
|
return status; /* give up if we can't detect vendor/product */
|
|
for (devcount = 0; devcount < SANEI_USB_MAX_DEVICES;
|
|
devcount++)
|
|
{
|
|
snprintf (devname, sizeof (devname), "%s%d", *prefix,
|
|
devcount);
|
|
status = check_vendor_product (devname, vendor, product, attach);
|
|
if (status == SANE_STATUS_UNSUPPORTED)
|
|
return status; /* give up if we can't detect vendor/product */
|
|
}
|
|
}
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sanei_usb_open (SANE_String_Const devname, SANE_Int *fd)
|
|
{
|
|
if (!fd)
|
|
{
|
|
DBG (1, "sanei_usb_open: fd == NULL\n");
|
|
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));
|
|
if (errno == EACCES)
|
|
status = SANE_STATUS_ACCESS_DENIED;
|
|
return status;
|
|
}
|
|
DBG (5, "sanei_usb_open: fd %d opened\n", *fd);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
void
|
|
sanei_usb_close (SANE_Int fd)
|
|
{
|
|
DBG (5, "sanei_usb_close: closing fd %d\n", fd);
|
|
close (fd);
|
|
return;
|
|
}
|
|
|
|
SANE_Status
|
|
sanei_usb_read_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size)
|
|
{
|
|
ssize_t read_size;
|
|
|
|
if (!size)
|
|
{
|
|
DBG (1, "sanei_usb_read_bulk: size == NULL\n");
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
read_size = read (fd, buffer, *size);
|
|
if (read_size < 0)
|
|
{
|
|
DBG (1, "sanei_usb_read_bulk: read failed: %s\n", strerror (errno));
|
|
*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;
|
|
}
|
|
DBG (5, "sanei_usb_read_bulk: wanted %lu bytes, got %ld bytes\n",
|
|
(unsigned long) *size, (unsigned long) read_size);
|
|
*size = read_size;
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sanei_usb_write_bulk (SANE_Int fd, SANE_Byte * buffer, size_t *size)
|
|
{
|
|
ssize_t write_size;
|
|
|
|
if (!size)
|
|
{
|
|
DBG (1, "sanei_usb_write_bulk: size == NULL\n");
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
write_size = write (fd, buffer, *size);
|
|
if (write_size < 0)
|
|
{
|
|
DBG (1, "sanei_usb_write_bulk: write failed: %s\n", strerror (errno));
|
|
*size = 0;
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
DBG (5, "sanei_usb_write_bulk: wanted %lu bytes, wrote %ld bytes\n",
|
|
(unsigned long) *size, (unsigned long) write_size);
|
|
*size = write_size;
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sanei_usb_control_msg(SANE_Int fd, SANE_Int rtype, SANE_Int req,
|
|
SANE_Int value, SANE_Int index, SANE_Int len,
|
|
SANE_Byte *data )
|
|
{
|
|
#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(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
|
|
DBG (5, "sanei_usb_control_msg: not supported on this OS\n");
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
#endif /* __linux__ */
|
|
}
|