1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 2001 - 2005 Henning Meier-Geinitz 3141cc406Sopenharmony_ci Copyright (C) 2001 Frank Zago (sanei_usb_control_msg) 4141cc406Sopenharmony_ci Copyright (C) 2003 Rene Rebe (sanei_read_int,sanei_set_timeout) 5141cc406Sopenharmony_ci Copyright (C) 2005 Paul Smedley <paul@smedley.info> (OS/2 usbcalls) 6141cc406Sopenharmony_ci Copyright (C) 2008 m. allan noah (bus rescan support, sanei_usb_clear_halt) 7141cc406Sopenharmony_ci Copyright (C) 2009 Julien BLACHE <jb@jblache.org> (libusb-1.0) 8141cc406Sopenharmony_ci Copyright (C) 2011 Reinhold Kainhofer <reinhold@kainhofer.com> (sanei_usb_set_endpoint) 9141cc406Sopenharmony_ci This file is part of the SANE package. 10141cc406Sopenharmony_ci 11141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 12141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 13141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 14141cc406Sopenharmony_ci License, or (at your option) any later version. 15141cc406Sopenharmony_ci 16141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 17141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 18141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19141cc406Sopenharmony_ci General Public License for more details. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 22141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 25141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 28141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 29141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 30141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 31141cc406Sopenharmony_ci account of linking the SANE library code into it. 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 34141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 35141cc406Sopenharmony_ci License. 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 38141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 39141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 42141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 43141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 44141cc406Sopenharmony_ci 45141cc406Sopenharmony_ci This file provides a generic USB interface. */ 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci#include "../include/sane/config.h" 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_ci#ifdef HAVE_STDINT_H 50141cc406Sopenharmony_ci# include <stdint.h> 51141cc406Sopenharmony_ci#endif 52141cc406Sopenharmony_ci#include <stdlib.h> 53141cc406Sopenharmony_ci#include <ctype.h> 54141cc406Sopenharmony_ci#include <sys/types.h> 55141cc406Sopenharmony_ci#include <sys/stat.h> 56141cc406Sopenharmony_ci#include <fcntl.h> 57141cc406Sopenharmony_ci#include <errno.h> 58141cc406Sopenharmony_ci#include <string.h> 59141cc406Sopenharmony_ci#include <unistd.h> 60141cc406Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 61141cc406Sopenharmony_ci#include <sys/ioctl.h> 62141cc406Sopenharmony_ci#endif 63141cc406Sopenharmony_ci#include <stdio.h> 64141cc406Sopenharmony_ci#include <dirent.h> 65141cc406Sopenharmony_ci#include <time.h> 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 68141cc406Sopenharmony_ci#include <libxml/tree.h> 69141cc406Sopenharmony_ci#endif 70141cc406Sopenharmony_ci 71141cc406Sopenharmony_ci#ifdef HAVE_RESMGR 72141cc406Sopenharmony_ci#include <resmgr.h> 73141cc406Sopenharmony_ci#endif 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 76141cc406Sopenharmony_ci#ifdef HAVE_LUSB0_USB_H 77141cc406Sopenharmony_ci#include <lusb0_usb.h> 78141cc406Sopenharmony_ci#else 79141cc406Sopenharmony_ci#include <usb.h> 80141cc406Sopenharmony_ci#endif 81141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY */ 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB 84141cc406Sopenharmony_ci#include <libusb.h> 85141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB */ 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 88141cc406Sopenharmony_ci#include "usb_manager.h" 89141cc406Sopenharmony_ci#endif /* HAVE_USB_MANAGER */ 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 92141cc406Sopenharmony_ci#include <usb.h> 93141cc406Sopenharmony_ci#include <os2.h> 94141cc406Sopenharmony_ci#include <usbcalls.h> 95141cc406Sopenharmony_ci#define MAX_RW 64000 96141cc406Sopenharmony_cistatic int usbcalls_timeout = 30 * 1000; /* 30 seconds */ 97141cc406Sopenharmony_ciUSBHANDLE dh; 98141cc406Sopenharmony_ciPHEV pUsbIrqStartHev=NULL; 99141cc406Sopenharmony_ci 100141cc406Sopenharmony_cistatic 101141cc406Sopenharmony_cistruct usb_descriptor_header * 102141cc406Sopenharmony_ciGetNextDescriptor( struct usb_descriptor_header *currHead, UCHAR *lastBytePtr) 103141cc406Sopenharmony_ci{ 104141cc406Sopenharmony_ci UCHAR *currBytePtr, *nextBytePtr; 105141cc406Sopenharmony_ci 106141cc406Sopenharmony_ci if (!currHead->bLength) 107141cc406Sopenharmony_ci return (NULL); 108141cc406Sopenharmony_ci currBytePtr=(UCHAR *)currHead; 109141cc406Sopenharmony_ci nextBytePtr=currBytePtr+currHead->bLength; 110141cc406Sopenharmony_ci if (nextBytePtr>=lastBytePtr) 111141cc406Sopenharmony_ci return (NULL); 112141cc406Sopenharmony_ci return ((struct usb_descriptor_header*)nextBytePtr); 113141cc406Sopenharmony_ci} 114141cc406Sopenharmony_ci#endif /* HAVE_USBCALLS */ 115141cc406Sopenharmony_ci 116141cc406Sopenharmony_ci#if (defined (__FreeBSD__) && (__FreeBSD_version < 800064)) 117141cc406Sopenharmony_ci#include <sys/param.h> 118141cc406Sopenharmony_ci#include <dev/usb/usb.h> 119141cc406Sopenharmony_ci#endif /* __FreeBSD__ */ 120141cc406Sopenharmony_ci#if defined (__DragonFly__) 121141cc406Sopenharmony_ci#include <bus/usb/usb.h> 122141cc406Sopenharmony_ci#endif 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_ci#define BACKEND_NAME sanei_usb 125141cc406Sopenharmony_ci#include "../include/sane/sane.h" 126141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h" 127141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 128141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_citypedef enum 131141cc406Sopenharmony_ci{ 132141cc406Sopenharmony_ci sanei_usb_method_scanner_driver = 0, /* kernel scanner driver 133141cc406Sopenharmony_ci (Linux, BSD) */ 134141cc406Sopenharmony_ci sanei_usb_method_libusb, 135141cc406Sopenharmony_ci 136141cc406Sopenharmony_ci sanei_usb_method_usbcalls, 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci sanei_usb_method_usb_manager 139141cc406Sopenharmony_ci} 140141cc406Sopenharmony_cisanei_usb_access_method_type; 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_citypedef struct 143141cc406Sopenharmony_ci{ 144141cc406Sopenharmony_ci SANE_Bool open; 145141cc406Sopenharmony_ci sanei_usb_access_method_type method; 146141cc406Sopenharmony_ci int fd; 147141cc406Sopenharmony_ci SANE_String devname; 148141cc406Sopenharmony_ci SANE_Int vendor; 149141cc406Sopenharmony_ci SANE_Int product; 150141cc406Sopenharmony_ci SANE_Int bulk_in_ep; 151141cc406Sopenharmony_ci SANE_Int bulk_out_ep; 152141cc406Sopenharmony_ci SANE_Int iso_in_ep; 153141cc406Sopenharmony_ci SANE_Int iso_out_ep; 154141cc406Sopenharmony_ci SANE_Int int_in_ep; 155141cc406Sopenharmony_ci SANE_Int int_out_ep; 156141cc406Sopenharmony_ci SANE_Int control_in_ep; 157141cc406Sopenharmony_ci SANE_Int control_out_ep; 158141cc406Sopenharmony_ci SANE_Int interface_nr; 159141cc406Sopenharmony_ci SANE_Int alt_setting; 160141cc406Sopenharmony_ci SANE_Int missing; 161141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 162141cc406Sopenharmony_ci usb_dev_handle *libusb_handle; 163141cc406Sopenharmony_ci struct usb_device *libusb_device; 164141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY */ 165141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB 166141cc406Sopenharmony_ci libusb_device *lu_device; 167141cc406Sopenharmony_ci libusb_device_handle *lu_handle; 168141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB */ 169141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 170141cc406Sopenharmony_ci usb_manager_device *usb_manager_device; 171141cc406Sopenharmony_ci usb_manager_device_handle *usb_manager_handle; 172141cc406Sopenharmony_ci#endif /* HAVE_USB_MANAGER */ 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_ci} 175141cc406Sopenharmony_cidevice_list_type; 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_ci/** 178141cc406Sopenharmony_ci * total number of devices that can be found at the same time */ 179141cc406Sopenharmony_ci#define MAX_DEVICES 100 180141cc406Sopenharmony_ci 181141cc406Sopenharmony_ci/** 182141cc406Sopenharmony_ci * per-device information, using the functions' parameters dn as index */ 183141cc406Sopenharmony_cistatic device_list_type devices[MAX_DEVICES]; 184141cc406Sopenharmony_ci 185141cc406Sopenharmony_ci/** 186141cc406Sopenharmony_ci * total number of detected devices in devices array */ 187141cc406Sopenharmony_cistatic int device_number=0; 188141cc406Sopenharmony_ci 189141cc406Sopenharmony_ci/** 190141cc406Sopenharmony_ci * count number of time sanei_usb has been initialized */ 191141cc406Sopenharmony_cistatic int initialized=0; 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_citypedef enum 194141cc406Sopenharmony_ci{ 195141cc406Sopenharmony_ci sanei_usb_testing_mode_disabled = 0, 196141cc406Sopenharmony_ci 197141cc406Sopenharmony_ci sanei_usb_testing_mode_record, // records the communication with the slave 198141cc406Sopenharmony_ci // but does not change the USB stack in any 199141cc406Sopenharmony_ci // way 200141cc406Sopenharmony_ci sanei_usb_testing_mode_replay, // replays the communication with the scanner 201141cc406Sopenharmony_ci // recorded earlier 202141cc406Sopenharmony_ci} 203141cc406Sopenharmony_cisanei_usb_testing_mode; 204141cc406Sopenharmony_ci 205141cc406Sopenharmony_ci// Whether testing mode has been enabled 206141cc406Sopenharmony_cistatic sanei_usb_testing_mode testing_mode = sanei_usb_testing_mode_disabled; 207141cc406Sopenharmony_ci 208141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 209141cc406Sopenharmony_cistatic int testing_development_mode = 0; 210141cc406Sopenharmony_cistatic int testing_already_opened = 0; 211141cc406Sopenharmony_cistatic int testing_known_commands_input_failed = 0; 212141cc406Sopenharmony_cistatic unsigned testing_last_known_seq = 0; 213141cc406Sopenharmony_cistatic SANE_String testing_record_backend = NULL; 214141cc406Sopenharmony_cistatic xmlNode* testing_append_commands_node = NULL; 215141cc406Sopenharmony_ci 216141cc406Sopenharmony_ci// XML file from which we read testing data 217141cc406Sopenharmony_cistatic SANE_String testing_xml_path = NULL; 218141cc406Sopenharmony_cistatic xmlDoc* testing_xml_doc = NULL; 219141cc406Sopenharmony_cistatic xmlNode* testing_xml_next_tx_node = NULL; 220141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 221141cc406Sopenharmony_ci 222141cc406Sopenharmony_ci#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) 223141cc406Sopenharmony_cistatic int libusb_timeout = 30 * 1000; /* 30 seconds */ 224141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY */ 225141cc406Sopenharmony_ci 226141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 227141cc406Sopenharmony_cistatic int usb_manager_timeout = 30 * 1000; /* 30 seconds */ 228141cc406Sopenharmony_ci#endif /* HAVE_USB_MANAGER */ 229141cc406Sopenharmony_ci 230141cc406Sopenharmony_ci 231141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB 232141cc406Sopenharmony_cistatic libusb_context *sanei_usb_ctx; 233141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB */ 234141cc406Sopenharmony_ci 235141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 236141cc406Sopenharmony_cistatic usb_manager_context *sanei_usb_ctx; 237141cc406Sopenharmony_ci#endif /* HAVE_USB_MANAGER */ 238141cc406Sopenharmony_ci 239141cc406Sopenharmony_ci#if defined (__APPLE__) 240141cc406Sopenharmony_ci/* macOS won't configure several USB scanners (i.e. ScanSnap 300M) because their 241141cc406Sopenharmony_ci * descriptors are vendor specific. As a result the device will get configured 242141cc406Sopenharmony_ci * later during sanei_usb_open making it safe to ignore the configuration check 243141cc406Sopenharmony_ci * on these platforms. */ 244141cc406Sopenharmony_ci#define SANEI_ALLOW_UNCONFIGURED_DEVICES 245141cc406Sopenharmony_ci#endif 246141cc406Sopenharmony_ci 247141cc406Sopenharmony_ci#if defined (__linux__) 248141cc406Sopenharmony_ci/* From /usr/src/linux/driver/usb/scanner.h */ 249141cc406Sopenharmony_ci#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int) 250141cc406Sopenharmony_ci#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int) 251141cc406Sopenharmony_ci#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest) 252141cc406Sopenharmony_ci/* Older (unofficial) IOCTL numbers for Linux < v2.4.13 */ 253141cc406Sopenharmony_ci#define SCANNER_IOCTL_VENDOR_OLD _IOR('u', 0xa0, int) 254141cc406Sopenharmony_ci#define SCANNER_IOCTL_PRODUCT_OLD _IOR('u', 0xa1, int) 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci/* From /usr/src/linux/include/linux/usb.h */ 257141cc406Sopenharmony_citypedef struct 258141cc406Sopenharmony_ci{ 259141cc406Sopenharmony_ci unsigned char requesttype; 260141cc406Sopenharmony_ci unsigned char request; 261141cc406Sopenharmony_ci unsigned short value; 262141cc406Sopenharmony_ci unsigned short index; 263141cc406Sopenharmony_ci unsigned short length; 264141cc406Sopenharmony_ci} 265141cc406Sopenharmony_cidevrequest; 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci/* From /usr/src/linux/driver/usb/scanner.h */ 268141cc406Sopenharmony_cistruct ctrlmsg_ioctl 269141cc406Sopenharmony_ci{ 270141cc406Sopenharmony_ci devrequest req; 271141cc406Sopenharmony_ci void *data; 272141cc406Sopenharmony_ci} 273141cc406Sopenharmony_cicmsg; 274141cc406Sopenharmony_ci#elif defined(__BEOS__) 275141cc406Sopenharmony_ci#include <drivers/USB_scanner.h> 276141cc406Sopenharmony_ci#include <kernel/OS.h> 277141cc406Sopenharmony_ci#endif /* __linux__ */ 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci/* Debug level from sanei_init_debug */ 280141cc406Sopenharmony_cistatic SANE_Int debug_level; 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_cistatic void 283141cc406Sopenharmony_ciprint_buffer (const SANE_Byte * buffer, SANE_Int size) 284141cc406Sopenharmony_ci{ 285141cc406Sopenharmony_ci#define NUM_COLUMNS 16 286141cc406Sopenharmony_ci#define PRINT_BUFFER_SIZE (4 + NUM_COLUMNS * (3 + 1) + 1 + 1) 287141cc406Sopenharmony_ci char line_str[PRINT_BUFFER_SIZE]; 288141cc406Sopenharmony_ci char *pp; 289141cc406Sopenharmony_ci int column; 290141cc406Sopenharmony_ci int line; 291141cc406Sopenharmony_ci 292141cc406Sopenharmony_ci memset (line_str, 0, PRINT_BUFFER_SIZE); 293141cc406Sopenharmony_ci 294141cc406Sopenharmony_ci for (line = 0; line < ((size + NUM_COLUMNS - 1) / NUM_COLUMNS); line++) 295141cc406Sopenharmony_ci { 296141cc406Sopenharmony_ci pp = line_str; 297141cc406Sopenharmony_ci sprintf (pp, "%03X ", line * NUM_COLUMNS); 298141cc406Sopenharmony_ci pp += 4; 299141cc406Sopenharmony_ci for (column = 0; column < NUM_COLUMNS; column++) 300141cc406Sopenharmony_ci { 301141cc406Sopenharmony_ci if ((line * NUM_COLUMNS + column) < size) 302141cc406Sopenharmony_ci sprintf (pp, "%02X ", buffer[line * NUM_COLUMNS + column]); 303141cc406Sopenharmony_ci else 304141cc406Sopenharmony_ci sprintf (pp, " "); 305141cc406Sopenharmony_ci pp += 3; 306141cc406Sopenharmony_ci } 307141cc406Sopenharmony_ci for (column = 0; column < NUM_COLUMNS; column++) 308141cc406Sopenharmony_ci { 309141cc406Sopenharmony_ci if ((line * NUM_COLUMNS + column) < size) 310141cc406Sopenharmony_ci sprintf (pp, "%c", 311141cc406Sopenharmony_ci (buffer[line * NUM_COLUMNS + column] < 127) && 312141cc406Sopenharmony_ci (buffer[line * NUM_COLUMNS + column] > 31) ? 313141cc406Sopenharmony_ci buffer[line * NUM_COLUMNS + column] : '.'); 314141cc406Sopenharmony_ci else 315141cc406Sopenharmony_ci sprintf (pp, " "); 316141cc406Sopenharmony_ci pp += 1; 317141cc406Sopenharmony_ci } 318141cc406Sopenharmony_ci DBG (11, "%s\n", line_str); 319141cc406Sopenharmony_ci } 320141cc406Sopenharmony_ci} 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_ci#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) 323141cc406Sopenharmony_cistatic void 324141cc406Sopenharmony_cikernel_get_vendor_product (int fd, const char *name, int *vendorID, int *productID) 325141cc406Sopenharmony_ci{ 326141cc406Sopenharmony_ci#if defined (__linux__) 327141cc406Sopenharmony_ci /* read the vendor and product IDs via the IOCTLs */ 328141cc406Sopenharmony_ci if (ioctl (fd, SCANNER_IOCTL_VENDOR, vendorID) == -1) 329141cc406Sopenharmony_ci { 330141cc406Sopenharmony_ci if (ioctl (fd, SCANNER_IOCTL_VENDOR_OLD, vendorID) == -1) 331141cc406Sopenharmony_ci DBG (3, "kernel_get_vendor_product: ioctl (vendor) " 332141cc406Sopenharmony_ci "of device %s failed: %s\n", name, strerror (errno)); 333141cc406Sopenharmony_ci } 334141cc406Sopenharmony_ci if (ioctl (fd, SCANNER_IOCTL_PRODUCT, productID) == -1) 335141cc406Sopenharmony_ci { 336141cc406Sopenharmony_ci if (ioctl (fd, SCANNER_IOCTL_PRODUCT_OLD, productID) == -1) 337141cc406Sopenharmony_ci DBG (3, "sanei_usb_get_vendor_product: ioctl (product) " 338141cc406Sopenharmony_ci "of device %s failed: %s\n", name, strerror (errno)); 339141cc406Sopenharmony_ci } 340141cc406Sopenharmony_ci#elif defined(__BEOS__) 341141cc406Sopenharmony_ci { 342141cc406Sopenharmony_ci uint16 vendor, product; 343141cc406Sopenharmony_ci if (ioctl (fd, B_SCANNER_IOCTL_VENDOR, &vendor) != B_OK) 344141cc406Sopenharmony_ci DBG (3, "kernel_get_vendor_product: ioctl (vendor) " 345141cc406Sopenharmony_ci "of device %d failed: %s\n", fd, strerror (errno)); 346141cc406Sopenharmony_ci if (ioctl (fd, B_SCANNER_IOCTL_PRODUCT, &product) != B_OK) 347141cc406Sopenharmony_ci DBG (3, "sanei_usb_get_vendor_product: ioctl (product) " 348141cc406Sopenharmony_ci "of device %d failed: %s\n", fd, strerror (errno)); 349141cc406Sopenharmony_ci /* copy from 16 to 32 bit value */ 350141cc406Sopenharmony_ci *vendorID = vendor; 351141cc406Sopenharmony_ci *productID = product; 352141cc406Sopenharmony_ci } 353141cc406Sopenharmony_ci#elif (defined (__FreeBSD__) && __FreeBSD_version < 800064) || defined (__DragonFly__) 354141cc406Sopenharmony_ci { 355141cc406Sopenharmony_ci int controller; 356141cc406Sopenharmony_ci int ctrl_fd; 357141cc406Sopenharmony_ci char buf[40]; 358141cc406Sopenharmony_ci int dev; 359141cc406Sopenharmony_ci 360141cc406Sopenharmony_ci for (controller = 0; ; controller++ ) 361141cc406Sopenharmony_ci { 362141cc406Sopenharmony_ci snprintf (buf, sizeof (buf) - 1, "/dev/usb%d", controller); 363141cc406Sopenharmony_ci ctrl_fd = open (buf, O_RDWR); 364141cc406Sopenharmony_ci 365141cc406Sopenharmony_ci /* If we can not open the usb controller device, treat it 366141cc406Sopenharmony_ci as the end of controller devices */ 367141cc406Sopenharmony_ci if (ctrl_fd < 0) 368141cc406Sopenharmony_ci break; 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ci /* Search for the scanner device on this bus */ 371141cc406Sopenharmony_ci for (dev = 1; dev < USB_MAX_DEVICES; dev++) 372141cc406Sopenharmony_ci { 373141cc406Sopenharmony_ci struct usb_device_info devInfo; 374141cc406Sopenharmony_ci devInfo.udi_addr = dev; 375141cc406Sopenharmony_ci 376141cc406Sopenharmony_ci if (ioctl (ctrl_fd, USB_DEVICEINFO, &devInfo) == -1) 377141cc406Sopenharmony_ci break; /* Treat this as the end of devices for this controller */ 378141cc406Sopenharmony_ci 379141cc406Sopenharmony_ci snprintf (buf, sizeof (buf), "/dev/%s", devInfo.udi_devnames[0]); 380141cc406Sopenharmony_ci if (strncmp (buf, name, sizeof (buf)) == 0) 381141cc406Sopenharmony_ci { 382141cc406Sopenharmony_ci *vendorID = (int) devInfo.udi_vendorNo; 383141cc406Sopenharmony_ci *productID = (int) devInfo.udi_productNo; 384141cc406Sopenharmony_ci close (ctrl_fd); 385141cc406Sopenharmony_ci return; 386141cc406Sopenharmony_ci } 387141cc406Sopenharmony_ci } 388141cc406Sopenharmony_ci close (ctrl_fd); 389141cc406Sopenharmony_ci } 390141cc406Sopenharmony_ci DBG (3, "kernel_get_vendor_product: Could not retrieve " 391141cc406Sopenharmony_ci "vendor/product ID from device %s\n", name); 392141cc406Sopenharmony_ci } 393141cc406Sopenharmony_ci#endif /* defined (__linux__), defined(__BEOS__), ... */ 394141cc406Sopenharmony_ci /* put more os-dependant stuff ... */ 395141cc406Sopenharmony_ci} 396141cc406Sopenharmony_ci#endif /* !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) */ 397141cc406Sopenharmony_ci 398141cc406Sopenharmony_ci/** 399141cc406Sopenharmony_ci * store the given device in device list if it isn't already 400141cc406Sopenharmony_ci * in it 401141cc406Sopenharmony_ci * @param device device to store if new 402141cc406Sopenharmony_ci */ 403141cc406Sopenharmony_cistatic void 404141cc406Sopenharmony_cistore_device (device_list_type device) 405141cc406Sopenharmony_ci{ 406141cc406Sopenharmony_ci int i = 0; 407141cc406Sopenharmony_ci int pos = -1; 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_ci /* if there are already some devices present, check against 410141cc406Sopenharmony_ci * them and leave if an equal one is found */ 411141cc406Sopenharmony_ci for (i = 0; i < device_number; i++) 412141cc406Sopenharmony_ci { 413141cc406Sopenharmony_ci if (devices[i].method == device.method 414141cc406Sopenharmony_ci && !strcmp (devices[i].devname, device.devname) 415141cc406Sopenharmony_ci && devices[i].vendor == device.vendor 416141cc406Sopenharmony_ci && devices[i].product == device.product) 417141cc406Sopenharmony_ci { 418141cc406Sopenharmony_ci /* 419141cc406Sopenharmony_ci * Need to update the LibUSB device pointer, since it might 420141cc406Sopenharmony_ci * have changed after the latest USB scan. 421141cc406Sopenharmony_ci */ 422141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 423141cc406Sopenharmony_ci devices[i].libusb_device = device.libusb_device; 424141cc406Sopenharmony_ci#endif 425141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB 426141cc406Sopenharmony_ci devices[i].lu_device = device.lu_device; 427141cc406Sopenharmony_ci#endif 428141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 429141cc406Sopenharmony_ci devices[i].usb_manager_device = device.usb_manager_device; 430141cc406Sopenharmony_ci#endif 431141cc406Sopenharmony_ci 432141cc406Sopenharmony_ci devices[i].missing=0; 433141cc406Sopenharmony_ci DBG (3, "store_device: not storing device %s\n", device.devname); 434141cc406Sopenharmony_ci 435141cc406Sopenharmony_ci /* since devname has been created by strdup() 436141cc406Sopenharmony_ci * we have to free it to avoid leaking memory */ 437141cc406Sopenharmony_ci free(device.devname); 438141cc406Sopenharmony_ci return; 439141cc406Sopenharmony_ci } 440141cc406Sopenharmony_ci if (devices[i].missing >= 2) 441141cc406Sopenharmony_ci pos = i; 442141cc406Sopenharmony_ci } 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_ci /* reuse slot of a device now missing */ 445141cc406Sopenharmony_ci if(pos > -1){ 446141cc406Sopenharmony_ci DBG (3, "store_device: overwrite dn %d with %s\n", pos, device.devname); 447141cc406Sopenharmony_ci /* we reuse the slot used by a now missing device 448141cc406Sopenharmony_ci * so we free the allocated memory for the missing one */ 449141cc406Sopenharmony_ci if (devices[pos].devname) { 450141cc406Sopenharmony_ci free(devices[pos].devname); 451141cc406Sopenharmony_ci devices[pos].devname = NULL; 452141cc406Sopenharmony_ci } 453141cc406Sopenharmony_ci } 454141cc406Sopenharmony_ci else{ 455141cc406Sopenharmony_ci if(device_number >= MAX_DEVICES){ 456141cc406Sopenharmony_ci DBG (3, "store_device: no room for %s\n", device.devname); 457141cc406Sopenharmony_ci return; 458141cc406Sopenharmony_ci } 459141cc406Sopenharmony_ci pos = device_number; 460141cc406Sopenharmony_ci device_number++; 461141cc406Sopenharmony_ci DBG (3, "store_device: add dn %d with %s\n", pos, device.devname); 462141cc406Sopenharmony_ci } 463141cc406Sopenharmony_ci memcpy (&(devices[pos]), &device, sizeof (device)); 464141cc406Sopenharmony_ci devices[pos].open = SANE_FALSE; 465141cc406Sopenharmony_ci} 466141cc406Sopenharmony_ci 467141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB 468141cc406Sopenharmony_cistatic char * 469141cc406Sopenharmony_cisanei_libusb_strerror (int errcode) 470141cc406Sopenharmony_ci{ 471141cc406Sopenharmony_ci /* Error codes & descriptions from the libusb-1.0 documentation */ 472141cc406Sopenharmony_ci 473141cc406Sopenharmony_ci switch (errcode) 474141cc406Sopenharmony_ci { 475141cc406Sopenharmony_ci case LIBUSB_SUCCESS: 476141cc406Sopenharmony_ci return "Success (no error)"; 477141cc406Sopenharmony_ci 478141cc406Sopenharmony_ci case LIBUSB_ERROR_IO: 479141cc406Sopenharmony_ci return "Input/output error"; 480141cc406Sopenharmony_ci 481141cc406Sopenharmony_ci case LIBUSB_ERROR_INVALID_PARAM: 482141cc406Sopenharmony_ci return "Invalid parameter"; 483141cc406Sopenharmony_ci 484141cc406Sopenharmony_ci case LIBUSB_ERROR_ACCESS: 485141cc406Sopenharmony_ci return "Access denied (insufficient permissions)"; 486141cc406Sopenharmony_ci 487141cc406Sopenharmony_ci case LIBUSB_ERROR_NO_DEVICE: 488141cc406Sopenharmony_ci return "No such device (it may have been disconnected)"; 489141cc406Sopenharmony_ci 490141cc406Sopenharmony_ci case LIBUSB_ERROR_NOT_FOUND: 491141cc406Sopenharmony_ci return "Entity not found"; 492141cc406Sopenharmony_ci 493141cc406Sopenharmony_ci case LIBUSB_ERROR_BUSY: 494141cc406Sopenharmony_ci return "Resource busy"; 495141cc406Sopenharmony_ci 496141cc406Sopenharmony_ci case LIBUSB_ERROR_TIMEOUT: 497141cc406Sopenharmony_ci return "Operation timed out"; 498141cc406Sopenharmony_ci 499141cc406Sopenharmony_ci case LIBUSB_ERROR_OVERFLOW: 500141cc406Sopenharmony_ci return "Overflow"; 501141cc406Sopenharmony_ci 502141cc406Sopenharmony_ci case LIBUSB_ERROR_PIPE: 503141cc406Sopenharmony_ci return "Pipe error"; 504141cc406Sopenharmony_ci 505141cc406Sopenharmony_ci case LIBUSB_ERROR_INTERRUPTED: 506141cc406Sopenharmony_ci return "System call interrupted (perhaps due to signal)"; 507141cc406Sopenharmony_ci 508141cc406Sopenharmony_ci case LIBUSB_ERROR_NO_MEM: 509141cc406Sopenharmony_ci return "Insufficient memory"; 510141cc406Sopenharmony_ci 511141cc406Sopenharmony_ci case LIBUSB_ERROR_NOT_SUPPORTED: 512141cc406Sopenharmony_ci return "Operation not supported or unimplemented on this platform"; 513141cc406Sopenharmony_ci 514141cc406Sopenharmony_ci case LIBUSB_ERROR_OTHER: 515141cc406Sopenharmony_ci return "Other error"; 516141cc406Sopenharmony_ci 517141cc406Sopenharmony_ci default: 518141cc406Sopenharmony_ci return "Unknown libusb-1.0 error code"; 519141cc406Sopenharmony_ci } 520141cc406Sopenharmony_ci} 521141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB */ 522141cc406Sopenharmony_ci 523141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 524141cc406Sopenharmony_cistatic char * 525141cc406Sopenharmony_cisanei_usb_manager_strerror (int errcode) 526141cc406Sopenharmony_ci{ 527141cc406Sopenharmony_ci /* Error codes & descriptions from the usb_manager documentation */ 528141cc406Sopenharmony_ci 529141cc406Sopenharmony_ci switch (errcode) 530141cc406Sopenharmony_ci { 531141cc406Sopenharmony_ci case USB_MANAGER_SUCCESS: 532141cc406Sopenharmony_ci return "Success (no error)"; 533141cc406Sopenharmony_ci 534141cc406Sopenharmony_ci case USB_MANAGER_ERROR_IO: 535141cc406Sopenharmony_ci return "Input/output error"; 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ci case USB_MANAGER_ERROR_INVALID_PARAM: 538141cc406Sopenharmony_ci return "Invalid parameter"; 539141cc406Sopenharmony_ci 540141cc406Sopenharmony_ci case USB_MANAGER_ERROR_ACCESS: 541141cc406Sopenharmony_ci return "Access denied (insufficient permissions)"; 542141cc406Sopenharmony_ci 543141cc406Sopenharmony_ci case USB_MANAGER_ERROR_NO_DEVICE: 544141cc406Sopenharmony_ci return "No such device (it may have been disconnected)"; 545141cc406Sopenharmony_ci 546141cc406Sopenharmony_ci case USB_MANAGER_ERROR_NOT_FOUND: 547141cc406Sopenharmony_ci return "Entity not found"; 548141cc406Sopenharmony_ci 549141cc406Sopenharmony_ci case USB_MANAGER_ERROR_BUSY: 550141cc406Sopenharmony_ci return "Resource busy"; 551141cc406Sopenharmony_ci 552141cc406Sopenharmony_ci case USB_MANAGER_ERROR_TIMEOUT: 553141cc406Sopenharmony_ci return "Operation timed out"; 554141cc406Sopenharmony_ci 555141cc406Sopenharmony_ci case USB_MANAGER_ERROR_OVERFLOW: 556141cc406Sopenharmony_ci return "Overflow"; 557141cc406Sopenharmony_ci 558141cc406Sopenharmony_ci case USB_MANAGER_ERROR_PIPE: 559141cc406Sopenharmony_ci return "Pipe error"; 560141cc406Sopenharmony_ci 561141cc406Sopenharmony_ci case USB_MANAGER_ERROR_INTERRUPTED: 562141cc406Sopenharmony_ci return "System call interrupted (perhaps due to signal)"; 563141cc406Sopenharmony_ci 564141cc406Sopenharmony_ci case USB_MANAGER_ERROR_NO_MEM: 565141cc406Sopenharmony_ci return "Insufficient memory"; 566141cc406Sopenharmony_ci 567141cc406Sopenharmony_ci case USB_MANAGER_ERROR_NOT_SUPPORTED: 568141cc406Sopenharmony_ci return "Operation not supported or unimplemented on this platform"; 569141cc406Sopenharmony_ci 570141cc406Sopenharmony_ci case USB_MANAGER_ERROR_OTHER: 571141cc406Sopenharmony_ci return "Other error"; 572141cc406Sopenharmony_ci 573141cc406Sopenharmony_ci default: 574141cc406Sopenharmony_ci return "Unknown usb_manager error code"; 575141cc406Sopenharmony_ci } 576141cc406Sopenharmony_ci} 577141cc406Sopenharmony_ci#endif /* HAVE_USB_MANAGER */ 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 580141cc406Sopenharmony_ciSANE_Status sanei_usb_testing_enable_replay(SANE_String_Const path, 581141cc406Sopenharmony_ci int development_mode) 582141cc406Sopenharmony_ci{ 583141cc406Sopenharmony_ci testing_mode = sanei_usb_testing_mode_replay; 584141cc406Sopenharmony_ci testing_development_mode = development_mode; 585141cc406Sopenharmony_ci 586141cc406Sopenharmony_ci // TODO: we'll leak if no one ever inits sane_usb properly 587141cc406Sopenharmony_ci testing_xml_path = strdup(path); 588141cc406Sopenharmony_ci testing_xml_doc = xmlReadFile(testing_xml_path, NULL, 0); 589141cc406Sopenharmony_ci if (!testing_xml_doc) 590141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 591141cc406Sopenharmony_ci 592141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 593141cc406Sopenharmony_ci} 594141cc406Sopenharmony_ci 595141cc406Sopenharmony_ci#define FAIL_TEST(func, ...) \ 596141cc406Sopenharmony_ci do { \ 597141cc406Sopenharmony_ci DBG(1, "%s: FAIL: ", func); \ 598141cc406Sopenharmony_ci DBG(1, __VA_ARGS__); \ 599141cc406Sopenharmony_ci fail_test(); \ 600141cc406Sopenharmony_ci } while (0) 601141cc406Sopenharmony_ci 602141cc406Sopenharmony_ci#define FAIL_TEST_TX(func, node, ...) \ 603141cc406Sopenharmony_ci do { \ 604141cc406Sopenharmony_ci sanei_xml_print_seq_if_any(node, func); \ 605141cc406Sopenharmony_ci DBG(1, "%s: FAIL: ", func); \ 606141cc406Sopenharmony_ci DBG(1, __VA_ARGS__); \ 607141cc406Sopenharmony_ci fail_test(); \ 608141cc406Sopenharmony_ci } while (0) 609141cc406Sopenharmony_ci 610141cc406Sopenharmony_civoid fail_test() 611141cc406Sopenharmony_ci{ 612141cc406Sopenharmony_ci} 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ciSANE_Status sanei_usb_testing_enable_record(SANE_String_Const path, SANE_String_Const be_name) 615141cc406Sopenharmony_ci{ 616141cc406Sopenharmony_ci testing_mode = sanei_usb_testing_mode_record; 617141cc406Sopenharmony_ci testing_record_backend = strdup(be_name); 618141cc406Sopenharmony_ci testing_xml_path = strdup(path); 619141cc406Sopenharmony_ci 620141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 621141cc406Sopenharmony_ci} 622141cc406Sopenharmony_ci 623141cc406Sopenharmony_cistatic xmlNode* sanei_xml_find_first_child_with_name(xmlNode* parent, 624141cc406Sopenharmony_ci const char* name) 625141cc406Sopenharmony_ci{ 626141cc406Sopenharmony_ci xmlNode* curr_child = xmlFirstElementChild(parent); 627141cc406Sopenharmony_ci while (curr_child != NULL) 628141cc406Sopenharmony_ci { 629141cc406Sopenharmony_ci if (xmlStrcmp(curr_child->name, (const xmlChar*)name) == 0) 630141cc406Sopenharmony_ci return curr_child; 631141cc406Sopenharmony_ci curr_child = xmlNextElementSibling(curr_child); 632141cc406Sopenharmony_ci } 633141cc406Sopenharmony_ci return NULL; 634141cc406Sopenharmony_ci} 635141cc406Sopenharmony_ci 636141cc406Sopenharmony_cistatic xmlNode* sanei_xml_find_next_child_with_name(xmlNode* child, 637141cc406Sopenharmony_ci const char* name) 638141cc406Sopenharmony_ci{ 639141cc406Sopenharmony_ci xmlNode* curr_child = xmlNextElementSibling(child); 640141cc406Sopenharmony_ci while (curr_child != NULL) 641141cc406Sopenharmony_ci { 642141cc406Sopenharmony_ci if (xmlStrcmp(curr_child->name, (const xmlChar*)name) == 0) 643141cc406Sopenharmony_ci return curr_child; 644141cc406Sopenharmony_ci curr_child = xmlNextElementSibling(curr_child); 645141cc406Sopenharmony_ci } 646141cc406Sopenharmony_ci return NULL; 647141cc406Sopenharmony_ci} 648141cc406Sopenharmony_ci 649141cc406Sopenharmony_ci// a wrapper to get rid of -Wpointer-sign warnings in a single place 650141cc406Sopenharmony_cistatic char* sanei_xml_get_prop(xmlNode* node, const char* name) 651141cc406Sopenharmony_ci{ 652141cc406Sopenharmony_ci return (char*)xmlGetProp(node, (const xmlChar*)name); 653141cc406Sopenharmony_ci} 654141cc406Sopenharmony_ci 655141cc406Sopenharmony_ci// returns -1 if attribute is not found 656141cc406Sopenharmony_cistatic int sanei_xml_get_prop_uint(xmlNode* node, const char* name) 657141cc406Sopenharmony_ci{ 658141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, name); 659141cc406Sopenharmony_ci if (attr == NULL) 660141cc406Sopenharmony_ci { 661141cc406Sopenharmony_ci return -1; 662141cc406Sopenharmony_ci } 663141cc406Sopenharmony_ci 664141cc406Sopenharmony_ci unsigned attr_uint = strtoul(attr, NULL, 0); 665141cc406Sopenharmony_ci xmlFree(attr); 666141cc406Sopenharmony_ci return attr_uint; 667141cc406Sopenharmony_ci} 668141cc406Sopenharmony_ci 669141cc406Sopenharmony_cistatic void sanei_xml_print_seq_if_any(xmlNode* node, const char* parent_fun) 670141cc406Sopenharmony_ci{ 671141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, "seq"); 672141cc406Sopenharmony_ci if (attr == NULL) 673141cc406Sopenharmony_ci return; 674141cc406Sopenharmony_ci 675141cc406Sopenharmony_ci DBG(1, "%s: FAIL: in transaction with seq %s:\n", parent_fun, attr); 676141cc406Sopenharmony_ci xmlFree(attr); 677141cc406Sopenharmony_ci} 678141cc406Sopenharmony_ci 679141cc406Sopenharmony_ci// Checks whether transaction should be ignored. We ignore set_configuration 680141cc406Sopenharmony_ci// transactions, because set_configuration is called in sanei_usb_open outside test path. 681141cc406Sopenharmony_cistatic int sanei_xml_is_transaction_ignored(xmlNode* node) 682141cc406Sopenharmony_ci{ 683141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"control_tx") != 0) 684141cc406Sopenharmony_ci return 0; 685141cc406Sopenharmony_ci 686141cc406Sopenharmony_ci if (sanei_xml_get_prop_uint(node, "endpoint_number") != 0) 687141cc406Sopenharmony_ci return 0; 688141cc406Sopenharmony_ci 689141cc406Sopenharmony_ci int is_direction_in = 0; 690141cc406Sopenharmony_ci int is_direction_out = 0; 691141cc406Sopenharmony_ci 692141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, "direction"); 693141cc406Sopenharmony_ci if (attr == NULL) 694141cc406Sopenharmony_ci return 0; 695141cc406Sopenharmony_ci 696141cc406Sopenharmony_ci if (strcmp(attr, "IN") == 0) 697141cc406Sopenharmony_ci is_direction_in = 1; 698141cc406Sopenharmony_ci if (strcmp(attr, "OUT") == 0) 699141cc406Sopenharmony_ci is_direction_out = 1; 700141cc406Sopenharmony_ci xmlFree(attr); 701141cc406Sopenharmony_ci 702141cc406Sopenharmony_ci unsigned bRequest = sanei_xml_get_prop_uint(node, "bRequest"); 703141cc406Sopenharmony_ci if (bRequest == USB_REQ_GET_DESCRIPTOR && is_direction_in) 704141cc406Sopenharmony_ci { 705141cc406Sopenharmony_ci if (sanei_xml_get_prop_uint(node, "bmRequestType") != 0x80) 706141cc406Sopenharmony_ci return 0; 707141cc406Sopenharmony_ci return 1; 708141cc406Sopenharmony_ci } 709141cc406Sopenharmony_ci if (bRequest == USB_REQ_SET_CONFIGURATION && is_direction_out) 710141cc406Sopenharmony_ci return 1; 711141cc406Sopenharmony_ci 712141cc406Sopenharmony_ci return 0; 713141cc406Sopenharmony_ci} 714141cc406Sopenharmony_ci 715141cc406Sopenharmony_cistatic xmlNode* sanei_xml_skip_non_tx_nodes(xmlNode* node) 716141cc406Sopenharmony_ci{ 717141cc406Sopenharmony_ci const char* known_node_names[] = { 718141cc406Sopenharmony_ci "control_tx", "bulk_tx", "interrupt_tx", 719141cc406Sopenharmony_ci "get_descriptor", "debug", "known_commands_end" 720141cc406Sopenharmony_ci }; 721141cc406Sopenharmony_ci 722141cc406Sopenharmony_ci while (node != NULL) 723141cc406Sopenharmony_ci { 724141cc406Sopenharmony_ci int found = 0; 725141cc406Sopenharmony_ci for (unsigned i = 0; i < sizeof(known_node_names) / 726141cc406Sopenharmony_ci sizeof(known_node_names[0]); ++i) 727141cc406Sopenharmony_ci { 728141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*) known_node_names[i]) == 0) 729141cc406Sopenharmony_ci { 730141cc406Sopenharmony_ci found = 1; 731141cc406Sopenharmony_ci break; 732141cc406Sopenharmony_ci } 733141cc406Sopenharmony_ci } 734141cc406Sopenharmony_ci 735141cc406Sopenharmony_ci if (found && sanei_xml_is_transaction_ignored(node) == 0) 736141cc406Sopenharmony_ci { 737141cc406Sopenharmony_ci break; 738141cc406Sopenharmony_ci } 739141cc406Sopenharmony_ci 740141cc406Sopenharmony_ci node = xmlNextElementSibling(node); 741141cc406Sopenharmony_ci } 742141cc406Sopenharmony_ci return node; 743141cc406Sopenharmony_ci} 744141cc406Sopenharmony_ci 745141cc406Sopenharmony_cistatic int sanei_xml_is_known_commands_end(xmlNode* node) 746141cc406Sopenharmony_ci{ 747141cc406Sopenharmony_ci if (!testing_development_mode || node == NULL) 748141cc406Sopenharmony_ci return 0; 749141cc406Sopenharmony_ci return xmlStrcmp(node->name, (const xmlChar*)"known_commands_end") == 0; 750141cc406Sopenharmony_ci} 751141cc406Sopenharmony_ci 752141cc406Sopenharmony_cistatic xmlNode* sanei_xml_peek_next_tx_node() 753141cc406Sopenharmony_ci{ 754141cc406Sopenharmony_ci return testing_xml_next_tx_node; 755141cc406Sopenharmony_ci} 756141cc406Sopenharmony_ci 757141cc406Sopenharmony_cistatic xmlNode* sanei_xml_get_next_tx_node() 758141cc406Sopenharmony_ci{ 759141cc406Sopenharmony_ci xmlNode* next = testing_xml_next_tx_node; 760141cc406Sopenharmony_ci 761141cc406Sopenharmony_ci if (sanei_xml_is_known_commands_end(next)) 762141cc406Sopenharmony_ci { 763141cc406Sopenharmony_ci testing_append_commands_node = xmlPreviousElementSibling(next); 764141cc406Sopenharmony_ci return next; 765141cc406Sopenharmony_ci } 766141cc406Sopenharmony_ci 767141cc406Sopenharmony_ci testing_xml_next_tx_node = 768141cc406Sopenharmony_ci xmlNextElementSibling(testing_xml_next_tx_node); 769141cc406Sopenharmony_ci 770141cc406Sopenharmony_ci testing_xml_next_tx_node = 771141cc406Sopenharmony_ci sanei_xml_skip_non_tx_nodes(testing_xml_next_tx_node); 772141cc406Sopenharmony_ci 773141cc406Sopenharmony_ci return next; 774141cc406Sopenharmony_ci} 775141cc406Sopenharmony_ci 776141cc406Sopenharmony_ci#define CHAR_TYPE_INVALID -1 777141cc406Sopenharmony_ci#define CHAR_TYPE_SPACE -2 778141cc406Sopenharmony_ci 779141cc406Sopenharmony_cistatic int8_t sanei_xml_char_types[256] = 780141cc406Sopenharmony_ci{ 781141cc406Sopenharmony_ci /* 0x00-0x0f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, 782141cc406Sopenharmony_ci /* 0x10-0x1f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 783141cc406Sopenharmony_ci /* 0x20-0x2f */ -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 784141cc406Sopenharmony_ci /* 0x30-0x3f */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 785141cc406Sopenharmony_ci /* 0x40-0x4f */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 786141cc406Sopenharmony_ci /* 0x50-0x5f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 787141cc406Sopenharmony_ci /* 0x60-0x6f */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 788141cc406Sopenharmony_ci /* 0x70-0x7f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 789141cc406Sopenharmony_ci /* 0x80-0x8f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 790141cc406Sopenharmony_ci /* 0x90-0x9f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 791141cc406Sopenharmony_ci /* 0xa0-0xaf */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 792141cc406Sopenharmony_ci /* 0xb0-0xbf */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 793141cc406Sopenharmony_ci /* 0xc0-0xcf */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 794141cc406Sopenharmony_ci /* 0xd0-0xdf */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 795141cc406Sopenharmony_ci /* 0xe0-0xef */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 796141cc406Sopenharmony_ci /* 0xf0-0xff */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 797141cc406Sopenharmony_ci}; 798141cc406Sopenharmony_ci 799141cc406Sopenharmony_cistatic char* sanei_xml_get_hex_data_slow_path(xmlNode* node, xmlChar* content, xmlChar* cur_content, 800141cc406Sopenharmony_ci char* ret_data, char* cur_ret_data, size_t* size) 801141cc406Sopenharmony_ci{ 802141cc406Sopenharmony_ci int num_nibbles = 0; 803141cc406Sopenharmony_ci unsigned cur_nibble = 0; 804141cc406Sopenharmony_ci 805141cc406Sopenharmony_ci while (*cur_content != 0) 806141cc406Sopenharmony_ci { 807141cc406Sopenharmony_ci while (sanei_xml_char_types[(uint8_t)*cur_content] == CHAR_TYPE_SPACE) 808141cc406Sopenharmony_ci cur_content++; 809141cc406Sopenharmony_ci 810141cc406Sopenharmony_ci if (*cur_content == 0) 811141cc406Sopenharmony_ci break; 812141cc406Sopenharmony_ci 813141cc406Sopenharmony_ci // don't use stroul because it will parse in big-endian and data is in 814141cc406Sopenharmony_ci // little endian 815141cc406Sopenharmony_ci uint8_t c = *cur_content; 816141cc406Sopenharmony_ci int8_t ci = sanei_xml_char_types[c]; 817141cc406Sopenharmony_ci if (ci == CHAR_TYPE_INVALID) 818141cc406Sopenharmony_ci { 819141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected character %c\n", c); 820141cc406Sopenharmony_ci cur_content++; 821141cc406Sopenharmony_ci continue; 822141cc406Sopenharmony_ci } 823141cc406Sopenharmony_ci 824141cc406Sopenharmony_ci cur_nibble = (cur_nibble << 4) | ci; 825141cc406Sopenharmony_ci num_nibbles++; 826141cc406Sopenharmony_ci 827141cc406Sopenharmony_ci if (num_nibbles == 2) 828141cc406Sopenharmony_ci { 829141cc406Sopenharmony_ci *cur_ret_data++ = cur_nibble; 830141cc406Sopenharmony_ci cur_nibble = 0; 831141cc406Sopenharmony_ci num_nibbles = 0; 832141cc406Sopenharmony_ci } 833141cc406Sopenharmony_ci cur_content++; 834141cc406Sopenharmony_ci } 835141cc406Sopenharmony_ci *size = cur_ret_data - ret_data; 836141cc406Sopenharmony_ci xmlFree(content); 837141cc406Sopenharmony_ci return ret_data; 838141cc406Sopenharmony_ci} 839141cc406Sopenharmony_ci 840141cc406Sopenharmony_ci// Parses hex data in XML text node in the format of '00 11 ab 3f', etc. to 841141cc406Sopenharmony_ci// binary string. The size is returned as *size. The caller is responsible for 842141cc406Sopenharmony_ci// freeing the returned value 843141cc406Sopenharmony_cistatic char* sanei_xml_get_hex_data(xmlNode* node, size_t* size) 844141cc406Sopenharmony_ci{ 845141cc406Sopenharmony_ci xmlChar* content = xmlNodeGetContent(node); 846141cc406Sopenharmony_ci 847141cc406Sopenharmony_ci // let's overallocate to simplify the implementation. We expect the string 848141cc406Sopenharmony_ci // to be deallocated soon anyway 849141cc406Sopenharmony_ci char* ret_data = malloc(strlen((const char*)content) / 2 + 2); 850141cc406Sopenharmony_ci char* cur_ret_data = ret_data; 851141cc406Sopenharmony_ci 852141cc406Sopenharmony_ci xmlChar* cur_content = content; 853141cc406Sopenharmony_ci 854141cc406Sopenharmony_ci // the text to binary conversion takes most of the time spent in tests, so we 855141cc406Sopenharmony_ci // take extra care to optimize it. We split the implementation into fast and 856141cc406Sopenharmony_ci // slow path. The fast path utilizes the knowledge that there will be no spaces 857141cc406Sopenharmony_ci // within bytes. When this assumption does not hold, we switch to the slow path. 858141cc406Sopenharmony_ci while (*cur_content != 0) 859141cc406Sopenharmony_ci { 860141cc406Sopenharmony_ci // most of the time there will be 1 or 2 spaces between bytes. Give the CPU 861141cc406Sopenharmony_ci // chance to predict this by partially unrolling the while loop. 862141cc406Sopenharmony_ci if (sanei_xml_char_types[(uint8_t)*cur_content] == CHAR_TYPE_SPACE) 863141cc406Sopenharmony_ci { 864141cc406Sopenharmony_ci cur_content++; 865141cc406Sopenharmony_ci if (sanei_xml_char_types[(uint8_t)*cur_content] == CHAR_TYPE_SPACE) 866141cc406Sopenharmony_ci { 867141cc406Sopenharmony_ci cur_content++; 868141cc406Sopenharmony_ci while (sanei_xml_char_types[(uint8_t)*cur_content] == CHAR_TYPE_SPACE) 869141cc406Sopenharmony_ci cur_content++; 870141cc406Sopenharmony_ci } 871141cc406Sopenharmony_ci } 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci if (*cur_content == 0) 874141cc406Sopenharmony_ci break; 875141cc406Sopenharmony_ci 876141cc406Sopenharmony_ci // don't use stroul because it will parse in big-endian and data is in 877141cc406Sopenharmony_ci // little endian 878141cc406Sopenharmony_ci int8_t ci1 = sanei_xml_char_types[(uint8_t)*cur_content]; 879141cc406Sopenharmony_ci int8_t ci2 = sanei_xml_char_types[(uint8_t)*(cur_content + 1)]; 880141cc406Sopenharmony_ci 881141cc406Sopenharmony_ci if (ci1 < 0 || ci2 < 0) 882141cc406Sopenharmony_ci return sanei_xml_get_hex_data_slow_path(node, content, cur_content, ret_data, cur_ret_data, 883141cc406Sopenharmony_ci size); 884141cc406Sopenharmony_ci 885141cc406Sopenharmony_ci *cur_ret_data++ = ci1 << 4 | ci2; 886141cc406Sopenharmony_ci cur_content += 2; 887141cc406Sopenharmony_ci } 888141cc406Sopenharmony_ci *size = cur_ret_data - ret_data; 889141cc406Sopenharmony_ci xmlFree(content); 890141cc406Sopenharmony_ci return ret_data; 891141cc406Sopenharmony_ci} 892141cc406Sopenharmony_ci 893141cc406Sopenharmony_ci// caller is responsible for freeing the returned pointer 894141cc406Sopenharmony_cistatic char* sanei_binary_to_hex_data(const char* data, size_t size, 895141cc406Sopenharmony_ci size_t* out_size) 896141cc406Sopenharmony_ci{ 897141cc406Sopenharmony_ci char* hex_data = malloc(size * 4); 898141cc406Sopenharmony_ci size_t hex_size = 0; 899141cc406Sopenharmony_ci 900141cc406Sopenharmony_ci for (size_t i = 0; i < size; ++i) 901141cc406Sopenharmony_ci { 902141cc406Sopenharmony_ci hex_size += snprintf(hex_data + hex_size, 3, "%02hhx", data[i]); 903141cc406Sopenharmony_ci if (i + 1 != size) 904141cc406Sopenharmony_ci { 905141cc406Sopenharmony_ci if ((i + 1) % 32 == 0) 906141cc406Sopenharmony_ci hex_data[hex_size++] = '\n'; 907141cc406Sopenharmony_ci else 908141cc406Sopenharmony_ci hex_data[hex_size++] = ' '; 909141cc406Sopenharmony_ci } 910141cc406Sopenharmony_ci } 911141cc406Sopenharmony_ci hex_data[hex_size] = 0; 912141cc406Sopenharmony_ci if (out_size) 913141cc406Sopenharmony_ci *out_size = hex_size; 914141cc406Sopenharmony_ci return hex_data; 915141cc406Sopenharmony_ci} 916141cc406Sopenharmony_ci 917141cc406Sopenharmony_ci 918141cc406Sopenharmony_cistatic void sanei_xml_set_data(xmlNode* node, const char* data) 919141cc406Sopenharmony_ci{ 920141cc406Sopenharmony_ci // FIXME: remove existing children 921141cc406Sopenharmony_ci xmlAddChild(node, xmlNewText((const xmlChar*)data)); 922141cc406Sopenharmony_ci} 923141cc406Sopenharmony_ci 924141cc406Sopenharmony_ci// Writes binary data to XML node as a child text node in the hex format of 925141cc406Sopenharmony_ci// '00 11 ab 3f'. 926141cc406Sopenharmony_cistatic void sanei_xml_set_hex_data(xmlNode* node, const char* data, 927141cc406Sopenharmony_ci size_t size) 928141cc406Sopenharmony_ci{ 929141cc406Sopenharmony_ci char* hex_data = sanei_binary_to_hex_data(data, size, NULL); 930141cc406Sopenharmony_ci sanei_xml_set_data(node, hex_data); 931141cc406Sopenharmony_ci free(hex_data); 932141cc406Sopenharmony_ci} 933141cc406Sopenharmony_ci 934141cc406Sopenharmony_cistatic void sanei_xml_set_hex_attr(xmlNode* node, const char* attr_name, 935141cc406Sopenharmony_ci unsigned attr_value) 936141cc406Sopenharmony_ci{ 937141cc406Sopenharmony_ci const int buf_size = 128; 938141cc406Sopenharmony_ci char buf[buf_size]; 939141cc406Sopenharmony_ci if (attr_value > 0xffffff) 940141cc406Sopenharmony_ci snprintf(buf, buf_size, "0x%x", attr_value); 941141cc406Sopenharmony_ci else if (attr_value > 0xffff) 942141cc406Sopenharmony_ci snprintf(buf, buf_size, "0x%06x", attr_value); 943141cc406Sopenharmony_ci else if (attr_value > 0xff) 944141cc406Sopenharmony_ci snprintf(buf, buf_size, "0x%04x", attr_value); 945141cc406Sopenharmony_ci else 946141cc406Sopenharmony_ci snprintf(buf, buf_size, "0x%02x", attr_value); 947141cc406Sopenharmony_ci 948141cc406Sopenharmony_ci xmlNewProp(node, (const xmlChar*)attr_name, (const xmlChar*)buf); 949141cc406Sopenharmony_ci} 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_cistatic void sanei_xml_set_uint_attr(xmlNode* node, const char* attr_name, 952141cc406Sopenharmony_ci unsigned attr_value) 953141cc406Sopenharmony_ci{ 954141cc406Sopenharmony_ci const int buf_size = 128; 955141cc406Sopenharmony_ci char buf[buf_size]; 956141cc406Sopenharmony_ci snprintf(buf, buf_size, "%d", attr_value); 957141cc406Sopenharmony_ci xmlNewProp(node, (const xmlChar*)attr_name, (const xmlChar*)buf); 958141cc406Sopenharmony_ci} 959141cc406Sopenharmony_ci 960141cc406Sopenharmony_cistatic xmlNode* sanei_xml_append_command(xmlNode* sibling, 961141cc406Sopenharmony_ci int indent, xmlNode* e_command) 962141cc406Sopenharmony_ci{ 963141cc406Sopenharmony_ci if (indent) 964141cc406Sopenharmony_ci { 965141cc406Sopenharmony_ci xmlNode* e_indent = xmlNewText((const xmlChar*)"\n "); 966141cc406Sopenharmony_ci sibling = xmlAddNextSibling(sibling, e_indent); 967141cc406Sopenharmony_ci } 968141cc406Sopenharmony_ci return xmlAddNextSibling(sibling, e_command); 969141cc406Sopenharmony_ci} 970141cc406Sopenharmony_ci 971141cc406Sopenharmony_cistatic void sanei_xml_command_common_props(xmlNode* node, int endpoint_number, 972141cc406Sopenharmony_ci const char* direction) 973141cc406Sopenharmony_ci{ 974141cc406Sopenharmony_ci xmlNewProp(node, (const xmlChar*)"time_usec", (const xmlChar*)"0"); 975141cc406Sopenharmony_ci sanei_xml_set_uint_attr(node, "seq", ++testing_last_known_seq); 976141cc406Sopenharmony_ci sanei_xml_set_uint_attr(node, "endpoint_number", endpoint_number); 977141cc406Sopenharmony_ci xmlNewProp(node, (const xmlChar*)"direction", (const xmlChar*)direction); 978141cc406Sopenharmony_ci} 979141cc406Sopenharmony_ci 980141cc406Sopenharmony_cistatic void sanei_xml_record_seq(xmlNode* node) 981141cc406Sopenharmony_ci{ 982141cc406Sopenharmony_ci int seq = sanei_xml_get_prop_uint(node, "seq"); 983141cc406Sopenharmony_ci if (seq > 0) 984141cc406Sopenharmony_ci testing_last_known_seq = seq; 985141cc406Sopenharmony_ci} 986141cc406Sopenharmony_ci 987141cc406Sopenharmony_cistatic void sanei_xml_break() 988141cc406Sopenharmony_ci{ 989141cc406Sopenharmony_ci} 990141cc406Sopenharmony_ci 991141cc406Sopenharmony_cistatic void sanei_xml_break_if_needed(xmlNode* node) 992141cc406Sopenharmony_ci{ 993141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, "debug_break"); 994141cc406Sopenharmony_ci if (attr != NULL) 995141cc406Sopenharmony_ci { 996141cc406Sopenharmony_ci sanei_xml_break(); 997141cc406Sopenharmony_ci xmlFree(attr); 998141cc406Sopenharmony_ci } 999141cc406Sopenharmony_ci} 1000141cc406Sopenharmony_ci 1001141cc406Sopenharmony_ci// returns 1 on success 1002141cc406Sopenharmony_cistatic int sanei_usb_check_attr(xmlNode* node, const char* attr_name, 1003141cc406Sopenharmony_ci const char* expected, const char* parent_fun) 1004141cc406Sopenharmony_ci{ 1005141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, attr_name); 1006141cc406Sopenharmony_ci if (attr == NULL) 1007141cc406Sopenharmony_ci { 1008141cc406Sopenharmony_ci FAIL_TEST_TX(parent_fun, node, "no %s attribute\n", attr_name); 1009141cc406Sopenharmony_ci return 0; 1010141cc406Sopenharmony_ci } 1011141cc406Sopenharmony_ci 1012141cc406Sopenharmony_ci if (strcmp(attr, expected) != 0) 1013141cc406Sopenharmony_ci { 1014141cc406Sopenharmony_ci FAIL_TEST_TX(parent_fun, node, "unexpected %s attribute: %s, wanted %s\n", 1015141cc406Sopenharmony_ci attr_name, attr, expected); 1016141cc406Sopenharmony_ci xmlFree(attr); 1017141cc406Sopenharmony_ci return 0; 1018141cc406Sopenharmony_ci } 1019141cc406Sopenharmony_ci xmlFree(attr); 1020141cc406Sopenharmony_ci return 1; 1021141cc406Sopenharmony_ci} 1022141cc406Sopenharmony_ci 1023141cc406Sopenharmony_ci// returns 1 on success 1024141cc406Sopenharmony_cistatic int sanei_usb_attr_is(xmlNode* node, const char* attr_name, 1025141cc406Sopenharmony_ci const char* expected) 1026141cc406Sopenharmony_ci{ 1027141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, attr_name); 1028141cc406Sopenharmony_ci if (attr == NULL) 1029141cc406Sopenharmony_ci return 0; 1030141cc406Sopenharmony_ci 1031141cc406Sopenharmony_ci if (strcmp(attr, expected) != 0) 1032141cc406Sopenharmony_ci { 1033141cc406Sopenharmony_ci xmlFree(attr); 1034141cc406Sopenharmony_ci return 0; 1035141cc406Sopenharmony_ci } 1036141cc406Sopenharmony_ci xmlFree(attr); 1037141cc406Sopenharmony_ci return 1; 1038141cc406Sopenharmony_ci} 1039141cc406Sopenharmony_ci 1040141cc406Sopenharmony_ci// returns 0 on success 1041141cc406Sopenharmony_cistatic int sanei_usb_check_attr_uint(xmlNode* node, const char* attr_name, 1042141cc406Sopenharmony_ci unsigned expected, const char* parent_fun) 1043141cc406Sopenharmony_ci{ 1044141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, attr_name); 1045141cc406Sopenharmony_ci if (attr == NULL) 1046141cc406Sopenharmony_ci { 1047141cc406Sopenharmony_ci FAIL_TEST_TX(parent_fun, node, "no %s attribute\n", attr_name); 1048141cc406Sopenharmony_ci return 0; 1049141cc406Sopenharmony_ci } 1050141cc406Sopenharmony_ci 1051141cc406Sopenharmony_ci unsigned attr_int = strtoul(attr, NULL, 0); 1052141cc406Sopenharmony_ci if (attr_int != expected) 1053141cc406Sopenharmony_ci { 1054141cc406Sopenharmony_ci FAIL_TEST_TX(parent_fun, node, 1055141cc406Sopenharmony_ci "unexpected %s attribute: %s, wanted 0x%x\n", 1056141cc406Sopenharmony_ci attr_name, attr, expected); 1057141cc406Sopenharmony_ci xmlFree(attr); 1058141cc406Sopenharmony_ci return 0; 1059141cc406Sopenharmony_ci } 1060141cc406Sopenharmony_ci xmlFree(attr); 1061141cc406Sopenharmony_ci return 1; 1062141cc406Sopenharmony_ci} 1063141cc406Sopenharmony_ci 1064141cc406Sopenharmony_cistatic int sanei_usb_attr_is_uint(xmlNode* node, const char* attr_name, 1065141cc406Sopenharmony_ci unsigned expected) 1066141cc406Sopenharmony_ci{ 1067141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(node, attr_name); 1068141cc406Sopenharmony_ci if (attr == NULL) 1069141cc406Sopenharmony_ci return 0; 1070141cc406Sopenharmony_ci 1071141cc406Sopenharmony_ci unsigned attr_int = strtoul(attr, NULL, 0); 1072141cc406Sopenharmony_ci if (attr_int != expected) 1073141cc406Sopenharmony_ci { 1074141cc406Sopenharmony_ci xmlFree(attr); 1075141cc406Sopenharmony_ci return 0; 1076141cc406Sopenharmony_ci } 1077141cc406Sopenharmony_ci xmlFree(attr); 1078141cc406Sopenharmony_ci return 1; 1079141cc406Sopenharmony_ci} 1080141cc406Sopenharmony_ci 1081141cc406Sopenharmony_ci// returns 1 on data equality 1082141cc406Sopenharmony_cistatic int sanei_usb_check_data_equal(xmlNode* node, 1083141cc406Sopenharmony_ci const char* data, 1084141cc406Sopenharmony_ci size_t data_size, 1085141cc406Sopenharmony_ci const char* expected_data, 1086141cc406Sopenharmony_ci size_t expected_size, 1087141cc406Sopenharmony_ci const char* parent_fun) 1088141cc406Sopenharmony_ci{ 1089141cc406Sopenharmony_ci if ((data_size == expected_size) && 1090141cc406Sopenharmony_ci (memcmp(data, expected_data, data_size) == 0)) 1091141cc406Sopenharmony_ci return 1; 1092141cc406Sopenharmony_ci 1093141cc406Sopenharmony_ci char* data_hex = sanei_binary_to_hex_data(data, data_size, NULL); 1094141cc406Sopenharmony_ci char* expected_hex = sanei_binary_to_hex_data(expected_data, expected_size, 1095141cc406Sopenharmony_ci NULL); 1096141cc406Sopenharmony_ci 1097141cc406Sopenharmony_ci if (data_size == expected_size) 1098141cc406Sopenharmony_ci FAIL_TEST_TX(parent_fun, node, "data differs (size %lu):\n", data_size); 1099141cc406Sopenharmony_ci else 1100141cc406Sopenharmony_ci FAIL_TEST_TX(parent_fun, node, 1101141cc406Sopenharmony_ci "data differs (got size %lu, expected %lu):\n", 1102141cc406Sopenharmony_ci data_size, expected_size); 1103141cc406Sopenharmony_ci 1104141cc406Sopenharmony_ci FAIL_TEST(parent_fun, "got: %s\n", data_hex); 1105141cc406Sopenharmony_ci FAIL_TEST(parent_fun, "expected: %s\n", expected_hex); 1106141cc406Sopenharmony_ci free(data_hex); 1107141cc406Sopenharmony_ci free(expected_hex); 1108141cc406Sopenharmony_ci return 0; 1109141cc406Sopenharmony_ci} 1110141cc406Sopenharmony_ci 1111141cc406Sopenharmony_ciSANE_String sanei_usb_testing_get_backend() 1112141cc406Sopenharmony_ci{ 1113141cc406Sopenharmony_ci if (testing_xml_doc == NULL) 1114141cc406Sopenharmony_ci return NULL; 1115141cc406Sopenharmony_ci 1116141cc406Sopenharmony_ci xmlNode* el_root = xmlDocGetRootElement(testing_xml_doc); 1117141cc406Sopenharmony_ci if (xmlStrcmp(el_root->name, (const xmlChar*)"device_capture") != 0) 1118141cc406Sopenharmony_ci { 1119141cc406Sopenharmony_ci FAIL_TEST(__func__, "the given file is not USB capture\n"); 1120141cc406Sopenharmony_ci return NULL; 1121141cc406Sopenharmony_ci } 1122141cc406Sopenharmony_ci 1123141cc406Sopenharmony_ci char* attr = sanei_xml_get_prop(el_root, "backend"); 1124141cc406Sopenharmony_ci if (attr == NULL) 1125141cc406Sopenharmony_ci { 1126141cc406Sopenharmony_ci FAIL_TEST(__func__, "no backend attr in description node\n"); 1127141cc406Sopenharmony_ci return NULL; 1128141cc406Sopenharmony_ci } 1129141cc406Sopenharmony_ci // duplicate using strdup so that the caller can use free() 1130141cc406Sopenharmony_ci char* ret = strdup(attr); 1131141cc406Sopenharmony_ci xmlFree(attr); 1132141cc406Sopenharmony_ci return ret; 1133141cc406Sopenharmony_ci} 1134141cc406Sopenharmony_ci 1135141cc406Sopenharmony_ciSANE_Bool sanei_usb_is_replay_mode_enabled() 1136141cc406Sopenharmony_ci{ 1137141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 1138141cc406Sopenharmony_ci return SANE_TRUE; 1139141cc406Sopenharmony_ci 1140141cc406Sopenharmony_ci return SANE_FALSE; 1141141cc406Sopenharmony_ci} 1142141cc406Sopenharmony_ci 1143141cc406Sopenharmony_cistatic void sanei_usb_record_debug_msg(xmlNode* node, SANE_String_Const message) 1144141cc406Sopenharmony_ci{ 1145141cc406Sopenharmony_ci int node_was_null = node == NULL; 1146141cc406Sopenharmony_ci if (node_was_null) 1147141cc406Sopenharmony_ci node = testing_append_commands_node; 1148141cc406Sopenharmony_ci 1149141cc406Sopenharmony_ci xmlNode* e_tx = xmlNewNode(NULL, (const xmlChar*)"debug"); 1150141cc406Sopenharmony_ci sanei_xml_set_uint_attr(e_tx, "seq", ++testing_last_known_seq); 1151141cc406Sopenharmony_ci xmlNewProp(e_tx, (const xmlChar*)"message", (const xmlChar*)message); 1152141cc406Sopenharmony_ci 1153141cc406Sopenharmony_ci node = sanei_xml_append_command(node, node_was_null, e_tx); 1154141cc406Sopenharmony_ci 1155141cc406Sopenharmony_ci if (node_was_null) 1156141cc406Sopenharmony_ci testing_append_commands_node = node; 1157141cc406Sopenharmony_ci} 1158141cc406Sopenharmony_ci 1159141cc406Sopenharmony_cistatic void sanei_usb_record_replace_debug_msg(xmlNode* node, SANE_String_Const message) 1160141cc406Sopenharmony_ci{ 1161141cc406Sopenharmony_ci if (!testing_development_mode) 1162141cc406Sopenharmony_ci return; 1163141cc406Sopenharmony_ci 1164141cc406Sopenharmony_ci testing_last_known_seq--; 1165141cc406Sopenharmony_ci sanei_usb_record_debug_msg(node, message); 1166141cc406Sopenharmony_ci xmlUnlinkNode(node); 1167141cc406Sopenharmony_ci xmlFreeNode(node); 1168141cc406Sopenharmony_ci} 1169141cc406Sopenharmony_ci 1170141cc406Sopenharmony_cistatic void sanei_usb_replay_debug_msg(SANE_String_Const message) 1171141cc406Sopenharmony_ci{ 1172141cc406Sopenharmony_ci if (testing_known_commands_input_failed) 1173141cc406Sopenharmony_ci return; 1174141cc406Sopenharmony_ci 1175141cc406Sopenharmony_ci xmlNode* node = sanei_xml_get_next_tx_node(); 1176141cc406Sopenharmony_ci if (node == NULL) 1177141cc406Sopenharmony_ci { 1178141cc406Sopenharmony_ci FAIL_TEST(__func__, "no more transactions\n"); 1179141cc406Sopenharmony_ci return; 1180141cc406Sopenharmony_ci } 1181141cc406Sopenharmony_ci 1182141cc406Sopenharmony_ci if (sanei_xml_is_known_commands_end(node)) 1183141cc406Sopenharmony_ci { 1184141cc406Sopenharmony_ci sanei_usb_record_debug_msg(NULL, message); 1185141cc406Sopenharmony_ci return; 1186141cc406Sopenharmony_ci } 1187141cc406Sopenharmony_ci 1188141cc406Sopenharmony_ci sanei_xml_record_seq(node); 1189141cc406Sopenharmony_ci sanei_xml_break_if_needed(node); 1190141cc406Sopenharmony_ci 1191141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"debug") != 0) 1192141cc406Sopenharmony_ci { 1193141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", 1194141cc406Sopenharmony_ci (const char*) node->name); 1195141cc406Sopenharmony_ci sanei_usb_record_replace_debug_msg(node, message); 1196141cc406Sopenharmony_ci } 1197141cc406Sopenharmony_ci 1198141cc406Sopenharmony_ci if (!sanei_usb_check_attr(node, "message", message, __func__)) 1199141cc406Sopenharmony_ci { 1200141cc406Sopenharmony_ci sanei_usb_record_replace_debug_msg(node, message); 1201141cc406Sopenharmony_ci } 1202141cc406Sopenharmony_ci} 1203141cc406Sopenharmony_ci 1204141cc406Sopenharmony_ciextern void sanei_usb_testing_record_clear() 1205141cc406Sopenharmony_ci{ 1206141cc406Sopenharmony_ci if (testing_mode != sanei_usb_testing_mode_record) 1207141cc406Sopenharmony_ci return; 1208141cc406Sopenharmony_ci 1209141cc406Sopenharmony_ci // we only need to indicate that we never opened a device and sanei_usb_record_open() will 1210141cc406Sopenharmony_ci // reinitialize everything for us. 1211141cc406Sopenharmony_ci testing_already_opened = 0; 1212141cc406Sopenharmony_ci testing_known_commands_input_failed = 0; 1213141cc406Sopenharmony_ci testing_last_known_seq = 0; 1214141cc406Sopenharmony_ci testing_append_commands_node = NULL; 1215141cc406Sopenharmony_ci} 1216141cc406Sopenharmony_ci 1217141cc406Sopenharmony_ciextern void sanei_usb_testing_record_message(SANE_String_Const message) 1218141cc406Sopenharmony_ci{ 1219141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 1220141cc406Sopenharmony_ci { 1221141cc406Sopenharmony_ci sanei_usb_record_debug_msg(NULL, message); 1222141cc406Sopenharmony_ci } 1223141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 1224141cc406Sopenharmony_ci { 1225141cc406Sopenharmony_ci sanei_usb_replay_debug_msg(message); 1226141cc406Sopenharmony_ci } 1227141cc406Sopenharmony_ci} 1228141cc406Sopenharmony_ci 1229141cc406Sopenharmony_cistatic void sanei_usb_add_endpoint(device_list_type* device, 1230141cc406Sopenharmony_ci SANE_Int transfer_type, 1231141cc406Sopenharmony_ci SANE_Int ep_address, 1232141cc406Sopenharmony_ci SANE_Int ep_direction); 1233141cc406Sopenharmony_ci 1234141cc406Sopenharmony_cistatic SANE_Status sanei_usb_testing_init() 1235141cc406Sopenharmony_ci{ 1236141cc406Sopenharmony_ci DBG_INIT(); 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 1239141cc406Sopenharmony_ci { 1240141cc406Sopenharmony_ci testing_xml_doc = xmlNewDoc((const xmlChar*)"1.0"); 1241141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1242141cc406Sopenharmony_ci } 1243141cc406Sopenharmony_ci 1244141cc406Sopenharmony_ci if (device_number != 0) 1245141cc406Sopenharmony_ci return SANE_STATUS_INVAL; // already opened 1246141cc406Sopenharmony_ci 1247141cc406Sopenharmony_ci xmlNode* el_root = xmlDocGetRootElement(testing_xml_doc); 1248141cc406Sopenharmony_ci if (xmlStrcmp(el_root->name, (const xmlChar*)"device_capture") != 0) 1249141cc406Sopenharmony_ci { 1250141cc406Sopenharmony_ci DBG(1, "%s: the given file is not USB capture\n", __func__); 1251141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1252141cc406Sopenharmony_ci } 1253141cc406Sopenharmony_ci 1254141cc406Sopenharmony_ci xmlNode* el_description = 1255141cc406Sopenharmony_ci sanei_xml_find_first_child_with_name(el_root, "description"); 1256141cc406Sopenharmony_ci if (el_description == NULL) 1257141cc406Sopenharmony_ci { 1258141cc406Sopenharmony_ci DBG(1, "%s: could not find description node\n", __func__); 1259141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1260141cc406Sopenharmony_ci } 1261141cc406Sopenharmony_ci 1262141cc406Sopenharmony_ci int device_id = sanei_xml_get_prop_uint(el_description, "id_vendor"); 1263141cc406Sopenharmony_ci if (device_id < 0) 1264141cc406Sopenharmony_ci { 1265141cc406Sopenharmony_ci DBG(1, "%s: no id_vendor attr in description node\n", __func__); 1266141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1267141cc406Sopenharmony_ci } 1268141cc406Sopenharmony_ci 1269141cc406Sopenharmony_ci int product_id = sanei_xml_get_prop_uint(el_description, "id_product"); 1270141cc406Sopenharmony_ci if (product_id < 0) 1271141cc406Sopenharmony_ci { 1272141cc406Sopenharmony_ci DBG(1, "%s: no id_product attr in description node\n", __func__); 1273141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1274141cc406Sopenharmony_ci } 1275141cc406Sopenharmony_ci 1276141cc406Sopenharmony_ci xmlNode* el_configurations = 1277141cc406Sopenharmony_ci sanei_xml_find_first_child_with_name(el_description, "configurations"); 1278141cc406Sopenharmony_ci if (el_configurations == NULL) 1279141cc406Sopenharmony_ci { 1280141cc406Sopenharmony_ci DBG(1, "%s: could not find configurations node\n", __func__); 1281141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1282141cc406Sopenharmony_ci } 1283141cc406Sopenharmony_ci 1284141cc406Sopenharmony_ci xmlNode* el_configuration = 1285141cc406Sopenharmony_ci sanei_xml_find_first_child_with_name(el_configurations, "configuration"); 1286141cc406Sopenharmony_ci if (el_configuration == NULL) 1287141cc406Sopenharmony_ci { 1288141cc406Sopenharmony_ci DBG(1, "%s: no configuration nodes\n", __func__); 1289141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1290141cc406Sopenharmony_ci } 1291141cc406Sopenharmony_ci 1292141cc406Sopenharmony_ci while (el_configuration != NULL) 1293141cc406Sopenharmony_ci { 1294141cc406Sopenharmony_ci xmlNode* el_interface = 1295141cc406Sopenharmony_ci sanei_xml_find_first_child_with_name(el_configuration, "interface"); 1296141cc406Sopenharmony_ci 1297141cc406Sopenharmony_ci while (el_interface != NULL) 1298141cc406Sopenharmony_ci { 1299141cc406Sopenharmony_ci device_list_type device; 1300141cc406Sopenharmony_ci memset(&device, 0, sizeof(device)); 1301141cc406Sopenharmony_ci device.devname = strdup(testing_xml_path); 1302141cc406Sopenharmony_ci 1303141cc406Sopenharmony_ci // other code shouldn't depend on method because testing_mode is 1304141cc406Sopenharmony_ci // sanei_usb_testing_mode_replay 1305141cc406Sopenharmony_ci device.method = sanei_usb_method_libusb; 1306141cc406Sopenharmony_ci device.vendor = device_id; 1307141cc406Sopenharmony_ci device.product = product_id; 1308141cc406Sopenharmony_ci 1309141cc406Sopenharmony_ci device.interface_nr = sanei_xml_get_prop_uint(el_interface, "number"); 1310141cc406Sopenharmony_ci if (device.interface_nr < 0) 1311141cc406Sopenharmony_ci { 1312141cc406Sopenharmony_ci DBG(1, "%s: no number attr in interface node\n", __func__); 1313141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1314141cc406Sopenharmony_ci } 1315141cc406Sopenharmony_ci 1316141cc406Sopenharmony_ci xmlNode* el_endpoint = 1317141cc406Sopenharmony_ci sanei_xml_find_first_child_with_name(el_interface, "endpoint"); 1318141cc406Sopenharmony_ci 1319141cc406Sopenharmony_ci while (el_endpoint != NULL) 1320141cc406Sopenharmony_ci { 1321141cc406Sopenharmony_ci char* transfer_attr = sanei_xml_get_prop(el_endpoint, 1322141cc406Sopenharmony_ci "transfer_type"); 1323141cc406Sopenharmony_ci int address = sanei_xml_get_prop_uint(el_endpoint, "address"); 1324141cc406Sopenharmony_ci char* direction_attr = sanei_xml_get_prop(el_endpoint, 1325141cc406Sopenharmony_ci "direction"); 1326141cc406Sopenharmony_ci 1327141cc406Sopenharmony_ci int direction_is_in = strcmp(direction_attr, "IN") == 0 ? 1 : 0; 1328141cc406Sopenharmony_ci int transfer_type = -1; 1329141cc406Sopenharmony_ci if (strcmp(transfer_attr, "INTERRUPT") == 0) 1330141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_INTERRUPT; 1331141cc406Sopenharmony_ci else if (strcmp(transfer_attr, "BULK") == 0) 1332141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_BULK; 1333141cc406Sopenharmony_ci else if (strcmp(transfer_attr, "ISOCHRONOUS") == 0) 1334141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_ISOCHRONOUS; 1335141cc406Sopenharmony_ci else if (strcmp(transfer_attr, "CONTROL") == 0) 1336141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_CONTROL; 1337141cc406Sopenharmony_ci else 1338141cc406Sopenharmony_ci { 1339141cc406Sopenharmony_ci DBG(3, "%s: unknown endpoint type %s\n", 1340141cc406Sopenharmony_ci __func__, transfer_attr); 1341141cc406Sopenharmony_ci } 1342141cc406Sopenharmony_ci 1343141cc406Sopenharmony_ci if (transfer_type >= 0) 1344141cc406Sopenharmony_ci { 1345141cc406Sopenharmony_ci sanei_usb_add_endpoint(&device, transfer_type, address, 1346141cc406Sopenharmony_ci direction_is_in); 1347141cc406Sopenharmony_ci } 1348141cc406Sopenharmony_ci 1349141cc406Sopenharmony_ci xmlFree(transfer_attr); 1350141cc406Sopenharmony_ci xmlFree(direction_attr); 1351141cc406Sopenharmony_ci 1352141cc406Sopenharmony_ci el_endpoint = 1353141cc406Sopenharmony_ci sanei_xml_find_next_child_with_name(el_endpoint, "endpoint"); 1354141cc406Sopenharmony_ci } 1355141cc406Sopenharmony_ci device.alt_setting = 0; 1356141cc406Sopenharmony_ci device.missing = 0; 1357141cc406Sopenharmony_ci 1358141cc406Sopenharmony_ci memcpy(&(devices[device_number]), &device, sizeof(device)); 1359141cc406Sopenharmony_ci device_number++; 1360141cc406Sopenharmony_ci 1361141cc406Sopenharmony_ci el_interface = sanei_xml_find_next_child_with_name(el_interface, 1362141cc406Sopenharmony_ci "interface"); 1363141cc406Sopenharmony_ci } 1364141cc406Sopenharmony_ci el_configuration = 1365141cc406Sopenharmony_ci sanei_xml_find_next_child_with_name(el_configurations, 1366141cc406Sopenharmony_ci "configuration"); 1367141cc406Sopenharmony_ci } 1368141cc406Sopenharmony_ci 1369141cc406Sopenharmony_ci xmlNode* el_transactions = 1370141cc406Sopenharmony_ci sanei_xml_find_first_child_with_name(el_root, "transactions"); 1371141cc406Sopenharmony_ci 1372141cc406Sopenharmony_ci if (el_transactions == NULL) 1373141cc406Sopenharmony_ci { 1374141cc406Sopenharmony_ci DBG(1, "%s: could not find transactions node\n", __func__); 1375141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1376141cc406Sopenharmony_ci } 1377141cc406Sopenharmony_ci 1378141cc406Sopenharmony_ci xmlNode* el_transaction = xmlFirstElementChild(el_transactions); 1379141cc406Sopenharmony_ci el_transaction = sanei_xml_skip_non_tx_nodes(el_transaction); 1380141cc406Sopenharmony_ci 1381141cc406Sopenharmony_ci if (el_transaction == NULL) 1382141cc406Sopenharmony_ci { 1383141cc406Sopenharmony_ci DBG(1, "%s: no transactions within capture\n", __func__); 1384141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1385141cc406Sopenharmony_ci } 1386141cc406Sopenharmony_ci 1387141cc406Sopenharmony_ci testing_xml_next_tx_node = el_transaction; 1388141cc406Sopenharmony_ci 1389141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1390141cc406Sopenharmony_ci} 1391141cc406Sopenharmony_ci 1392141cc406Sopenharmony_cistatic void sanei_usb_testing_exit() 1393141cc406Sopenharmony_ci{ 1394141cc406Sopenharmony_ci if (testing_development_mode || testing_mode == sanei_usb_testing_mode_record) 1395141cc406Sopenharmony_ci { 1396141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 1397141cc406Sopenharmony_ci { 1398141cc406Sopenharmony_ci xmlAddNextSibling(testing_append_commands_node, xmlNewText((const xmlChar*)"\n ")); 1399141cc406Sopenharmony_ci free(testing_record_backend); 1400141cc406Sopenharmony_ci } 1401141cc406Sopenharmony_ci xmlSaveFileEnc(testing_xml_path, testing_xml_doc, "UTF-8"); 1402141cc406Sopenharmony_ci } 1403141cc406Sopenharmony_ci xmlFreeDoc(testing_xml_doc); 1404141cc406Sopenharmony_ci free(testing_xml_path); 1405141cc406Sopenharmony_ci xmlCleanupParser(); 1406141cc406Sopenharmony_ci 1407141cc406Sopenharmony_ci // reset testing-related all data to initial values 1408141cc406Sopenharmony_ci testing_development_mode = 0; 1409141cc406Sopenharmony_ci testing_already_opened = 0; 1410141cc406Sopenharmony_ci testing_known_commands_input_failed = 0; 1411141cc406Sopenharmony_ci testing_last_known_seq = 0; 1412141cc406Sopenharmony_ci testing_record_backend = NULL; 1413141cc406Sopenharmony_ci testing_append_commands_node = NULL; 1414141cc406Sopenharmony_ci 1415141cc406Sopenharmony_ci testing_xml_path = NULL; 1416141cc406Sopenharmony_ci testing_xml_doc = NULL; 1417141cc406Sopenharmony_ci testing_xml_next_tx_node = NULL; 1418141cc406Sopenharmony_ci} 1419141cc406Sopenharmony_ci#else // WITH_USB_RECORD_REPLAY 1420141cc406Sopenharmony_ciSANE_Status sanei_usb_testing_enable_replay(SANE_String_Const path, 1421141cc406Sopenharmony_ci int development_mode) 1422141cc406Sopenharmony_ci{ 1423141cc406Sopenharmony_ci (void) path; 1424141cc406Sopenharmony_ci (void) development_mode; 1425141cc406Sopenharmony_ci 1426141cc406Sopenharmony_ci DBG(1, "USB record-replay mode support is missing\n"); 1427141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1428141cc406Sopenharmony_ci} 1429141cc406Sopenharmony_ci 1430141cc406Sopenharmony_ciSANE_Status sanei_usb_testing_enable_record(SANE_String_Const path, SANE_String_Const be_name) 1431141cc406Sopenharmony_ci{ 1432141cc406Sopenharmony_ci (void) path; 1433141cc406Sopenharmony_ci (void) be_name; 1434141cc406Sopenharmony_ci 1435141cc406Sopenharmony_ci DBG(1, "USB record-replay mode support is missing\n"); 1436141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1437141cc406Sopenharmony_ci} 1438141cc406Sopenharmony_ci 1439141cc406Sopenharmony_ciSANE_String sanei_usb_testing_get_backend() 1440141cc406Sopenharmony_ci{ 1441141cc406Sopenharmony_ci return NULL; 1442141cc406Sopenharmony_ci} 1443141cc406Sopenharmony_ci 1444141cc406Sopenharmony_ciSANE_Bool sanei_usb_is_replay_mode_enabled() 1445141cc406Sopenharmony_ci{ 1446141cc406Sopenharmony_ci return SANE_FALSE; 1447141cc406Sopenharmony_ci} 1448141cc406Sopenharmony_ci 1449141cc406Sopenharmony_civoid sanei_usb_testing_record_clear() 1450141cc406Sopenharmony_ci{ 1451141cc406Sopenharmony_ci} 1452141cc406Sopenharmony_ci 1453141cc406Sopenharmony_civoid sanei_usb_testing_record_message(SANE_String_Const message) 1454141cc406Sopenharmony_ci{ 1455141cc406Sopenharmony_ci (void) message; 1456141cc406Sopenharmony_ci} 1457141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 1458141cc406Sopenharmony_ci 1459141cc406Sopenharmony_civoid 1460141cc406Sopenharmony_cisanei_usb_init (void) 1461141cc406Sopenharmony_ci{ 1462141cc406Sopenharmony_ci#if defined(HAVE_LIBUSB) || defined(HAVE_USB_MANAGER) 1463141cc406Sopenharmony_ci int ret; 1464141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB || HAVE_USB_MANAGER */ 1465141cc406Sopenharmony_ci 1466141cc406Sopenharmony_ci DBG_INIT (); 1467141cc406Sopenharmony_ci#ifdef DBG_LEVEL 1468141cc406Sopenharmony_ci debug_level = DBG_LEVEL; 1469141cc406Sopenharmony_ci#else 1470141cc406Sopenharmony_ci debug_level = 0; 1471141cc406Sopenharmony_ci#endif 1472141cc406Sopenharmony_ci 1473141cc406Sopenharmony_ci /* if no device yet, clean up memory */ 1474141cc406Sopenharmony_ci if(device_number==0) 1475141cc406Sopenharmony_ci memset (devices, 0, sizeof (devices)); 1476141cc406Sopenharmony_ci 1477141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 1478141cc406Sopenharmony_ci if (testing_mode != sanei_usb_testing_mode_disabled) 1479141cc406Sopenharmony_ci { 1480141cc406Sopenharmony_ci if (initialized == 0) 1481141cc406Sopenharmony_ci { 1482141cc406Sopenharmony_ci if (sanei_usb_testing_init() != SANE_STATUS_GOOD) 1483141cc406Sopenharmony_ci { 1484141cc406Sopenharmony_ci DBG(1, "%s: failed initializing fake USB stack\n", __func__); 1485141cc406Sopenharmony_ci return; 1486141cc406Sopenharmony_ci } 1487141cc406Sopenharmony_ci } 1488141cc406Sopenharmony_ci 1489141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 1490141cc406Sopenharmony_ci { 1491141cc406Sopenharmony_ci initialized++; 1492141cc406Sopenharmony_ci return; 1493141cc406Sopenharmony_ci } 1494141cc406Sopenharmony_ci } 1495141cc406Sopenharmony_ci#endif 1496141cc406Sopenharmony_ci 1497141cc406Sopenharmony_ci /* initialize USB with old libusb library */ 1498141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 1499141cc406Sopenharmony_ci DBG (4, "%s: Looking for libusb devices\n", __func__); 1500141cc406Sopenharmony_ci usb_init (); 1501141cc406Sopenharmony_ci#ifdef DBG_LEVEL 1502141cc406Sopenharmony_ci if (DBG_LEVEL > 4) 1503141cc406Sopenharmony_ci usb_set_debug (255); 1504141cc406Sopenharmony_ci#endif /* DBG_LEVEL */ 1505141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY */ 1506141cc406Sopenharmony_ci 1507141cc406Sopenharmony_ci 1508141cc406Sopenharmony_ci /* initialize USB using libusb-1.0 */ 1509141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB 1510141cc406Sopenharmony_ci if (!sanei_usb_ctx) 1511141cc406Sopenharmony_ci { 1512141cc406Sopenharmony_ci DBG (4, "%s: initializing libusb-1.0\n", __func__); 1513141cc406Sopenharmony_ci ret = libusb_init (&sanei_usb_ctx); 1514141cc406Sopenharmony_ci if (ret < 0) 1515141cc406Sopenharmony_ci { 1516141cc406Sopenharmony_ci DBG (1, 1517141cc406Sopenharmony_ci "%s: failed to initialize libusb-1.0, error %d\n", __func__, 1518141cc406Sopenharmony_ci ret); 1519141cc406Sopenharmony_ci return; 1520141cc406Sopenharmony_ci } 1521141cc406Sopenharmony_ci#ifdef DBG_LEVEL 1522141cc406Sopenharmony_ci if (DBG_LEVEL > 4) 1523141cc406Sopenharmony_ci#if LIBUSB_API_VERSION >= 0x01000106 1524141cc406Sopenharmony_ci libusb_set_option (sanei_usb_ctx, LIBUSB_OPTION_LOG_LEVEL, 1525141cc406Sopenharmony_ci LIBUSB_LOG_LEVEL_INFO); 1526141cc406Sopenharmony_ci#else 1527141cc406Sopenharmony_ci libusb_set_debug (sanei_usb_ctx, 3); 1528141cc406Sopenharmony_ci#endif /* LIBUSB_API_VERSION */ 1529141cc406Sopenharmony_ci#endif /* DBG_LEVEL */ 1530141cc406Sopenharmony_ci } 1531141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB */ 1532141cc406Sopenharmony_ci 1533141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 1534141cc406Sopenharmony_ci if (!sanei_usb_ctx) 1535141cc406Sopenharmony_ci { 1536141cc406Sopenharmony_ci DBG (4, "%s: initializing usb_manager\n", __func__); 1537141cc406Sopenharmony_ci ret = usb_manager_init (&sanei_usb_ctx); 1538141cc406Sopenharmony_ci if (ret < 0) 1539141cc406Sopenharmony_ci { 1540141cc406Sopenharmony_ci DBG (1, 1541141cc406Sopenharmony_ci "%s: failed to initialize usb_manager, error %d\n", __func__, 1542141cc406Sopenharmony_ci ret); 1543141cc406Sopenharmony_ci return; 1544141cc406Sopenharmony_ci } 1545141cc406Sopenharmony_ci } 1546141cc406Sopenharmony_ci#endif /* HAVE_USB_MANAGER */ 1547141cc406Sopenharmony_ci 1548141cc406Sopenharmony_ci#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) 1549141cc406Sopenharmony_ci DBG (4, "%s: SANE is built without support for libusb\n", __func__); 1550141cc406Sopenharmony_ci#endif 1551141cc406Sopenharmony_ci 1552141cc406Sopenharmony_ci /* sanei_usb is now initialized */ 1553141cc406Sopenharmony_ci initialized++; 1554141cc406Sopenharmony_ci 1555141cc406Sopenharmony_ci /* do a first scan of USB buses to fill device list */ 1556141cc406Sopenharmony_ci sanei_usb_scan_devices(); 1557141cc406Sopenharmony_ci} 1558141cc406Sopenharmony_ci 1559141cc406Sopenharmony_civoid 1560141cc406Sopenharmony_cisanei_usb_exit (void) 1561141cc406Sopenharmony_ci{ 1562141cc406Sopenharmony_ciint i; 1563141cc406Sopenharmony_ci 1564141cc406Sopenharmony_ci /* check we have really some work to do */ 1565141cc406Sopenharmony_ci if(initialized==0) 1566141cc406Sopenharmony_ci { 1567141cc406Sopenharmony_ci DBG (1, "%s: sanei_usb in not initialized!\n", __func__); 1568141cc406Sopenharmony_ci return; 1569141cc406Sopenharmony_ci } 1570141cc406Sopenharmony_ci 1571141cc406Sopenharmony_ci /* decrement the use count */ 1572141cc406Sopenharmony_ci initialized--; 1573141cc406Sopenharmony_ci 1574141cc406Sopenharmony_ci /* if we reach 0, free allocated resources */ 1575141cc406Sopenharmony_ci if(initialized==0) 1576141cc406Sopenharmony_ci { 1577141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 1578141cc406Sopenharmony_ci if (testing_mode != sanei_usb_testing_mode_disabled) 1579141cc406Sopenharmony_ci { 1580141cc406Sopenharmony_ci sanei_usb_testing_exit(); 1581141cc406Sopenharmony_ci } 1582141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 1583141cc406Sopenharmony_ci 1584141cc406Sopenharmony_ci /* free allocated resources */ 1585141cc406Sopenharmony_ci DBG (4, "%s: freeing resources\n", __func__); 1586141cc406Sopenharmony_ci for (i = 0; i < device_number; i++) 1587141cc406Sopenharmony_ci { 1588141cc406Sopenharmony_ci if (devices[i].devname != NULL) 1589141cc406Sopenharmony_ci { 1590141cc406Sopenharmony_ci DBG (5, "%s: freeing device %02d\n", __func__, i); 1591141cc406Sopenharmony_ci free(devices[i].devname); 1592141cc406Sopenharmony_ci devices[i].devname=NULL; 1593141cc406Sopenharmony_ci } 1594141cc406Sopenharmony_ci } 1595141cc406Sopenharmony_ci#if defined(HAVE_LIBUSB) 1596141cc406Sopenharmony_ci if (sanei_usb_ctx) 1597141cc406Sopenharmony_ci { 1598141cc406Sopenharmony_ci libusb_exit (sanei_usb_ctx); 1599141cc406Sopenharmony_ci /* reset libusb-1.0 context */ 1600141cc406Sopenharmony_ci sanei_usb_ctx=NULL; 1601141cc406Sopenharmony_ci } 1602141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 1603141cc406Sopenharmony_ci if (sanei_usb_ctx) 1604141cc406Sopenharmony_ci { 1605141cc406Sopenharmony_ci usb_manager_exit (sanei_usb_ctx); 1606141cc406Sopenharmony_ci /* reset usb_manager context */ 1607141cc406Sopenharmony_ci sanei_usb_ctx=NULL; 1608141cc406Sopenharmony_ci } 1609141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB || HAVE_USB_MANAGER */ 1610141cc406Sopenharmony_ci /* reset device_number */ 1611141cc406Sopenharmony_ci device_number=0; 1612141cc406Sopenharmony_ci } 1613141cc406Sopenharmony_ci else 1614141cc406Sopenharmony_ci { 1615141cc406Sopenharmony_ci DBG (4, "%s: not freeing resources since use count is %d\n", __func__, initialized); 1616141cc406Sopenharmony_ci } 1617141cc406Sopenharmony_ci return; 1618141cc406Sopenharmony_ci} 1619141cc406Sopenharmony_ci 1620141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 1621141cc406Sopenharmony_ci/** scan for devices through usbcall method 1622141cc406Sopenharmony_ci * Check for devices using OS/2 USBCALLS Interface 1623141cc406Sopenharmony_ci */ 1624141cc406Sopenharmony_cistatic void usbcall_scan_devices(void) 1625141cc406Sopenharmony_ci{ 1626141cc406Sopenharmony_ci SANE_Char devname[1024]; 1627141cc406Sopenharmony_ci device_list_type device; 1628141cc406Sopenharmony_ci CHAR ucData[2048]; 1629141cc406Sopenharmony_ci struct usb_device_descriptor *pDevDesc; 1630141cc406Sopenharmony_ci struct usb_config_descriptor *pCfgDesc; 1631141cc406Sopenharmony_ci 1632141cc406Sopenharmony_ci APIRET rc; 1633141cc406Sopenharmony_ci ULONG ulNumDev, ulDev, ulBufLen; 1634141cc406Sopenharmony_ci 1635141cc406Sopenharmony_ci ulBufLen = sizeof(ucData); 1636141cc406Sopenharmony_ci memset(&ucData,0,sizeof(ucData)); 1637141cc406Sopenharmony_ci rc = UsbQueryNumberDevices( &ulNumDev); 1638141cc406Sopenharmony_ci 1639141cc406Sopenharmony_ci if(rc==0 && ulNumDev) 1640141cc406Sopenharmony_ci { 1641141cc406Sopenharmony_ci for (ulDev=1; ulDev<=ulNumDev; ulDev++) 1642141cc406Sopenharmony_ci { 1643141cc406Sopenharmony_ci UsbQueryDeviceReport(ulDev, &ulBufLen, ucData); 1644141cc406Sopenharmony_ci 1645141cc406Sopenharmony_ci pDevDesc = (struct usb_device_descriptor*) ucData; 1646141cc406Sopenharmony_ci pCfgDesc = (struct usb_config_descriptor*) (ucData+sizeof(struct usb_device_descriptor)); 1647141cc406Sopenharmony_ci int interface=0; 1648141cc406Sopenharmony_ci SANE_Bool found; 1649141cc406Sopenharmony_ci if (!pCfgDesc->bConfigurationValue) 1650141cc406Sopenharmony_ci { 1651141cc406Sopenharmony_ci DBG (1, "%s: device 0x%04x/0x%04x is not configured\n", __func__, 1652141cc406Sopenharmony_ci pDevDesc->idVendor, pDevDesc->idProduct); 1653141cc406Sopenharmony_ci continue; 1654141cc406Sopenharmony_ci } 1655141cc406Sopenharmony_ci if (pDevDesc->idVendor == 0 || pDevDesc->idProduct == 0) 1656141cc406Sopenharmony_ci { 1657141cc406Sopenharmony_ci DBG (5, "%s: device 0x%04x/0x%04x looks like a root hub\n", __func__, 1658141cc406Sopenharmony_ci pDevDesc->idVendor, pDevDesc->idProduct); 1659141cc406Sopenharmony_ci continue; 1660141cc406Sopenharmony_ci } 1661141cc406Sopenharmony_ci found = SANE_FALSE; 1662141cc406Sopenharmony_ci 1663141cc406Sopenharmony_ci if (pDevDesc->bDeviceClass == USB_CLASS_VENDOR_SPEC) 1664141cc406Sopenharmony_ci { 1665141cc406Sopenharmony_ci found = SANE_TRUE; 1666141cc406Sopenharmony_ci } 1667141cc406Sopenharmony_ci 1668141cc406Sopenharmony_ci if (!found) 1669141cc406Sopenharmony_ci { 1670141cc406Sopenharmony_ci DBG (5, "%s: device 0x%04x/0x%04x: no suitable interfaces\n", __func__, 1671141cc406Sopenharmony_ci pDevDesc->idVendor, pDevDesc->idProduct); 1672141cc406Sopenharmony_ci continue; 1673141cc406Sopenharmony_ci } 1674141cc406Sopenharmony_ci 1675141cc406Sopenharmony_ci snprintf (devname, sizeof (devname), "usbcalls:%d", ulDev); 1676141cc406Sopenharmony_ci memset (&device, 0, sizeof (device)); 1677141cc406Sopenharmony_ci device.devname = strdup (devname); 1678141cc406Sopenharmony_ci device.fd = ulDev; /* store usbcalls device number */ 1679141cc406Sopenharmony_ci device.vendor = pDevDesc->idVendor; 1680141cc406Sopenharmony_ci device.product = pDevDesc->idProduct; 1681141cc406Sopenharmony_ci device.method = sanei_usb_method_usbcalls; 1682141cc406Sopenharmony_ci device.interface_nr = interface; 1683141cc406Sopenharmony_ci device.alt_setting = 0; 1684141cc406Sopenharmony_ci DBG (4, "%s: found usbcalls device (0x%04x/0x%04x) as device number %s\n", __func__, 1685141cc406Sopenharmony_ci pDevDesc->idVendor, pDevDesc->idProduct,device.devname); 1686141cc406Sopenharmony_ci store_device(device); 1687141cc406Sopenharmony_ci } 1688141cc406Sopenharmony_ci } 1689141cc406Sopenharmony_ci} 1690141cc406Sopenharmony_ci#endif /* HAVE_USBCALLS */ 1691141cc406Sopenharmony_ci 1692141cc406Sopenharmony_ci#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) 1693141cc406Sopenharmony_ci/** scan for devices using kernel device. 1694141cc406Sopenharmony_ci * Check for devices using kernel device 1695141cc406Sopenharmony_ci */ 1696141cc406Sopenharmony_cistatic void kernel_scan_devices(void) 1697141cc406Sopenharmony_ci{ 1698141cc406Sopenharmony_ci SANE_String *prefix; 1699141cc406Sopenharmony_ci SANE_String prefixlist[] = { 1700141cc406Sopenharmony_ci#if defined(__linux__) 1701141cc406Sopenharmony_ci "/dev/", "usbscanner", 1702141cc406Sopenharmony_ci "/dev/usb/", "scanner", 1703141cc406Sopenharmony_ci#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined (__DragonFly__) 1704141cc406Sopenharmony_ci "/dev/", "uscanner", 1705141cc406Sopenharmony_ci#elif defined(__BEOS__) 1706141cc406Sopenharmony_ci "/dev/scanner/usb/", "", 1707141cc406Sopenharmony_ci#endif 1708141cc406Sopenharmony_ci 0, 0 1709141cc406Sopenharmony_ci }; 1710141cc406Sopenharmony_ci SANE_Int vendor, product; 1711141cc406Sopenharmony_ci SANE_Char devname[1024]; 1712141cc406Sopenharmony_ci int fd; 1713141cc406Sopenharmony_ci device_list_type device; 1714141cc406Sopenharmony_ci 1715141cc406Sopenharmony_ci DBG (4, "%s: Looking for kernel scanner devices\n", __func__); 1716141cc406Sopenharmony_ci /* Check for devices using the kernel scanner driver */ 1717141cc406Sopenharmony_ci 1718141cc406Sopenharmony_ci for (prefix = prefixlist; *prefix; prefix += 2) 1719141cc406Sopenharmony_ci { 1720141cc406Sopenharmony_ci SANE_String dir_name = *prefix; 1721141cc406Sopenharmony_ci SANE_String base_name = *(prefix + 1); 1722141cc406Sopenharmony_ci struct stat stat_buf; 1723141cc406Sopenharmony_ci DIR *dir; 1724141cc406Sopenharmony_ci struct dirent *dir_entry; 1725141cc406Sopenharmony_ci 1726141cc406Sopenharmony_ci if (stat (dir_name, &stat_buf) < 0) 1727141cc406Sopenharmony_ci { 1728141cc406Sopenharmony_ci DBG (5, "%s: can't stat %s: %s\n", __func__, dir_name, 1729141cc406Sopenharmony_ci strerror (errno)); 1730141cc406Sopenharmony_ci continue; 1731141cc406Sopenharmony_ci } 1732141cc406Sopenharmony_ci if (!S_ISDIR (stat_buf.st_mode)) 1733141cc406Sopenharmony_ci { 1734141cc406Sopenharmony_ci DBG (5, "%s: %s is not a directory\n", __func__, dir_name); 1735141cc406Sopenharmony_ci continue; 1736141cc406Sopenharmony_ci } 1737141cc406Sopenharmony_ci if ((dir = opendir (dir_name)) == 0) 1738141cc406Sopenharmony_ci { 1739141cc406Sopenharmony_ci DBG (5, "%s: cannot read directory %s: %s\n", __func__, dir_name, 1740141cc406Sopenharmony_ci strerror (errno)); 1741141cc406Sopenharmony_ci continue; 1742141cc406Sopenharmony_ci } 1743141cc406Sopenharmony_ci 1744141cc406Sopenharmony_ci while ((dir_entry = readdir (dir)) != 0) 1745141cc406Sopenharmony_ci { 1746141cc406Sopenharmony_ci /* skip standard dir entries */ 1747141cc406Sopenharmony_ci if (strcmp (dir_entry->d_name, ".") == 0 || strcmp (dir_entry->d_name, "..") == 0) 1748141cc406Sopenharmony_ci continue; 1749141cc406Sopenharmony_ci 1750141cc406Sopenharmony_ci if (strncmp (base_name, dir_entry->d_name, strlen (base_name)) == 0) 1751141cc406Sopenharmony_ci { 1752141cc406Sopenharmony_ci if (strlen (dir_name) + strlen (dir_entry->d_name) + 1 > 1753141cc406Sopenharmony_ci sizeof (devname)) 1754141cc406Sopenharmony_ci continue; 1755141cc406Sopenharmony_ci sprintf (devname, "%s%s", dir_name, dir_entry->d_name); 1756141cc406Sopenharmony_ci fd = -1; 1757141cc406Sopenharmony_ci#ifdef HAVE_RESMGR 1758141cc406Sopenharmony_ci fd = rsm_open_device (devname, O_RDWR); 1759141cc406Sopenharmony_ci#endif 1760141cc406Sopenharmony_ci if (fd == -1) 1761141cc406Sopenharmony_ci fd = open (devname, O_RDWR); 1762141cc406Sopenharmony_ci if (fd < 0) 1763141cc406Sopenharmony_ci { 1764141cc406Sopenharmony_ci DBG (5, "%s: couldn't open %s: %s\n", __func__, devname, 1765141cc406Sopenharmony_ci strerror (errno)); 1766141cc406Sopenharmony_ci continue; 1767141cc406Sopenharmony_ci } 1768141cc406Sopenharmony_ci vendor = -1; 1769141cc406Sopenharmony_ci product = -1; 1770141cc406Sopenharmony_ci kernel_get_vendor_product (fd, devname, &vendor, &product); 1771141cc406Sopenharmony_ci close (fd); 1772141cc406Sopenharmony_ci memset (&device, 0, sizeof (device)); 1773141cc406Sopenharmony_ci device.devname = strdup (devname); 1774141cc406Sopenharmony_ci if (!device.devname) 1775141cc406Sopenharmony_ci { 1776141cc406Sopenharmony_ci closedir (dir); 1777141cc406Sopenharmony_ci return; 1778141cc406Sopenharmony_ci } 1779141cc406Sopenharmony_ci device.vendor = vendor; 1780141cc406Sopenharmony_ci device.product = product; 1781141cc406Sopenharmony_ci device.method = sanei_usb_method_scanner_driver; 1782141cc406Sopenharmony_ci DBG (4, 1783141cc406Sopenharmony_ci "%s: found kernel scanner device (0x%04x/0x%04x) at %s\n", __func__, 1784141cc406Sopenharmony_ci vendor, product, devname); 1785141cc406Sopenharmony_ci store_device(device); 1786141cc406Sopenharmony_ci } 1787141cc406Sopenharmony_ci } 1788141cc406Sopenharmony_ci closedir (dir); 1789141cc406Sopenharmony_ci } 1790141cc406Sopenharmony_ci} 1791141cc406Sopenharmony_ci#endif /* !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) */ 1792141cc406Sopenharmony_ci 1793141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 1794141cc406Sopenharmony_ci/** scan for devices using old libusb 1795141cc406Sopenharmony_ci * Check for devices using 0.1.x libusb 1796141cc406Sopenharmony_ci */ 1797141cc406Sopenharmony_cistatic void libusb_scan_devices(void) 1798141cc406Sopenharmony_ci{ 1799141cc406Sopenharmony_ci struct usb_bus *bus; 1800141cc406Sopenharmony_ci struct usb_device *dev; 1801141cc406Sopenharmony_ci SANE_Char devname[1024]; 1802141cc406Sopenharmony_ci device_list_type device; 1803141cc406Sopenharmony_ci 1804141cc406Sopenharmony_ci DBG (4, "%s: Looking for libusb devices\n", __func__); 1805141cc406Sopenharmony_ci 1806141cc406Sopenharmony_ci usb_find_busses (); 1807141cc406Sopenharmony_ci usb_find_devices (); 1808141cc406Sopenharmony_ci 1809141cc406Sopenharmony_ci /* Check for the matching device */ 1810141cc406Sopenharmony_ci for (bus = usb_get_busses (); bus; bus = bus->next) 1811141cc406Sopenharmony_ci { 1812141cc406Sopenharmony_ci for (dev = bus->devices; dev; dev = dev->next) 1813141cc406Sopenharmony_ci { 1814141cc406Sopenharmony_ci int interface; 1815141cc406Sopenharmony_ci SANE_Bool found = SANE_FALSE; 1816141cc406Sopenharmony_ci 1817141cc406Sopenharmony_ci if (!dev->config) 1818141cc406Sopenharmony_ci { 1819141cc406Sopenharmony_ci DBG (1, 1820141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x is not configured\n", __func__, 1821141cc406Sopenharmony_ci dev->descriptor.idVendor, dev->descriptor.idProduct); 1822141cc406Sopenharmony_ci continue; 1823141cc406Sopenharmony_ci } 1824141cc406Sopenharmony_ci if (dev->descriptor.idVendor == 0 || dev->descriptor.idProduct == 0) 1825141cc406Sopenharmony_ci { 1826141cc406Sopenharmony_ci DBG (5, 1827141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x looks like a root hub\n", __func__, 1828141cc406Sopenharmony_ci dev->descriptor.idVendor, dev->descriptor.idProduct); 1829141cc406Sopenharmony_ci continue; 1830141cc406Sopenharmony_ci } 1831141cc406Sopenharmony_ci 1832141cc406Sopenharmony_ci for (interface = 0; 1833141cc406Sopenharmony_ci interface < dev->config[0].bNumInterfaces && !found; 1834141cc406Sopenharmony_ci interface++) 1835141cc406Sopenharmony_ci { 1836141cc406Sopenharmony_ci switch (dev->descriptor.bDeviceClass) 1837141cc406Sopenharmony_ci { 1838141cc406Sopenharmony_ci case USB_CLASS_VENDOR_SPEC: 1839141cc406Sopenharmony_ci found = SANE_TRUE; 1840141cc406Sopenharmony_ci break; 1841141cc406Sopenharmony_ci case USB_CLASS_PER_INTERFACE: 1842141cc406Sopenharmony_ci if (dev->config[0].interface[interface].num_altsetting == 0 || 1843141cc406Sopenharmony_ci !dev->config[0].interface[interface].altsetting) 1844141cc406Sopenharmony_ci { 1845141cc406Sopenharmony_ci DBG (1, "%s: device 0x%04x/0x%04x doesn't " 1846141cc406Sopenharmony_ci "have an altsetting for interface %d\n", __func__, 1847141cc406Sopenharmony_ci dev->descriptor.idVendor, dev->descriptor.idProduct, 1848141cc406Sopenharmony_ci interface); 1849141cc406Sopenharmony_ci continue; 1850141cc406Sopenharmony_ci } 1851141cc406Sopenharmony_ci switch (dev->config[0].interface[interface].altsetting[0]. 1852141cc406Sopenharmony_ci bInterfaceClass) 1853141cc406Sopenharmony_ci { 1854141cc406Sopenharmony_ci case USB_CLASS_VENDOR_SPEC: 1855141cc406Sopenharmony_ci case USB_CLASS_PER_INTERFACE: 1856141cc406Sopenharmony_ci case 6: /* imaging? */ 1857141cc406Sopenharmony_ci case 16: /* data? */ 1858141cc406Sopenharmony_ci found = SANE_TRUE; 1859141cc406Sopenharmony_ci break; 1860141cc406Sopenharmony_ci } 1861141cc406Sopenharmony_ci break; 1862141cc406Sopenharmony_ci } 1863141cc406Sopenharmony_ci if (!found) 1864141cc406Sopenharmony_ci DBG (5, 1865141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x, interface %d " 1866141cc406Sopenharmony_ci "doesn't look like a " 1867141cc406Sopenharmony_ci "scanner (%d/%d)\n", __func__, dev->descriptor.idVendor, 1868141cc406Sopenharmony_ci dev->descriptor.idProduct, interface, 1869141cc406Sopenharmony_ci dev->descriptor.bDeviceClass, 1870141cc406Sopenharmony_ci dev->config[0].interface[interface].num_altsetting != 0 1871141cc406Sopenharmony_ci ? dev->config[0].interface[interface].altsetting[0]. 1872141cc406Sopenharmony_ci bInterfaceClass : -1); 1873141cc406Sopenharmony_ci } 1874141cc406Sopenharmony_ci interface--; 1875141cc406Sopenharmony_ci if (!found) 1876141cc406Sopenharmony_ci { 1877141cc406Sopenharmony_ci DBG (5, 1878141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x: no suitable interfaces\n", __func__, 1879141cc406Sopenharmony_ci dev->descriptor.idVendor, dev->descriptor.idProduct); 1880141cc406Sopenharmony_ci continue; 1881141cc406Sopenharmony_ci } 1882141cc406Sopenharmony_ci 1883141cc406Sopenharmony_ci memset (&device, 0, sizeof (device)); 1884141cc406Sopenharmony_ci device.libusb_device = dev; 1885141cc406Sopenharmony_ci snprintf (devname, sizeof (devname), "libusb:%s:%s", 1886141cc406Sopenharmony_ci dev->bus->dirname, dev->filename); 1887141cc406Sopenharmony_ci device.devname = strdup (devname); 1888141cc406Sopenharmony_ci if (!device.devname) 1889141cc406Sopenharmony_ci return; 1890141cc406Sopenharmony_ci device.vendor = dev->descriptor.idVendor; 1891141cc406Sopenharmony_ci device.product = dev->descriptor.idProduct; 1892141cc406Sopenharmony_ci device.method = sanei_usb_method_libusb; 1893141cc406Sopenharmony_ci device.interface_nr = interface; 1894141cc406Sopenharmony_ci device.alt_setting = 0; 1895141cc406Sopenharmony_ci DBG (4, 1896141cc406Sopenharmony_ci "%s: found libusb device (0x%04x/0x%04x) interface " 1897141cc406Sopenharmony_ci "%d at %s\n", __func__, 1898141cc406Sopenharmony_ci dev->descriptor.idVendor, dev->descriptor.idProduct, interface, 1899141cc406Sopenharmony_ci devname); 1900141cc406Sopenharmony_ci store_device(device); 1901141cc406Sopenharmony_ci } 1902141cc406Sopenharmony_ci } 1903141cc406Sopenharmony_ci} 1904141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY */ 1905141cc406Sopenharmony_ci 1906141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB 1907141cc406Sopenharmony_ci/** scan for devices using libusb 1908141cc406Sopenharmony_ci * Check for devices using libusb-1.0 1909141cc406Sopenharmony_ci */ 1910141cc406Sopenharmony_cistatic void libusb_scan_devices(void) 1911141cc406Sopenharmony_ci{ 1912141cc406Sopenharmony_ci device_list_type device; 1913141cc406Sopenharmony_ci SANE_Char devname[1024]; 1914141cc406Sopenharmony_ci libusb_device **devlist; 1915141cc406Sopenharmony_ci ssize_t ndev; 1916141cc406Sopenharmony_ci libusb_device *dev; 1917141cc406Sopenharmony_ci libusb_device_handle *hdl; 1918141cc406Sopenharmony_ci struct libusb_device_descriptor desc; 1919141cc406Sopenharmony_ci struct libusb_config_descriptor *config0; 1920141cc406Sopenharmony_ci unsigned short vid, pid; 1921141cc406Sopenharmony_ci unsigned char busno, address; 1922141cc406Sopenharmony_ci int config; 1923141cc406Sopenharmony_ci int interface; 1924141cc406Sopenharmony_ci int ret; 1925141cc406Sopenharmony_ci int i; 1926141cc406Sopenharmony_ci 1927141cc406Sopenharmony_ci DBG (4, "%s: Looking for libusb-1.0 devices\n", __func__); 1928141cc406Sopenharmony_ci 1929141cc406Sopenharmony_ci ndev = libusb_get_device_list (sanei_usb_ctx, &devlist); 1930141cc406Sopenharmony_ci if (ndev < 0) 1931141cc406Sopenharmony_ci { 1932141cc406Sopenharmony_ci DBG (1, 1933141cc406Sopenharmony_ci "%s: failed to get libusb-1.0 device list, error %d\n", __func__, 1934141cc406Sopenharmony_ci (int) ndev); 1935141cc406Sopenharmony_ci return; 1936141cc406Sopenharmony_ci } 1937141cc406Sopenharmony_ci 1938141cc406Sopenharmony_ci for (i = 0; i < ndev; i++) 1939141cc406Sopenharmony_ci { 1940141cc406Sopenharmony_ci SANE_Bool found = SANE_FALSE; 1941141cc406Sopenharmony_ci 1942141cc406Sopenharmony_ci dev = devlist[i]; 1943141cc406Sopenharmony_ci 1944141cc406Sopenharmony_ci busno = libusb_get_bus_number (dev); 1945141cc406Sopenharmony_ci address = libusb_get_device_address (dev); 1946141cc406Sopenharmony_ci 1947141cc406Sopenharmony_ci ret = libusb_get_device_descriptor (dev, &desc); 1948141cc406Sopenharmony_ci if (ret < 0) 1949141cc406Sopenharmony_ci { 1950141cc406Sopenharmony_ci DBG (1, 1951141cc406Sopenharmony_ci "%s: could not get device descriptor for device at %03d:%03d (err %d)\n", __func__, 1952141cc406Sopenharmony_ci busno, address, ret); 1953141cc406Sopenharmony_ci continue; 1954141cc406Sopenharmony_ci } 1955141cc406Sopenharmony_ci 1956141cc406Sopenharmony_ci vid = desc.idVendor; 1957141cc406Sopenharmony_ci pid = desc.idProduct; 1958141cc406Sopenharmony_ci 1959141cc406Sopenharmony_ci if ((vid == 0) || (pid == 0)) 1960141cc406Sopenharmony_ci { 1961141cc406Sopenharmony_ci DBG (5, 1962141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x at %03d:%03d looks like a root hub\n", __func__, 1963141cc406Sopenharmony_ci vid, pid, busno, address); 1964141cc406Sopenharmony_ci continue; 1965141cc406Sopenharmony_ci } 1966141cc406Sopenharmony_ci 1967141cc406Sopenharmony_ci ret = libusb_open (dev, &hdl); 1968141cc406Sopenharmony_ci if (ret < 0) 1969141cc406Sopenharmony_ci { 1970141cc406Sopenharmony_ci DBG (1, 1971141cc406Sopenharmony_ci "%s: skipping device 0x%04x/0x%04x at %03d:%03d: cannot open: %s\n", __func__, 1972141cc406Sopenharmony_ci vid, pid, busno, address, sanei_libusb_strerror (ret)); 1973141cc406Sopenharmony_ci 1974141cc406Sopenharmony_ci continue; 1975141cc406Sopenharmony_ci } 1976141cc406Sopenharmony_ci 1977141cc406Sopenharmony_ci ret = libusb_get_configuration (hdl, &config); 1978141cc406Sopenharmony_ci 1979141cc406Sopenharmony_ci libusb_close (hdl); 1980141cc406Sopenharmony_ci 1981141cc406Sopenharmony_ci if (ret < 0) 1982141cc406Sopenharmony_ci { 1983141cc406Sopenharmony_ci DBG (1, 1984141cc406Sopenharmony_ci "%s: could not get configuration for device 0x%04x/0x%04x at %03d:%03d (err %d)\n", __func__, 1985141cc406Sopenharmony_ci vid, pid, busno, address, ret); 1986141cc406Sopenharmony_ci continue; 1987141cc406Sopenharmony_ci } 1988141cc406Sopenharmony_ci 1989141cc406Sopenharmony_ci#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES) 1990141cc406Sopenharmony_ci if (config == 0) 1991141cc406Sopenharmony_ci { 1992141cc406Sopenharmony_ci DBG (1, 1993141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x at %03d:%03d is not configured\n", __func__, 1994141cc406Sopenharmony_ci vid, pid, busno, address); 1995141cc406Sopenharmony_ci continue; 1996141cc406Sopenharmony_ci } 1997141cc406Sopenharmony_ci#endif 1998141cc406Sopenharmony_ci 1999141cc406Sopenharmony_ci ret = libusb_get_config_descriptor (dev, 0, &config0); 2000141cc406Sopenharmony_ci if (ret < 0) 2001141cc406Sopenharmony_ci { 2002141cc406Sopenharmony_ci DBG (1, 2003141cc406Sopenharmony_ci "%s: could not get config[0] descriptor for device 0x%04x/0x%04x at %03d:%03d (err %d)\n", __func__, 2004141cc406Sopenharmony_ci vid, pid, busno, address, ret); 2005141cc406Sopenharmony_ci continue; 2006141cc406Sopenharmony_ci } 2007141cc406Sopenharmony_ci 2008141cc406Sopenharmony_ci for (interface = 0; (interface < config0->bNumInterfaces) && !found; interface++) 2009141cc406Sopenharmony_ci { 2010141cc406Sopenharmony_ci switch (desc.bDeviceClass) 2011141cc406Sopenharmony_ci { 2012141cc406Sopenharmony_ci case LIBUSB_CLASS_VENDOR_SPEC: 2013141cc406Sopenharmony_ci found = SANE_TRUE; 2014141cc406Sopenharmony_ci break; 2015141cc406Sopenharmony_ci 2016141cc406Sopenharmony_ci case LIBUSB_CLASS_PER_INTERFACE: 2017141cc406Sopenharmony_ci if ((config0->interface[interface].num_altsetting == 0) 2018141cc406Sopenharmony_ci || !config0->interface[interface].altsetting) 2019141cc406Sopenharmony_ci { 2020141cc406Sopenharmony_ci DBG (1, "%s: device 0x%04x/0x%04x doesn't " 2021141cc406Sopenharmony_ci "have an altsetting for interface %d\n", __func__, 2022141cc406Sopenharmony_ci vid, pid, interface); 2023141cc406Sopenharmony_ci continue; 2024141cc406Sopenharmony_ci } 2025141cc406Sopenharmony_ci 2026141cc406Sopenharmony_ci switch (config0->interface[interface].altsetting[0].bInterfaceClass) 2027141cc406Sopenharmony_ci { 2028141cc406Sopenharmony_ci case LIBUSB_CLASS_VENDOR_SPEC: 2029141cc406Sopenharmony_ci case LIBUSB_CLASS_PER_INTERFACE: 2030141cc406Sopenharmony_ci case LIBUSB_CLASS_PTP: 2031141cc406Sopenharmony_ci case 16: /* data? */ 2032141cc406Sopenharmony_ci found = SANE_TRUE; 2033141cc406Sopenharmony_ci break; 2034141cc406Sopenharmony_ci } 2035141cc406Sopenharmony_ci break; 2036141cc406Sopenharmony_ci } 2037141cc406Sopenharmony_ci 2038141cc406Sopenharmony_ci if (!found) 2039141cc406Sopenharmony_ci DBG (5, 2040141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x, interface %d " 2041141cc406Sopenharmony_ci "doesn't look like a scanner (%d/%d)\n", __func__, 2042141cc406Sopenharmony_ci vid, pid, interface, desc.bDeviceClass, 2043141cc406Sopenharmony_ci (config0->interface[interface].num_altsetting != 0) 2044141cc406Sopenharmony_ci ? config0->interface[interface].altsetting[0].bInterfaceClass : -1); 2045141cc406Sopenharmony_ci } 2046141cc406Sopenharmony_ci 2047141cc406Sopenharmony_ci libusb_free_config_descriptor (config0); 2048141cc406Sopenharmony_ci 2049141cc406Sopenharmony_ci interface--; 2050141cc406Sopenharmony_ci 2051141cc406Sopenharmony_ci if (!found) 2052141cc406Sopenharmony_ci { 2053141cc406Sopenharmony_ci DBG (5, 2054141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x at %03d:%03d: no suitable interfaces\n", __func__, 2055141cc406Sopenharmony_ci vid, pid, busno, address); 2056141cc406Sopenharmony_ci continue; 2057141cc406Sopenharmony_ci } 2058141cc406Sopenharmony_ci 2059141cc406Sopenharmony_ci memset (&device, 0, sizeof (device)); 2060141cc406Sopenharmony_ci device.lu_device = libusb_ref_device(dev); 2061141cc406Sopenharmony_ci snprintf (devname, sizeof (devname), "libusb:%03d:%03d", 2062141cc406Sopenharmony_ci busno, address); 2063141cc406Sopenharmony_ci device.devname = strdup (devname); 2064141cc406Sopenharmony_ci if (!device.devname) 2065141cc406Sopenharmony_ci return; 2066141cc406Sopenharmony_ci device.vendor = vid; 2067141cc406Sopenharmony_ci device.product = pid; 2068141cc406Sopenharmony_ci device.method = sanei_usb_method_libusb; 2069141cc406Sopenharmony_ci device.interface_nr = interface; 2070141cc406Sopenharmony_ci device.alt_setting = 0; 2071141cc406Sopenharmony_ci DBG (4, 2072141cc406Sopenharmony_ci "%s: found libusb-1.0 device (0x%04x/0x%04x) interface " 2073141cc406Sopenharmony_ci "%d at %s\n", __func__, 2074141cc406Sopenharmony_ci vid, pid, interface, devname); 2075141cc406Sopenharmony_ci 2076141cc406Sopenharmony_ci store_device (device); 2077141cc406Sopenharmony_ci } 2078141cc406Sopenharmony_ci 2079141cc406Sopenharmony_ci libusb_free_device_list (devlist, 1); 2080141cc406Sopenharmony_ci 2081141cc406Sopenharmony_ci} 2082141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB */ 2083141cc406Sopenharmony_ci 2084141cc406Sopenharmony_ci#ifdef HAVE_USB_MANAGER 2085141cc406Sopenharmony_ci/** scan for devices using usb_manager 2086141cc406Sopenharmony_ci * Check for devices using usb_manager 2087141cc406Sopenharmony_ci */ 2088141cc406Sopenharmony_cistatic void libusb_scan_devices(void) 2089141cc406Sopenharmony_ci{ 2090141cc406Sopenharmony_ci device_list_type device; 2091141cc406Sopenharmony_ci SANE_Char devname[1024]; 2092141cc406Sopenharmony_ci usb_manager_device **devlist; 2093141cc406Sopenharmony_ci ssize_t ndev; 2094141cc406Sopenharmony_ci usb_manager_device *dev; 2095141cc406Sopenharmony_ci usb_manager_device_handle *hdl; 2096141cc406Sopenharmony_ci struct usb_manager_device_descriptor desc; 2097141cc406Sopenharmony_ci struct usb_manager_config_descriptor *config0; 2098141cc406Sopenharmony_ci unsigned short vid, pid; 2099141cc406Sopenharmony_ci unsigned char busno, address; 2100141cc406Sopenharmony_ci int config; 2101141cc406Sopenharmony_ci int interface; 2102141cc406Sopenharmony_ci int ret; 2103141cc406Sopenharmony_ci int i; 2104141cc406Sopenharmony_ci 2105141cc406Sopenharmony_ci DBG (4, "%s: Looking for usb_manager devices\n", __func__); 2106141cc406Sopenharmony_ci 2107141cc406Sopenharmony_ci ndev = usb_manager_get_device_list (sanei_usb_ctx, &devlist); 2108141cc406Sopenharmony_ci if (ndev < 0) 2109141cc406Sopenharmony_ci { 2110141cc406Sopenharmony_ci DBG (1, 2111141cc406Sopenharmony_ci "%s: failed to get usb_manager device list, error %d\n", __func__, 2112141cc406Sopenharmony_ci (int) ndev); 2113141cc406Sopenharmony_ci return; 2114141cc406Sopenharmony_ci } 2115141cc406Sopenharmony_ci 2116141cc406Sopenharmony_ci for (i = 0; i < ndev; i++) 2117141cc406Sopenharmony_ci { 2118141cc406Sopenharmony_ci SANE_Bool found = SANE_FALSE; 2119141cc406Sopenharmony_ci 2120141cc406Sopenharmony_ci dev = devlist[i]; 2121141cc406Sopenharmony_ci 2122141cc406Sopenharmony_ci busno = usb_manager_get_bus_number (dev); 2123141cc406Sopenharmony_ci address = usb_manager_get_device_address (dev); 2124141cc406Sopenharmony_ci 2125141cc406Sopenharmony_ci ret = usb_manager_get_device_descriptor (dev, &desc); 2126141cc406Sopenharmony_ci if (ret < 0) 2127141cc406Sopenharmony_ci { 2128141cc406Sopenharmony_ci DBG (1, 2129141cc406Sopenharmony_ci "%s: could not get device descriptor for device at %03d:%03d (err %d)\n", __func__, 2130141cc406Sopenharmony_ci busno, address, ret); 2131141cc406Sopenharmony_ci continue; 2132141cc406Sopenharmony_ci } 2133141cc406Sopenharmony_ci 2134141cc406Sopenharmony_ci vid = desc.idVendor; 2135141cc406Sopenharmony_ci pid = desc.idProduct; 2136141cc406Sopenharmony_ci 2137141cc406Sopenharmony_ci if ((vid == 0) || (pid == 0)) 2138141cc406Sopenharmony_ci { 2139141cc406Sopenharmony_ci DBG (5, 2140141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x at %03d:%03d looks like a root hub\n", __func__, 2141141cc406Sopenharmony_ci vid, pid, busno, address); 2142141cc406Sopenharmony_ci continue; 2143141cc406Sopenharmony_ci } 2144141cc406Sopenharmony_ci 2145141cc406Sopenharmony_ci ret = usb_manager_open (dev, &hdl); 2146141cc406Sopenharmony_ci if (ret < 0) 2147141cc406Sopenharmony_ci { 2148141cc406Sopenharmony_ci DBG (1, 2149141cc406Sopenharmony_ci "%s: skipping device 0x%04x/0x%04x at %03d:%03d: cannot open: %s\n", __func__, 2150141cc406Sopenharmony_ci vid, pid, busno, address, sanei_usb_manager_strerror (ret)); 2151141cc406Sopenharmony_ci 2152141cc406Sopenharmony_ci continue; 2153141cc406Sopenharmony_ci } 2154141cc406Sopenharmony_ci 2155141cc406Sopenharmony_ci ret = usb_manager_get_configuration (hdl, &config); 2156141cc406Sopenharmony_ci 2157141cc406Sopenharmony_ci usb_manager_close (hdl); 2158141cc406Sopenharmony_ci 2159141cc406Sopenharmony_ci if (ret < 0) 2160141cc406Sopenharmony_ci { 2161141cc406Sopenharmony_ci DBG (1, 2162141cc406Sopenharmony_ci "%s: could not get configuration for device 0x%04x/0x%04x at %03d:%03d (err %d)\n", __func__, 2163141cc406Sopenharmony_ci vid, pid, busno, address, ret); 2164141cc406Sopenharmony_ci continue; 2165141cc406Sopenharmony_ci } 2166141cc406Sopenharmony_ci 2167141cc406Sopenharmony_ci#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES) 2168141cc406Sopenharmony_ci if (config == 0) 2169141cc406Sopenharmony_ci { 2170141cc406Sopenharmony_ci DBG (1, 2171141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x at %03d:%03d is not configured\n", __func__, 2172141cc406Sopenharmony_ci vid, pid, busno, address); 2173141cc406Sopenharmony_ci continue; 2174141cc406Sopenharmony_ci } 2175141cc406Sopenharmony_ci#endif 2176141cc406Sopenharmony_ci 2177141cc406Sopenharmony_ci ret = usb_manager_get_config_descriptor (dev, 0, &config0); 2178141cc406Sopenharmony_ci if (ret < 0) 2179141cc406Sopenharmony_ci { 2180141cc406Sopenharmony_ci DBG (1, 2181141cc406Sopenharmony_ci "%s: could not get config[0] descriptor for device 0x%04x/0x%04x at %03d:%03d (err %d)\n", __func__, 2182141cc406Sopenharmony_ci vid, pid, busno, address, ret); 2183141cc406Sopenharmony_ci continue; 2184141cc406Sopenharmony_ci } 2185141cc406Sopenharmony_ci 2186141cc406Sopenharmony_ci for (interface = 0; (interface < config0->bNumInterfaces) && !found; interface++) 2187141cc406Sopenharmony_ci { 2188141cc406Sopenharmony_ci switch (desc.bDeviceClass) 2189141cc406Sopenharmony_ci { 2190141cc406Sopenharmony_ci case USB_MANAGER_CLASS_VENDOR_SPEC: 2191141cc406Sopenharmony_ci found = SANE_TRUE; 2192141cc406Sopenharmony_ci break; 2193141cc406Sopenharmony_ci 2194141cc406Sopenharmony_ci case USB_MANAGER_CLASS_PER_INTERFACE: 2195141cc406Sopenharmony_ci if ((config0->interface[interface].num_altsetting == 0) 2196141cc406Sopenharmony_ci || !config0->interface[interface].altsetting) 2197141cc406Sopenharmony_ci { 2198141cc406Sopenharmony_ci DBG (1, "%s: device 0x%04x/0x%04x doesn't " 2199141cc406Sopenharmony_ci "have an altsetting for interface %d\n", __func__, 2200141cc406Sopenharmony_ci vid, pid, interface); 2201141cc406Sopenharmony_ci continue; 2202141cc406Sopenharmony_ci } 2203141cc406Sopenharmony_ci 2204141cc406Sopenharmony_ci switch (config0->interface[interface].altsetting[0].bInterfaceClass) 2205141cc406Sopenharmony_ci { 2206141cc406Sopenharmony_ci case USB_MANAGER_CLASS_VENDOR_SPEC: 2207141cc406Sopenharmony_ci case USB_MANAGER_CLASS_PER_INTERFACE: 2208141cc406Sopenharmony_ci case USB_MANAGER_CLASS_PTP: 2209141cc406Sopenharmony_ci case 16: /* data? */ 2210141cc406Sopenharmony_ci found = SANE_TRUE; 2211141cc406Sopenharmony_ci break; 2212141cc406Sopenharmony_ci } 2213141cc406Sopenharmony_ci break; 2214141cc406Sopenharmony_ci } 2215141cc406Sopenharmony_ci 2216141cc406Sopenharmony_ci if (!found) 2217141cc406Sopenharmony_ci DBG (5, 2218141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x, interface %d " 2219141cc406Sopenharmony_ci "doesn't look like a scanner (%d/%d)\n", __func__, 2220141cc406Sopenharmony_ci vid, pid, interface, desc.bDeviceClass, 2221141cc406Sopenharmony_ci (config0->interface[interface].num_altsetting != 0) 2222141cc406Sopenharmony_ci ? config0->interface[interface].altsetting[0].bInterfaceClass : -1); 2223141cc406Sopenharmony_ci } 2224141cc406Sopenharmony_ci 2225141cc406Sopenharmony_ci usb_manager_free_config_descriptor (config0); 2226141cc406Sopenharmony_ci 2227141cc406Sopenharmony_ci interface--; 2228141cc406Sopenharmony_ci 2229141cc406Sopenharmony_ci if (!found) 2230141cc406Sopenharmony_ci { 2231141cc406Sopenharmony_ci DBG (5, 2232141cc406Sopenharmony_ci "%s: device 0x%04x/0x%04x at %03d:%03d: no suitable interfaces\n", __func__, 2233141cc406Sopenharmony_ci vid, pid, busno, address); 2234141cc406Sopenharmony_ci continue; 2235141cc406Sopenharmony_ci } 2236141cc406Sopenharmony_ci 2237141cc406Sopenharmony_ci memset (&device, 0, sizeof (device)); 2238141cc406Sopenharmony_ci device.usb_manager_device = usb_manager_ref_device(dev); 2239141cc406Sopenharmony_ci snprintf (devname, sizeof (devname), "libusb:%03d:%03d", 2240141cc406Sopenharmony_ci busno, address); 2241141cc406Sopenharmony_ci device.devname = strdup (devname); 2242141cc406Sopenharmony_ci if (!device.devname) 2243141cc406Sopenharmony_ci return; 2244141cc406Sopenharmony_ci device.vendor = vid; 2245141cc406Sopenharmony_ci device.product = pid; 2246141cc406Sopenharmony_ci device.method = sanei_usb_method_libusb; 2247141cc406Sopenharmony_ci device.interface_nr = interface; 2248141cc406Sopenharmony_ci device.alt_setting = 0; 2249141cc406Sopenharmony_ci DBG (4, 2250141cc406Sopenharmony_ci "%s: found usb_manager device (0x%04x/0x%04x) interface " 2251141cc406Sopenharmony_ci "%d at %s\n", __func__, 2252141cc406Sopenharmony_ci vid, pid, interface, devname); 2253141cc406Sopenharmony_ci 2254141cc406Sopenharmony_ci store_device (device); 2255141cc406Sopenharmony_ci } 2256141cc406Sopenharmony_ci 2257141cc406Sopenharmony_ci usb_manager_free_device_list (devlist, 1); 2258141cc406Sopenharmony_ci 2259141cc406Sopenharmony_ci} 2260141cc406Sopenharmony_ci#endif /* HAVE_USB_MANAGER */ 2261141cc406Sopenharmony_ci 2262141cc406Sopenharmony_civoid 2263141cc406Sopenharmony_cisanei_usb_scan_devices (void) 2264141cc406Sopenharmony_ci{ 2265141cc406Sopenharmony_ci int count; 2266141cc406Sopenharmony_ci int i; 2267141cc406Sopenharmony_ci 2268141cc406Sopenharmony_ci /* check USB has been initialized first */ 2269141cc406Sopenharmony_ci if(initialized==0) 2270141cc406Sopenharmony_ci { 2271141cc406Sopenharmony_ci DBG (1, "%s: sanei_usb is not initialized!\n", __func__); 2272141cc406Sopenharmony_ci return; 2273141cc406Sopenharmony_ci } 2274141cc406Sopenharmony_ci 2275141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 2276141cc406Sopenharmony_ci { 2277141cc406Sopenharmony_ci // device added in sanei_usb_testing_init() 2278141cc406Sopenharmony_ci return; 2279141cc406Sopenharmony_ci } 2280141cc406Sopenharmony_ci /* we mark all already detected devices as missing */ 2281141cc406Sopenharmony_ci /* each scan method will reset this value to 0 (not missing) 2282141cc406Sopenharmony_ci * when storing the device */ 2283141cc406Sopenharmony_ci DBG (4, "%s: marking existing devices\n", __func__); 2284141cc406Sopenharmony_ci for (i = 0; i < device_number; i++) 2285141cc406Sopenharmony_ci { 2286141cc406Sopenharmony_ci devices[i].missing++; 2287141cc406Sopenharmony_ci } 2288141cc406Sopenharmony_ci 2289141cc406Sopenharmony_ci /* Check for devices using the kernel scanner driver */ 2290141cc406Sopenharmony_ci#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) 2291141cc406Sopenharmony_ci kernel_scan_devices(); 2292141cc406Sopenharmony_ci#endif 2293141cc406Sopenharmony_ci 2294141cc406Sopenharmony_ci#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) || defined(HAVE_USB_MANAGER) 2295141cc406Sopenharmony_ci /* Check for devices using libusb (old or new)*/ 2296141cc406Sopenharmony_ci libusb_scan_devices(); 2297141cc406Sopenharmony_ci#endif 2298141cc406Sopenharmony_ci 2299141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 2300141cc406Sopenharmony_ci /* Check for devices using OS/2 USBCALLS Interface */ 2301141cc406Sopenharmony_ci usbcall_scan_devices(); 2302141cc406Sopenharmony_ci#endif 2303141cc406Sopenharmony_ci 2304141cc406Sopenharmony_ci /* display found devices */ 2305141cc406Sopenharmony_ci if (debug_level > 5) 2306141cc406Sopenharmony_ci { 2307141cc406Sopenharmony_ci count=0; 2308141cc406Sopenharmony_ci for (i = 0; i < device_number; i++) 2309141cc406Sopenharmony_ci { 2310141cc406Sopenharmony_ci if(!devices[i].missing) 2311141cc406Sopenharmony_ci { 2312141cc406Sopenharmony_ci count++; 2313141cc406Sopenharmony_ci DBG (6, "%s: device %02d is %s\n", __func__, i, devices[i].devname); 2314141cc406Sopenharmony_ci } 2315141cc406Sopenharmony_ci } 2316141cc406Sopenharmony_ci DBG (5, "%s: found %d devices\n", __func__, count); 2317141cc406Sopenharmony_ci } 2318141cc406Sopenharmony_ci} 2319141cc406Sopenharmony_ci 2320141cc406Sopenharmony_ci 2321141cc406Sopenharmony_ci 2322141cc406Sopenharmony_ci/* This logically belongs to sanei_config.c but not every backend that 2323141cc406Sopenharmony_ci uses sanei_config() wants to depend on sanei_usb. */ 2324141cc406Sopenharmony_civoid 2325141cc406Sopenharmony_cisanei_usb_attach_matching_devices (const char *name, 2326141cc406Sopenharmony_ci SANE_Status (*attach) (const char *dev)) 2327141cc406Sopenharmony_ci{ 2328141cc406Sopenharmony_ci char *vendor, *product; 2329141cc406Sopenharmony_ci 2330141cc406Sopenharmony_ci if (strncmp (name, "usb", 3) == 0) 2331141cc406Sopenharmony_ci { 2332141cc406Sopenharmony_ci SANE_Word vendorID = 0, productID = 0; 2333141cc406Sopenharmony_ci 2334141cc406Sopenharmony_ci name += 3; 2335141cc406Sopenharmony_ci 2336141cc406Sopenharmony_ci name = sanei_config_skip_whitespace (name); 2337141cc406Sopenharmony_ci if (*name) 2338141cc406Sopenharmony_ci { 2339141cc406Sopenharmony_ci name = sanei_config_get_string (name, &vendor); 2340141cc406Sopenharmony_ci if (vendor) 2341141cc406Sopenharmony_ci { 2342141cc406Sopenharmony_ci vendorID = strtol (vendor, 0, 0); 2343141cc406Sopenharmony_ci free (vendor); 2344141cc406Sopenharmony_ci } 2345141cc406Sopenharmony_ci name = sanei_config_skip_whitespace (name); 2346141cc406Sopenharmony_ci } 2347141cc406Sopenharmony_ci 2348141cc406Sopenharmony_ci name = sanei_config_skip_whitespace (name); 2349141cc406Sopenharmony_ci if (*name) 2350141cc406Sopenharmony_ci { 2351141cc406Sopenharmony_ci name = sanei_config_get_string (name, &product); 2352141cc406Sopenharmony_ci if (product) 2353141cc406Sopenharmony_ci { 2354141cc406Sopenharmony_ci productID = strtol (product, 0, 0); 2355141cc406Sopenharmony_ci free (product); 2356141cc406Sopenharmony_ci } 2357141cc406Sopenharmony_ci } 2358141cc406Sopenharmony_ci sanei_usb_find_devices (vendorID, productID, attach); 2359141cc406Sopenharmony_ci } 2360141cc406Sopenharmony_ci else 2361141cc406Sopenharmony_ci (*attach) (name); 2362141cc406Sopenharmony_ci} 2363141cc406Sopenharmony_ci 2364141cc406Sopenharmony_ciSANE_Status 2365141cc406Sopenharmony_cisanei_usb_get_vendor_product_byname (SANE_String_Const devname, 2366141cc406Sopenharmony_ci SANE_Word * vendor, SANE_Word * product) 2367141cc406Sopenharmony_ci{ 2368141cc406Sopenharmony_ci int i; 2369141cc406Sopenharmony_ci SANE_Bool found = SANE_FALSE; 2370141cc406Sopenharmony_ci 2371141cc406Sopenharmony_ci for (i = 0; i < device_number && devices[i].devname; i++) 2372141cc406Sopenharmony_ci { 2373141cc406Sopenharmony_ci if (!devices[i].missing && strcmp (devices[i].devname, devname) == 0) 2374141cc406Sopenharmony_ci { 2375141cc406Sopenharmony_ci found = SANE_TRUE; 2376141cc406Sopenharmony_ci break; 2377141cc406Sopenharmony_ci } 2378141cc406Sopenharmony_ci } 2379141cc406Sopenharmony_ci 2380141cc406Sopenharmony_ci if (!found) 2381141cc406Sopenharmony_ci { 2382141cc406Sopenharmony_ci DBG (1, "sanei_usb_get_vendor_product_byname: can't find device `%s' in list\n", devname); 2383141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2384141cc406Sopenharmony_ci } 2385141cc406Sopenharmony_ci 2386141cc406Sopenharmony_ci if ((devices[i].vendor == 0) && (devices[i].product == 0)) 2387141cc406Sopenharmony_ci { 2388141cc406Sopenharmony_ci DBG (1, "sanei_usb_get_vendor_product_byname: not support for this method\n"); 2389141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 2390141cc406Sopenharmony_ci } 2391141cc406Sopenharmony_ci 2392141cc406Sopenharmony_ci if (vendor) 2393141cc406Sopenharmony_ci *vendor = devices[i].vendor; 2394141cc406Sopenharmony_ci 2395141cc406Sopenharmony_ci if (product) 2396141cc406Sopenharmony_ci *product = devices[i].product; 2397141cc406Sopenharmony_ci 2398141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2399141cc406Sopenharmony_ci} 2400141cc406Sopenharmony_ci 2401141cc406Sopenharmony_ciSANE_Status 2402141cc406Sopenharmony_cisanei_usb_get_vendor_product (SANE_Int dn, SANE_Word * vendor, 2403141cc406Sopenharmony_ci SANE_Word * product) 2404141cc406Sopenharmony_ci{ 2405141cc406Sopenharmony_ci SANE_Word vendorID = 0; 2406141cc406Sopenharmony_ci SANE_Word productID = 0; 2407141cc406Sopenharmony_ci 2408141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 2409141cc406Sopenharmony_ci { 2410141cc406Sopenharmony_ci DBG (1, "sanei_usb_get_vendor_product: dn >= device number || dn < 0\n"); 2411141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2412141cc406Sopenharmony_ci } 2413141cc406Sopenharmony_ci if (devices[dn].missing >= 1) 2414141cc406Sopenharmony_ci { 2415141cc406Sopenharmony_ci DBG (1, "sanei_usb_get_vendor_product: dn=%d is missing!\n",dn); 2416141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2417141cc406Sopenharmony_ci } 2418141cc406Sopenharmony_ci 2419141cc406Sopenharmony_ci /* kernel, usbcal and libusb methods store these when device scanning 2420141cc406Sopenharmony_ci * is done, so we can use them directly */ 2421141cc406Sopenharmony_ci vendorID = devices[dn].vendor; 2422141cc406Sopenharmony_ci productID = devices[dn].product; 2423141cc406Sopenharmony_ci 2424141cc406Sopenharmony_ci if (vendor) 2425141cc406Sopenharmony_ci *vendor = vendorID; 2426141cc406Sopenharmony_ci if (product) 2427141cc406Sopenharmony_ci *product = productID; 2428141cc406Sopenharmony_ci 2429141cc406Sopenharmony_ci if (!vendorID || !productID) 2430141cc406Sopenharmony_ci { 2431141cc406Sopenharmony_ci DBG (3, "sanei_usb_get_vendor_product: device %d: Your OS doesn't " 2432141cc406Sopenharmony_ci "seem to support detection of vendor+product ids\n", dn); 2433141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 2434141cc406Sopenharmony_ci } 2435141cc406Sopenharmony_ci else 2436141cc406Sopenharmony_ci { 2437141cc406Sopenharmony_ci DBG (3, "sanei_usb_get_vendor_product: device %d: vendorID: 0x%04x, " 2438141cc406Sopenharmony_ci "productID: 0x%04x\n", dn, vendorID, productID); 2439141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2440141cc406Sopenharmony_ci } 2441141cc406Sopenharmony_ci} 2442141cc406Sopenharmony_ci 2443141cc406Sopenharmony_ciSANE_Status 2444141cc406Sopenharmony_cisanei_usb_find_devices (SANE_Int vendor, SANE_Int product, 2445141cc406Sopenharmony_ci SANE_Status (*attach) (SANE_String_Const dev)) 2446141cc406Sopenharmony_ci{ 2447141cc406Sopenharmony_ci SANE_Int dn = 0; 2448141cc406Sopenharmony_ci 2449141cc406Sopenharmony_ci DBG (3, 2450141cc406Sopenharmony_ci "sanei_usb_find_devices: vendor=0x%04x, product=0x%04x\n", 2451141cc406Sopenharmony_ci vendor, product); 2452141cc406Sopenharmony_ci 2453141cc406Sopenharmony_ci while (devices[dn].devname && dn < device_number) 2454141cc406Sopenharmony_ci { 2455141cc406Sopenharmony_ci if (devices[dn].vendor == vendor 2456141cc406Sopenharmony_ci && devices[dn].product == product 2457141cc406Sopenharmony_ci && !devices[dn].missing 2458141cc406Sopenharmony_ci && attach) 2459141cc406Sopenharmony_ci attach (devices[dn].devname); 2460141cc406Sopenharmony_ci dn++; 2461141cc406Sopenharmony_ci } 2462141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2463141cc406Sopenharmony_ci} 2464141cc406Sopenharmony_ci 2465141cc406Sopenharmony_civoid 2466141cc406Sopenharmony_cisanei_usb_set_endpoint (SANE_Int dn, SANE_Int ep_type, SANE_Int ep) 2467141cc406Sopenharmony_ci{ 2468141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 2469141cc406Sopenharmony_ci { 2470141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_endpoint: dn >= device number || dn < 0\n"); 2471141cc406Sopenharmony_ci return; 2472141cc406Sopenharmony_ci } 2473141cc406Sopenharmony_ci 2474141cc406Sopenharmony_ci DBG (5, "sanei_usb_set_endpoint: Setting endpoint of type 0x%02x to 0x%02x\n", ep_type, ep); 2475141cc406Sopenharmony_ci switch (ep_type) 2476141cc406Sopenharmony_ci { 2477141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_BULK: 2478141cc406Sopenharmony_ci devices[dn].bulk_in_ep = ep; 2479141cc406Sopenharmony_ci break; 2480141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_BULK: 2481141cc406Sopenharmony_ci devices[dn].bulk_out_ep = ep; 2482141cc406Sopenharmony_ci break; 2483141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_ISOCHRONOUS: 2484141cc406Sopenharmony_ci devices[dn].iso_in_ep = ep; 2485141cc406Sopenharmony_ci break; 2486141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_ISOCHRONOUS: 2487141cc406Sopenharmony_ci devices[dn].iso_out_ep = ep; 2488141cc406Sopenharmony_ci break; 2489141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_INTERRUPT: 2490141cc406Sopenharmony_ci devices[dn].int_in_ep = ep; 2491141cc406Sopenharmony_ci break; 2492141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_INTERRUPT: 2493141cc406Sopenharmony_ci devices[dn].int_out_ep = ep; 2494141cc406Sopenharmony_ci break; 2495141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_CONTROL: 2496141cc406Sopenharmony_ci devices[dn].control_in_ep = ep; 2497141cc406Sopenharmony_ci break; 2498141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_CONTROL: 2499141cc406Sopenharmony_ci devices[dn].control_out_ep = ep; 2500141cc406Sopenharmony_ci break; 2501141cc406Sopenharmony_ci } 2502141cc406Sopenharmony_ci} 2503141cc406Sopenharmony_ci 2504141cc406Sopenharmony_ci#if HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USBCALLS || WITH_USB_RECORD_REPLAY || HAVE_USB_MANAGER 2505141cc406Sopenharmony_cistatic const char* sanei_usb_transfer_type_desc(SANE_Int transfer_type) 2506141cc406Sopenharmony_ci{ 2507141cc406Sopenharmony_ci switch (transfer_type) 2508141cc406Sopenharmony_ci { 2509141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_INTERRUPT: return "interrupt"; 2510141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_BULK: return "bulk"; 2511141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_ISOCHRONOUS: return "isochronous"; 2512141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_CONTROL: return "control"; 2513141cc406Sopenharmony_ci } 2514141cc406Sopenharmony_ci return NULL; 2515141cc406Sopenharmony_ci} 2516141cc406Sopenharmony_ci 2517141cc406Sopenharmony_ci// Similar sanei_usb_set_endpoint, but ignores duplicate endpoints 2518141cc406Sopenharmony_cistatic void sanei_usb_add_endpoint(device_list_type* device, 2519141cc406Sopenharmony_ci SANE_Int transfer_type, 2520141cc406Sopenharmony_ci SANE_Int ep_address, 2521141cc406Sopenharmony_ci SANE_Int ep_direction) 2522141cc406Sopenharmony_ci{ 2523141cc406Sopenharmony_ci DBG(5, "%s: direction: %d, address: %d, transfer_type: %d\n", 2524141cc406Sopenharmony_ci __func__, ep_direction, ep_address, transfer_type); 2525141cc406Sopenharmony_ci 2526141cc406Sopenharmony_ci SANE_Int* ep_in = NULL; 2527141cc406Sopenharmony_ci SANE_Int* ep_out = NULL; 2528141cc406Sopenharmony_ci const char* transfer_type_msg = sanei_usb_transfer_type_desc(transfer_type); 2529141cc406Sopenharmony_ci 2530141cc406Sopenharmony_ci switch (transfer_type) 2531141cc406Sopenharmony_ci { 2532141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_INTERRUPT: 2533141cc406Sopenharmony_ci ep_in = &device->int_in_ep; 2534141cc406Sopenharmony_ci ep_out = &device->int_out_ep; 2535141cc406Sopenharmony_ci break; 2536141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_BULK: 2537141cc406Sopenharmony_ci ep_in = &device->bulk_in_ep; 2538141cc406Sopenharmony_ci ep_out = &device->bulk_out_ep; 2539141cc406Sopenharmony_ci break; 2540141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_ISOCHRONOUS: 2541141cc406Sopenharmony_ci ep_in = &device->iso_in_ep; 2542141cc406Sopenharmony_ci ep_out = &device->iso_out_ep; 2543141cc406Sopenharmony_ci break; 2544141cc406Sopenharmony_ci case USB_ENDPOINT_TYPE_CONTROL: 2545141cc406Sopenharmony_ci ep_in = &device->control_in_ep; 2546141cc406Sopenharmony_ci ep_out = &device->control_out_ep; 2547141cc406Sopenharmony_ci break; 2548141cc406Sopenharmony_ci } 2549141cc406Sopenharmony_ci 2550141cc406Sopenharmony_ci DBG(5, "%s: found %s-%s endpoint (address 0x%02x)\n", 2551141cc406Sopenharmony_ci __func__, transfer_type_msg, ep_direction ? "in" : "out", 2552141cc406Sopenharmony_ci ep_address); 2553141cc406Sopenharmony_ci 2554141cc406Sopenharmony_ci if (ep_direction) // in 2555141cc406Sopenharmony_ci { 2556141cc406Sopenharmony_ci if (*ep_in) 2557141cc406Sopenharmony_ci DBG(3, "%s: we already have a %s-in endpoint " 2558141cc406Sopenharmony_ci "(address: 0x%02x), ignoring the new one\n", 2559141cc406Sopenharmony_ci __func__, transfer_type_msg, *ep_in); 2560141cc406Sopenharmony_ci else 2561141cc406Sopenharmony_ci *ep_in = ep_address; 2562141cc406Sopenharmony_ci } 2563141cc406Sopenharmony_ci else 2564141cc406Sopenharmony_ci { 2565141cc406Sopenharmony_ci if (*ep_out) 2566141cc406Sopenharmony_ci DBG(3, "%s: we already have a %s-out endpoint " 2567141cc406Sopenharmony_ci "(address: 0x%02x), ignoring the new one\n", 2568141cc406Sopenharmony_ci __func__, transfer_type_msg, *ep_out); 2569141cc406Sopenharmony_ci else 2570141cc406Sopenharmony_ci *ep_out = ep_address; 2571141cc406Sopenharmony_ci } 2572141cc406Sopenharmony_ci} 2573141cc406Sopenharmony_ci#endif // HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USBCALLS || HAVE_USB_MANAGER 2574141cc406Sopenharmony_ci 2575141cc406Sopenharmony_ciSANE_Int 2576141cc406Sopenharmony_cisanei_usb_get_endpoint (SANE_Int dn, SANE_Int ep_type) 2577141cc406Sopenharmony_ci{ 2578141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 2579141cc406Sopenharmony_ci { 2580141cc406Sopenharmony_ci DBG (1, "sanei_usb_get_endpoint: dn >= device number || dn < 0\n"); 2581141cc406Sopenharmony_ci return 0; 2582141cc406Sopenharmony_ci } 2583141cc406Sopenharmony_ci 2584141cc406Sopenharmony_ci switch (ep_type) 2585141cc406Sopenharmony_ci { 2586141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_BULK: 2587141cc406Sopenharmony_ci return devices[dn].bulk_in_ep; 2588141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_BULK: 2589141cc406Sopenharmony_ci return devices[dn].bulk_out_ep; 2590141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_ISOCHRONOUS: 2591141cc406Sopenharmony_ci return devices[dn].iso_in_ep; 2592141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_ISOCHRONOUS: 2593141cc406Sopenharmony_ci return devices[dn].iso_out_ep; 2594141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_INTERRUPT: 2595141cc406Sopenharmony_ci return devices[dn].int_in_ep; 2596141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_INTERRUPT: 2597141cc406Sopenharmony_ci return devices[dn].int_out_ep; 2598141cc406Sopenharmony_ci case USB_DIR_IN|USB_ENDPOINT_TYPE_CONTROL: 2599141cc406Sopenharmony_ci return devices[dn].control_in_ep; 2600141cc406Sopenharmony_ci case USB_DIR_OUT|USB_ENDPOINT_TYPE_CONTROL: 2601141cc406Sopenharmony_ci return devices[dn].control_out_ep; 2602141cc406Sopenharmony_ci default: 2603141cc406Sopenharmony_ci return 0; 2604141cc406Sopenharmony_ci } 2605141cc406Sopenharmony_ci} 2606141cc406Sopenharmony_ci 2607141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 2608141cc406Sopenharmony_cistatic void sanei_xml_indent_child(xmlNode* parent, unsigned indent_count) 2609141cc406Sopenharmony_ci{ 2610141cc406Sopenharmony_ci indent_count *= 4; 2611141cc406Sopenharmony_ci 2612141cc406Sopenharmony_ci xmlChar* indent_str = malloc(indent_count + 2); 2613141cc406Sopenharmony_ci indent_str[0] = '\n'; 2614141cc406Sopenharmony_ci memset(indent_str + 1, ' ', indent_count); 2615141cc406Sopenharmony_ci indent_str[indent_count + 1] = '\0'; 2616141cc406Sopenharmony_ci 2617141cc406Sopenharmony_ci xmlAddChild(parent, xmlNewText(indent_str)); 2618141cc406Sopenharmony_ci free(indent_str); 2619141cc406Sopenharmony_ci} 2620141cc406Sopenharmony_ci 2621141cc406Sopenharmony_cistatic void sanei_usb_record_open(SANE_Int dn) 2622141cc406Sopenharmony_ci{ 2623141cc406Sopenharmony_ci if (testing_already_opened) 2624141cc406Sopenharmony_ci return; 2625141cc406Sopenharmony_ci 2626141cc406Sopenharmony_ci xmlNode* e_root = xmlNewNode(NULL, (const xmlChar*) "device_capture"); 2627141cc406Sopenharmony_ci xmlDocSetRootElement(testing_xml_doc, e_root); 2628141cc406Sopenharmony_ci xmlNewProp(e_root, (const xmlChar*)"backend", (const xmlChar*) testing_record_backend); 2629141cc406Sopenharmony_ci 2630141cc406Sopenharmony_ci sanei_xml_indent_child(e_root, 1); 2631141cc406Sopenharmony_ci xmlNode* e_description = xmlNewChild(e_root, NULL, (const xmlChar*) "description", NULL); 2632141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_description, "id_vendor", devices[dn].vendor); 2633141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_description, "id_product", devices[dn].product); 2634141cc406Sopenharmony_ci 2635141cc406Sopenharmony_ci sanei_xml_indent_child(e_description, 2); 2636141cc406Sopenharmony_ci xmlNode* e_configurations = xmlNewChild(e_description, NULL, 2637141cc406Sopenharmony_ci (const xmlChar*) "configurations", NULL); 2638141cc406Sopenharmony_ci 2639141cc406Sopenharmony_ci sanei_xml_indent_child(e_configurations, 3); 2640141cc406Sopenharmony_ci xmlNode* e_configuration = xmlNewChild(e_configurations, NULL, 2641141cc406Sopenharmony_ci (const xmlChar*) "configuration", NULL); 2642141cc406Sopenharmony_ci sanei_xml_set_uint_attr(e_configuration, "number", 1); 2643141cc406Sopenharmony_ci 2644141cc406Sopenharmony_ci sanei_xml_indent_child(e_configuration, 4); 2645141cc406Sopenharmony_ci xmlNode* e_interface = xmlNewChild(e_configuration, NULL, (const xmlChar*) "interface", NULL); 2646141cc406Sopenharmony_ci sanei_xml_set_uint_attr(e_interface, "number", devices[dn].interface_nr); 2647141cc406Sopenharmony_ci 2648141cc406Sopenharmony_ci struct endpoint_data_desc { 2649141cc406Sopenharmony_ci const char* transfer_type; 2650141cc406Sopenharmony_ci const char* direction; 2651141cc406Sopenharmony_ci SANE_Int ep_address; 2652141cc406Sopenharmony_ci }; 2653141cc406Sopenharmony_ci 2654141cc406Sopenharmony_ci struct endpoint_data_desc endpoints[8] = 2655141cc406Sopenharmony_ci { 2656141cc406Sopenharmony_ci { "BULK", "IN", devices[dn].bulk_in_ep }, 2657141cc406Sopenharmony_ci { "BULK", "OUT", devices[dn].bulk_out_ep }, 2658141cc406Sopenharmony_ci { "ISOCHRONOUS", "IN", devices[dn].iso_in_ep }, 2659141cc406Sopenharmony_ci { "ISOCHRONOUS", "OUT", devices[dn].iso_out_ep }, 2660141cc406Sopenharmony_ci { "INTERRUPT", "IN", devices[dn].int_in_ep }, 2661141cc406Sopenharmony_ci { "INTERRUPT", "OUT", devices[dn].int_out_ep }, 2662141cc406Sopenharmony_ci { "CONTROL", "IN", devices[dn].control_in_ep }, 2663141cc406Sopenharmony_ci { "CONTROL", "OUT", devices[dn].control_out_ep } 2664141cc406Sopenharmony_ci }; 2665141cc406Sopenharmony_ci 2666141cc406Sopenharmony_ci for (int i = 0; i < 8; ++i) 2667141cc406Sopenharmony_ci { 2668141cc406Sopenharmony_ci if (endpoints[i].ep_address) 2669141cc406Sopenharmony_ci { 2670141cc406Sopenharmony_ci sanei_xml_indent_child(e_interface, 5); 2671141cc406Sopenharmony_ci xmlNode* e_endpoint = xmlNewChild(e_interface, NULL, (const xmlChar*)"endpoint", NULL); 2672141cc406Sopenharmony_ci xmlNewProp(e_endpoint, (const xmlChar*)"transfer_type", 2673141cc406Sopenharmony_ci (const xmlChar*) endpoints[i].transfer_type); 2674141cc406Sopenharmony_ci sanei_xml_set_uint_attr(e_endpoint, "number", endpoints[i].ep_address & 0x0f); 2675141cc406Sopenharmony_ci xmlNewProp(e_endpoint, (const xmlChar*)"direction", 2676141cc406Sopenharmony_ci (const xmlChar*) endpoints[i].direction); 2677141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_endpoint, "address", endpoints[i].ep_address); 2678141cc406Sopenharmony_ci } 2679141cc406Sopenharmony_ci } 2680141cc406Sopenharmony_ci sanei_xml_indent_child(e_interface, 4); 2681141cc406Sopenharmony_ci sanei_xml_indent_child(e_configuration, 3); 2682141cc406Sopenharmony_ci sanei_xml_indent_child(e_configurations, 2); 2683141cc406Sopenharmony_ci sanei_xml_indent_child(e_description, 1); 2684141cc406Sopenharmony_ci 2685141cc406Sopenharmony_ci sanei_xml_indent_child(e_root, 1); 2686141cc406Sopenharmony_ci xmlNode* e_transactions = xmlNewChild(e_root, NULL, (const xmlChar*)"transactions", NULL); 2687141cc406Sopenharmony_ci 2688141cc406Sopenharmony_ci // add an empty node so that we have something to append to 2689141cc406Sopenharmony_ci testing_append_commands_node = xmlAddChild(e_transactions, xmlNewText((const xmlChar*)"")); 2690141cc406Sopenharmony_ci testing_already_opened = 1; 2691141cc406Sopenharmony_ci} 2692141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 2693141cc406Sopenharmony_ci 2694141cc406Sopenharmony_ciSANE_Status 2695141cc406Sopenharmony_cisanei_usb_open (SANE_String_Const devname, SANE_Int * dn) 2696141cc406Sopenharmony_ci{ 2697141cc406Sopenharmony_ci int devcount; 2698141cc406Sopenharmony_ci SANE_Bool found = SANE_FALSE; 2699141cc406Sopenharmony_ci 2700141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: trying to open device `%s'\n", devname); 2701141cc406Sopenharmony_ci if (!dn) 2702141cc406Sopenharmony_ci { 2703141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't open `%s': dn == NULL\n", devname); 2704141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2705141cc406Sopenharmony_ci } 2706141cc406Sopenharmony_ci 2707141cc406Sopenharmony_ci for (devcount = 0; 2708141cc406Sopenharmony_ci devcount < device_number && devices[devcount].devname != 0; 2709141cc406Sopenharmony_ci devcount++) 2710141cc406Sopenharmony_ci { 2711141cc406Sopenharmony_ci if (!devices[devcount].missing && strcmp (devices[devcount].devname, devname) == 0) 2712141cc406Sopenharmony_ci { 2713141cc406Sopenharmony_ci if (devices[devcount].open) 2714141cc406Sopenharmony_ci { 2715141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: device `%s' already open\n", devname); 2716141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2717141cc406Sopenharmony_ci } 2718141cc406Sopenharmony_ci found = SANE_TRUE; 2719141cc406Sopenharmony_ci break; 2720141cc406Sopenharmony_ci } 2721141cc406Sopenharmony_ci } 2722141cc406Sopenharmony_ci 2723141cc406Sopenharmony_ci if (!found) 2724141cc406Sopenharmony_ci { 2725141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't find device `%s' in list\n", devname); 2726141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2727141cc406Sopenharmony_ci } 2728141cc406Sopenharmony_ci 2729141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 2730141cc406Sopenharmony_ci { 2731141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: opening fake USB device\n"); 2732141cc406Sopenharmony_ci // the device configuration has been already filled in 2733141cc406Sopenharmony_ci // sanei_usb_testing_init() 2734141cc406Sopenharmony_ci } 2735141cc406Sopenharmony_ci else if (devices[devcount].method == sanei_usb_method_libusb) 2736141cc406Sopenharmony_ci { 2737141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 2738141cc406Sopenharmony_ci struct usb_device *dev; 2739141cc406Sopenharmony_ci struct usb_interface_descriptor *interface; 2740141cc406Sopenharmony_ci int result, num; 2741141cc406Sopenharmony_ci int c, i, a; 2742141cc406Sopenharmony_ci 2743141cc406Sopenharmony_ci devices[devcount].libusb_handle = 2744141cc406Sopenharmony_ci usb_open (devices[devcount].libusb_device); 2745141cc406Sopenharmony_ci if (!devices[devcount].libusb_handle) 2746141cc406Sopenharmony_ci { 2747141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2748141cc406Sopenharmony_ci 2749141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't open device `%s': %s\n", 2750141cc406Sopenharmony_ci devname, strerror (errno)); 2751141cc406Sopenharmony_ci if (errno == EPERM || errno == EACCES) 2752141cc406Sopenharmony_ci { 2753141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 2754141cc406Sopenharmony_ci "permissions\n"); 2755141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 2756141cc406Sopenharmony_ci } 2757141cc406Sopenharmony_ci else if (errno == EBUSY) 2758141cc406Sopenharmony_ci { 2759141cc406Sopenharmony_ci DBG (1, "Maybe the kernel scanner driver claims the " 2760141cc406Sopenharmony_ci "scanner's interface?\n"); 2761141cc406Sopenharmony_ci status = SANE_STATUS_DEVICE_BUSY; 2762141cc406Sopenharmony_ci } 2763141cc406Sopenharmony_ci return status; 2764141cc406Sopenharmony_ci } 2765141cc406Sopenharmony_ci 2766141cc406Sopenharmony_ci dev = usb_device (devices[devcount].libusb_handle); 2767141cc406Sopenharmony_ci 2768141cc406Sopenharmony_ci /* Set the configuration */ 2769141cc406Sopenharmony_ci if (!dev->config) 2770141cc406Sopenharmony_ci { 2771141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: device `%s' not configured?\n", devname); 2772141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2773141cc406Sopenharmony_ci } 2774141cc406Sopenharmony_ci if (dev->descriptor.bNumConfigurations > 1) 2775141cc406Sopenharmony_ci { 2776141cc406Sopenharmony_ci DBG (3, "sanei_usb_open: more than one " 2777141cc406Sopenharmony_ci "configuration (%d), choosing first config (%d)\n", 2778141cc406Sopenharmony_ci dev->descriptor.bNumConfigurations, 2779141cc406Sopenharmony_ci dev->config[0].bConfigurationValue); 2780141cc406Sopenharmony_ci 2781141cc406Sopenharmony_ci result = usb_set_configuration (devices[devcount].libusb_handle, 2782141cc406Sopenharmony_ci dev->config[0].bConfigurationValue); 2783141cc406Sopenharmony_ci if (result < 0) 2784141cc406Sopenharmony_ci { 2785141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2786141cc406Sopenharmony_ci 2787141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: libusb complained: %s\n", 2788141cc406Sopenharmony_ci usb_strerror ()); 2789141cc406Sopenharmony_ci if (errno == EPERM || errno == EACCES) 2790141cc406Sopenharmony_ci { 2791141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 2792141cc406Sopenharmony_ci "permissions\n"); 2793141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 2794141cc406Sopenharmony_ci } 2795141cc406Sopenharmony_ci else if (errno == EBUSY) 2796141cc406Sopenharmony_ci { 2797141cc406Sopenharmony_ci DBG (3, "Maybe the kernel scanner driver or usblp claims the " 2798141cc406Sopenharmony_ci "interface? Ignoring this error...\n"); 2799141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 2800141cc406Sopenharmony_ci } 2801141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2802141cc406Sopenharmony_ci { 2803141cc406Sopenharmony_ci usb_close (devices[devcount].libusb_handle); 2804141cc406Sopenharmony_ci return status; 2805141cc406Sopenharmony_ci } 2806141cc406Sopenharmony_ci } 2807141cc406Sopenharmony_ci } 2808141cc406Sopenharmony_ci 2809141cc406Sopenharmony_ci /* Claim the interface */ 2810141cc406Sopenharmony_ci result = usb_claim_interface (devices[devcount].libusb_handle, 2811141cc406Sopenharmony_ci devices[devcount].interface_nr); 2812141cc406Sopenharmony_ci if (result < 0) 2813141cc406Sopenharmony_ci { 2814141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2815141cc406Sopenharmony_ci 2816141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: libusb complained: %s\n", usb_strerror ()); 2817141cc406Sopenharmony_ci if (errno == EPERM || errno == EACCES) 2818141cc406Sopenharmony_ci { 2819141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 2820141cc406Sopenharmony_ci "permissions\n"); 2821141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 2822141cc406Sopenharmony_ci } 2823141cc406Sopenharmony_ci else if (errno == EBUSY) 2824141cc406Sopenharmony_ci { 2825141cc406Sopenharmony_ci DBG (1, "Maybe the kernel scanner driver claims the " 2826141cc406Sopenharmony_ci "scanner's interface?\n"); 2827141cc406Sopenharmony_ci status = SANE_STATUS_DEVICE_BUSY; 2828141cc406Sopenharmony_ci } 2829141cc406Sopenharmony_ci usb_close (devices[devcount].libusb_handle); 2830141cc406Sopenharmony_ci return status; 2831141cc406Sopenharmony_ci } 2832141cc406Sopenharmony_ci 2833141cc406Sopenharmony_ci /* Loop through all of the configurations */ 2834141cc406Sopenharmony_ci for (c = 0; c < dev->descriptor.bNumConfigurations; c++) 2835141cc406Sopenharmony_ci { 2836141cc406Sopenharmony_ci /* Loop through all of the interfaces */ 2837141cc406Sopenharmony_ci for (i = 0; i < dev->config[c].bNumInterfaces; i++) 2838141cc406Sopenharmony_ci { 2839141cc406Sopenharmony_ci /* Loop through all of the alternate settings */ 2840141cc406Sopenharmony_ci for (a = 0; a < dev->config[c].interface[i].num_altsetting; a++) 2841141cc406Sopenharmony_ci { 2842141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: configuration nr: %d\n", c); 2843141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: interface nr: %d\n", i); 2844141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: alt_setting nr: %d\n", a); 2845141cc406Sopenharmony_ci 2846141cc406Sopenharmony_ci /* Start by interfaces found in sanei_usb_init */ 2847141cc406Sopenharmony_ci if (c == 0 && i != devices[devcount].interface_nr) 2848141cc406Sopenharmony_ci { 2849141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: interface %d not detected as " 2850141cc406Sopenharmony_ci "a scanner by sanei_usb_init, ignoring.\n", i); 2851141cc406Sopenharmony_ci continue; 2852141cc406Sopenharmony_ci } 2853141cc406Sopenharmony_ci 2854141cc406Sopenharmony_ci interface = &dev->config[c].interface[i].altsetting[a]; 2855141cc406Sopenharmony_ci 2856141cc406Sopenharmony_ci /* Now we look for usable endpoints */ 2857141cc406Sopenharmony_ci for (num = 0; num < interface->bNumEndpoints; num++) 2858141cc406Sopenharmony_ci { 2859141cc406Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 2860141cc406Sopenharmony_ci int address, direction, transfer_type; 2861141cc406Sopenharmony_ci 2862141cc406Sopenharmony_ci endpoint = &interface->endpoint[num]; 2863141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: endpoint nr: %d\n", num); 2864141cc406Sopenharmony_ci transfer_type = 2865141cc406Sopenharmony_ci endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK; 2866141cc406Sopenharmony_ci direction = 2867141cc406Sopenharmony_ci endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK; 2868141cc406Sopenharmony_ci 2869141cc406Sopenharmony_ci sanei_usb_add_endpoint(&devices[devcount], transfer_type, 2870141cc406Sopenharmony_ci endpoint->bEndpointAddress, 2871141cc406Sopenharmony_ci direction); 2872141cc406Sopenharmony_ci } 2873141cc406Sopenharmony_ci } 2874141cc406Sopenharmony_ci } 2875141cc406Sopenharmony_ci } 2876141cc406Sopenharmony_ci 2877141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) /* libusb-1.0 */ 2878141cc406Sopenharmony_ci 2879141cc406Sopenharmony_ci int config; 2880141cc406Sopenharmony_ci libusb_device *dev; 2881141cc406Sopenharmony_ci struct libusb_device_descriptor desc; 2882141cc406Sopenharmony_ci struct libusb_config_descriptor *config0; 2883141cc406Sopenharmony_ci int result, num; 2884141cc406Sopenharmony_ci int c, i, a; 2885141cc406Sopenharmony_ci 2886141cc406Sopenharmony_ci dev = devices[devcount].lu_device; 2887141cc406Sopenharmony_ci 2888141cc406Sopenharmony_ci result = libusb_open (dev, &devices[devcount].lu_handle); 2889141cc406Sopenharmony_ci if (result < 0) 2890141cc406Sopenharmony_ci { 2891141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2892141cc406Sopenharmony_ci 2893141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't open device `%s': %s\n", 2894141cc406Sopenharmony_ci devname, sanei_libusb_strerror (result)); 2895141cc406Sopenharmony_ci if (result == LIBUSB_ERROR_ACCESS) 2896141cc406Sopenharmony_ci { 2897141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 2898141cc406Sopenharmony_ci "permissions\n"); 2899141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 2900141cc406Sopenharmony_ci } 2901141cc406Sopenharmony_ci else if (result == LIBUSB_ERROR_BUSY) 2902141cc406Sopenharmony_ci { 2903141cc406Sopenharmony_ci DBG (1, "Maybe the kernel scanner driver claims the " 2904141cc406Sopenharmony_ci "scanner's interface?\n"); 2905141cc406Sopenharmony_ci status = SANE_STATUS_DEVICE_BUSY; 2906141cc406Sopenharmony_ci } 2907141cc406Sopenharmony_ci else if (result == LIBUSB_ERROR_NO_MEM) 2908141cc406Sopenharmony_ci { 2909141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 2910141cc406Sopenharmony_ci } 2911141cc406Sopenharmony_ci return status; 2912141cc406Sopenharmony_ci } 2913141cc406Sopenharmony_ci 2914141cc406Sopenharmony_ci result = libusb_get_configuration (devices[devcount].lu_handle, &config); 2915141cc406Sopenharmony_ci if (result < 0) 2916141cc406Sopenharmony_ci { 2917141cc406Sopenharmony_ci DBG (1, 2918141cc406Sopenharmony_ci "sanei_usb_open: could not get configuration for device `%s' (err %d)\n", 2919141cc406Sopenharmony_ci devname, result); 2920141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2921141cc406Sopenharmony_ci } 2922141cc406Sopenharmony_ci 2923141cc406Sopenharmony_ci#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES) 2924141cc406Sopenharmony_ci if (config == 0) 2925141cc406Sopenharmony_ci { 2926141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: device `%s' not configured?\n", devname); 2927141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2928141cc406Sopenharmony_ci } 2929141cc406Sopenharmony_ci#endif 2930141cc406Sopenharmony_ci 2931141cc406Sopenharmony_ci result = libusb_get_device_descriptor (dev, &desc); 2932141cc406Sopenharmony_ci if (result < 0) 2933141cc406Sopenharmony_ci { 2934141cc406Sopenharmony_ci DBG (1, 2935141cc406Sopenharmony_ci "sanei_usb_open: could not get device descriptor for device `%s' (err %d)\n", 2936141cc406Sopenharmony_ci devname, result); 2937141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2938141cc406Sopenharmony_ci } 2939141cc406Sopenharmony_ci 2940141cc406Sopenharmony_ci result = libusb_get_config_descriptor (dev, 0, &config0); 2941141cc406Sopenharmony_ci if (result < 0) 2942141cc406Sopenharmony_ci { 2943141cc406Sopenharmony_ci DBG (1, 2944141cc406Sopenharmony_ci "sanei_usb_open: could not get config[0] descriptor for device `%s' (err %d)\n", 2945141cc406Sopenharmony_ci devname, result); 2946141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2947141cc406Sopenharmony_ci } 2948141cc406Sopenharmony_ci 2949141cc406Sopenharmony_ci /* Set the configuration */ 2950141cc406Sopenharmony_ci if (desc.bNumConfigurations > 1) 2951141cc406Sopenharmony_ci { 2952141cc406Sopenharmony_ci DBG (3, "sanei_usb_open: more than one " 2953141cc406Sopenharmony_ci "configuration (%d), choosing first config (%d)\n", 2954141cc406Sopenharmony_ci desc.bNumConfigurations, 2955141cc406Sopenharmony_ci config0->bConfigurationValue); 2956141cc406Sopenharmony_ci 2957141cc406Sopenharmony_ci result = 0; 2958141cc406Sopenharmony_ci if (config != config0->bConfigurationValue) 2959141cc406Sopenharmony_ci result = libusb_set_configuration (devices[devcount].lu_handle, 2960141cc406Sopenharmony_ci config0->bConfigurationValue); 2961141cc406Sopenharmony_ci 2962141cc406Sopenharmony_ci if (result < 0) 2963141cc406Sopenharmony_ci { 2964141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2965141cc406Sopenharmony_ci 2966141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: libusb complained: %s\n", 2967141cc406Sopenharmony_ci sanei_libusb_strerror (result)); 2968141cc406Sopenharmony_ci if (result == LIBUSB_ERROR_ACCESS) 2969141cc406Sopenharmony_ci { 2970141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 2971141cc406Sopenharmony_ci "permissions\n"); 2972141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 2973141cc406Sopenharmony_ci } 2974141cc406Sopenharmony_ci else if (result == LIBUSB_ERROR_BUSY) 2975141cc406Sopenharmony_ci { 2976141cc406Sopenharmony_ci DBG (3, "Maybe the kernel scanner driver or usblp claims " 2977141cc406Sopenharmony_ci "the interface? Ignoring this error...\n"); 2978141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 2979141cc406Sopenharmony_ci } 2980141cc406Sopenharmony_ci 2981141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2982141cc406Sopenharmony_ci { 2983141cc406Sopenharmony_ci libusb_close (devices[devcount].lu_handle); 2984141cc406Sopenharmony_ci libusb_free_config_descriptor (config0); 2985141cc406Sopenharmony_ci return status; 2986141cc406Sopenharmony_ci } 2987141cc406Sopenharmony_ci } 2988141cc406Sopenharmony_ci } 2989141cc406Sopenharmony_ci libusb_free_config_descriptor (config0); 2990141cc406Sopenharmony_ci 2991141cc406Sopenharmony_ci /* Claim the interface */ 2992141cc406Sopenharmony_ci result = libusb_claim_interface (devices[devcount].lu_handle, 2993141cc406Sopenharmony_ci devices[devcount].interface_nr); 2994141cc406Sopenharmony_ci if (result < 0) 2995141cc406Sopenharmony_ci { 2996141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 2997141cc406Sopenharmony_ci 2998141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: libusb complained: %s\n", 2999141cc406Sopenharmony_ci sanei_libusb_strerror (result)); 3000141cc406Sopenharmony_ci if (result == LIBUSB_ERROR_ACCESS) 3001141cc406Sopenharmony_ci { 3002141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 3003141cc406Sopenharmony_ci "permissions\n"); 3004141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 3005141cc406Sopenharmony_ci } 3006141cc406Sopenharmony_ci else if (result == LIBUSB_ERROR_BUSY) 3007141cc406Sopenharmony_ci { 3008141cc406Sopenharmony_ci DBG (1, "Maybe the kernel scanner driver claims the " 3009141cc406Sopenharmony_ci "scanner's interface?\n"); 3010141cc406Sopenharmony_ci status = SANE_STATUS_DEVICE_BUSY; 3011141cc406Sopenharmony_ci } 3012141cc406Sopenharmony_ci 3013141cc406Sopenharmony_ci libusb_close (devices[devcount].lu_handle); 3014141cc406Sopenharmony_ci return status; 3015141cc406Sopenharmony_ci } 3016141cc406Sopenharmony_ci 3017141cc406Sopenharmony_ci /* Loop through all of the configurations */ 3018141cc406Sopenharmony_ci for (c = 0; c < desc.bNumConfigurations; c++) 3019141cc406Sopenharmony_ci { 3020141cc406Sopenharmony_ci struct libusb_config_descriptor *config; 3021141cc406Sopenharmony_ci 3022141cc406Sopenharmony_ci result = libusb_get_config_descriptor (dev, c, &config); 3023141cc406Sopenharmony_ci if (result < 0) 3024141cc406Sopenharmony_ci { 3025141cc406Sopenharmony_ci DBG (1, 3026141cc406Sopenharmony_ci "sanei_usb_open: could not get config[%d] descriptor for device `%s' (err %d)\n", 3027141cc406Sopenharmony_ci c, devname, result); 3028141cc406Sopenharmony_ci continue; 3029141cc406Sopenharmony_ci } 3030141cc406Sopenharmony_ci 3031141cc406Sopenharmony_ci /* Loop through all of the interfaces */ 3032141cc406Sopenharmony_ci for (i = 0; i < config->bNumInterfaces; i++) 3033141cc406Sopenharmony_ci { 3034141cc406Sopenharmony_ci /* Loop through all of the alternate settings */ 3035141cc406Sopenharmony_ci for (a = 0; a < config->interface[i].num_altsetting; a++) 3036141cc406Sopenharmony_ci { 3037141cc406Sopenharmony_ci const struct libusb_interface_descriptor *interface; 3038141cc406Sopenharmony_ci 3039141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: configuration nr: %d\n", c); 3040141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: interface nr: %d\n", i); 3041141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: alt_setting nr: %d\n", a); 3042141cc406Sopenharmony_ci 3043141cc406Sopenharmony_ci /* Start by interfaces found in sanei_usb_init */ 3044141cc406Sopenharmony_ci if (c == 0 && i != devices[devcount].interface_nr) 3045141cc406Sopenharmony_ci { 3046141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: interface %d not detected as " 3047141cc406Sopenharmony_ci "a scanner by sanei_usb_init, ignoring.\n", i); 3048141cc406Sopenharmony_ci continue; 3049141cc406Sopenharmony_ci } 3050141cc406Sopenharmony_ci 3051141cc406Sopenharmony_ci interface = &config->interface[i].altsetting[a]; 3052141cc406Sopenharmony_ci 3053141cc406Sopenharmony_ci /* Now we look for usable endpoints */ 3054141cc406Sopenharmony_ci for (num = 0; num < interface->bNumEndpoints; num++) 3055141cc406Sopenharmony_ci { 3056141cc406Sopenharmony_ci const struct libusb_endpoint_descriptor *endpoint; 3057141cc406Sopenharmony_ci int direction, transfer_type, transfer_type_libusb; 3058141cc406Sopenharmony_ci 3059141cc406Sopenharmony_ci endpoint = &interface->endpoint[num]; 3060141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: endpoint nr: %d\n", num); 3061141cc406Sopenharmony_ci 3062141cc406Sopenharmony_ci transfer_type_libusb = 3063141cc406Sopenharmony_ci endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK; 3064141cc406Sopenharmony_ci direction = endpoint->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK; 3065141cc406Sopenharmony_ci 3066141cc406Sopenharmony_ci // don't rely on LIBUSB_TRANSFER_TYPE_* mapping to 3067141cc406Sopenharmony_ci // USB_ENDPOINT_TYPE_* even though they'll most likely be 3068141cc406Sopenharmony_ci // the same 3069141cc406Sopenharmony_ci switch (transfer_type_libusb) 3070141cc406Sopenharmony_ci { 3071141cc406Sopenharmony_ci case LIBUSB_TRANSFER_TYPE_INTERRUPT: 3072141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_INTERRUPT; 3073141cc406Sopenharmony_ci break; 3074141cc406Sopenharmony_ci case LIBUSB_TRANSFER_TYPE_BULK: 3075141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_BULK; 3076141cc406Sopenharmony_ci break; 3077141cc406Sopenharmony_ci case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 3078141cc406Sopenharmony_ci transfer_type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; 3079141cc406Sopenharmony_ci break; 3080141cc406Sopenharmony_ci case LIBUSB_TRANSFER_TYPE_CONTROL: 3081141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_CONTROL; 3082141cc406Sopenharmony_ci break; 3083141cc406Sopenharmony_ci 3084141cc406Sopenharmony_ci } 3085141cc406Sopenharmony_ci 3086141cc406Sopenharmony_ci sanei_usb_add_endpoint(&devices[devcount], 3087141cc406Sopenharmony_ci transfer_type, 3088141cc406Sopenharmony_ci endpoint->bEndpointAddress, 3089141cc406Sopenharmony_ci direction); 3090141cc406Sopenharmony_ci } 3091141cc406Sopenharmony_ci } 3092141cc406Sopenharmony_ci } 3093141cc406Sopenharmony_ci 3094141cc406Sopenharmony_ci libusb_free_config_descriptor (config); 3095141cc406Sopenharmony_ci } 3096141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) /* usb_manager */ 3097141cc406Sopenharmony_ci 3098141cc406Sopenharmony_ci int config; 3099141cc406Sopenharmony_ci usb_manager_device *dev; 3100141cc406Sopenharmony_ci struct usb_manager_device_descriptor desc; 3101141cc406Sopenharmony_ci struct usb_manager_config_descriptor *config0; 3102141cc406Sopenharmony_ci int result, num; 3103141cc406Sopenharmony_ci int c, i, a; 3104141cc406Sopenharmony_ci 3105141cc406Sopenharmony_ci dev = devices[devcount].usb_manager_device; 3106141cc406Sopenharmony_ci 3107141cc406Sopenharmony_ci result = usb_manager_open (dev, &devices[devcount].usb_manager_handle); 3108141cc406Sopenharmony_ci if (result < 0) 3109141cc406Sopenharmony_ci { 3110141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 3111141cc406Sopenharmony_ci 3112141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't open device `%s': %s\n", 3113141cc406Sopenharmony_ci devname, sanei_usb_manager_strerror (result)); 3114141cc406Sopenharmony_ci if (result == USB_MANAGER_ERROR_ACCESS) 3115141cc406Sopenharmony_ci { 3116141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 3117141cc406Sopenharmony_ci "permissions\n"); 3118141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 3119141cc406Sopenharmony_ci } 3120141cc406Sopenharmony_ci else if (result == USB_MANAGER_ERROR_BUSY) 3121141cc406Sopenharmony_ci { 3122141cc406Sopenharmony_ci DBG (1, "Maybe the kernel scanner driver claims the " 3123141cc406Sopenharmony_ci "scanner's interface?\n"); 3124141cc406Sopenharmony_ci status = SANE_STATUS_DEVICE_BUSY; 3125141cc406Sopenharmony_ci } 3126141cc406Sopenharmony_ci else if (result == USB_MANAGER_ERROR_NO_MEM) 3127141cc406Sopenharmony_ci { 3128141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 3129141cc406Sopenharmony_ci } 3130141cc406Sopenharmony_ci return status; 3131141cc406Sopenharmony_ci } 3132141cc406Sopenharmony_ci 3133141cc406Sopenharmony_ci result = usb_manager_get_configuration (devices[devcount].usb_manager_handle, &config); 3134141cc406Sopenharmony_ci if (result < 0) 3135141cc406Sopenharmony_ci { 3136141cc406Sopenharmony_ci DBG (1, 3137141cc406Sopenharmony_ci "sanei_usb_open: could not get configuration for device `%s' (err %d)\n", 3138141cc406Sopenharmony_ci devname, result); 3139141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3140141cc406Sopenharmony_ci } 3141141cc406Sopenharmony_ci 3142141cc406Sopenharmony_ci#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES) 3143141cc406Sopenharmony_ci if (config == 0) 3144141cc406Sopenharmony_ci { 3145141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: device `%s' not configured?\n", devname); 3146141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3147141cc406Sopenharmony_ci } 3148141cc406Sopenharmony_ci#endif 3149141cc406Sopenharmony_ci 3150141cc406Sopenharmony_ci result = usb_manager_get_device_descriptor (dev, &desc); 3151141cc406Sopenharmony_ci if (result < 0) 3152141cc406Sopenharmony_ci { 3153141cc406Sopenharmony_ci DBG (1, 3154141cc406Sopenharmony_ci "sanei_usb_open: could not get device descriptor for device `%s' (err %d)\n", 3155141cc406Sopenharmony_ci devname, result); 3156141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3157141cc406Sopenharmony_ci } 3158141cc406Sopenharmony_ci 3159141cc406Sopenharmony_ci result = usb_manager_get_config_descriptor (dev, 0, &config0); 3160141cc406Sopenharmony_ci if (result < 0) 3161141cc406Sopenharmony_ci { 3162141cc406Sopenharmony_ci DBG (1, 3163141cc406Sopenharmony_ci "sanei_usb_open: could not get config[0] descriptor for device `%s' (err %d)\n", 3164141cc406Sopenharmony_ci devname, result); 3165141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3166141cc406Sopenharmony_ci } 3167141cc406Sopenharmony_ci 3168141cc406Sopenharmony_ci /* Set the configuration */ 3169141cc406Sopenharmony_ci if (desc.bNumConfigurations > 1) 3170141cc406Sopenharmony_ci { 3171141cc406Sopenharmony_ci DBG (3, "sanei_usb_open: more than one " 3172141cc406Sopenharmony_ci "configuration (%d), choosing first config (%d)\n", 3173141cc406Sopenharmony_ci desc.bNumConfigurations, 3174141cc406Sopenharmony_ci config0->bConfigurationValue); 3175141cc406Sopenharmony_ci 3176141cc406Sopenharmony_ci result = 0; 3177141cc406Sopenharmony_ci if (config != config0->bConfigurationValue) 3178141cc406Sopenharmony_ci result = usb_manager_set_configuration (devices[devcount].usb_manager_handle, 3179141cc406Sopenharmony_ci config0->bConfigurationValue); 3180141cc406Sopenharmony_ci 3181141cc406Sopenharmony_ci if (result < 0) 3182141cc406Sopenharmony_ci { 3183141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 3184141cc406Sopenharmony_ci 3185141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: usb_manager complained: %s\n", 3186141cc406Sopenharmony_ci sanei_usb_manager_strerror (result)); 3187141cc406Sopenharmony_ci if (result == USB_MANAGER_ERROR_ACCESS) 3188141cc406Sopenharmony_ci { 3189141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 3190141cc406Sopenharmony_ci "permissions\n"); 3191141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 3192141cc406Sopenharmony_ci } 3193141cc406Sopenharmony_ci else if (result == USB_MANAGER_ERROR_BUSY) 3194141cc406Sopenharmony_ci { 3195141cc406Sopenharmony_ci DBG (3, "Maybe the kernel scanner driver or usblp claims " 3196141cc406Sopenharmony_ci "the interface? Ignoring this error...\n"); 3197141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 3198141cc406Sopenharmony_ci } 3199141cc406Sopenharmony_ci 3200141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 3201141cc406Sopenharmony_ci { 3202141cc406Sopenharmony_ci usb_manager_close (devices[devcount].usb_manager_handle); 3203141cc406Sopenharmony_ci usb_manager_free_config_descriptor (config0); 3204141cc406Sopenharmony_ci return status; 3205141cc406Sopenharmony_ci } 3206141cc406Sopenharmony_ci } 3207141cc406Sopenharmony_ci } 3208141cc406Sopenharmony_ci usb_manager_free_config_descriptor (config0); 3209141cc406Sopenharmony_ci 3210141cc406Sopenharmony_ci /* Claim the interface */ 3211141cc406Sopenharmony_ci result = usb_manager_claim_interface (devices[devcount].usb_manager_handle, 3212141cc406Sopenharmony_ci devices[devcount].interface_nr); 3213141cc406Sopenharmony_ci if (result < 0) 3214141cc406Sopenharmony_ci { 3215141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 3216141cc406Sopenharmony_ci 3217141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: usb_manager complained: %s\n", 3218141cc406Sopenharmony_ci sanei_usb_manager_strerror (result)); 3219141cc406Sopenharmony_ci if (result == USB_MANAGER_ERROR_ACCESS) 3220141cc406Sopenharmony_ci { 3221141cc406Sopenharmony_ci DBG (1, "Make sure you run as root or set appropriate " 3222141cc406Sopenharmony_ci "permissions\n"); 3223141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 3224141cc406Sopenharmony_ci } 3225141cc406Sopenharmony_ci else if (result == USB_MANAGER_ERROR_BUSY) 3226141cc406Sopenharmony_ci { 3227141cc406Sopenharmony_ci DBG (1, "Maybe the kernel scanner driver claims the " 3228141cc406Sopenharmony_ci "scanner's interface?\n"); 3229141cc406Sopenharmony_ci status = SANE_STATUS_DEVICE_BUSY; 3230141cc406Sopenharmony_ci } 3231141cc406Sopenharmony_ci 3232141cc406Sopenharmony_ci usb_manager_close (devices[devcount].usb_manager_handle); 3233141cc406Sopenharmony_ci return status; 3234141cc406Sopenharmony_ci } 3235141cc406Sopenharmony_ci 3236141cc406Sopenharmony_ci /* Loop through all of the configurations */ 3237141cc406Sopenharmony_ci for (c = 0; c < desc.bNumConfigurations; c++) 3238141cc406Sopenharmony_ci { 3239141cc406Sopenharmony_ci struct usb_manager_config_descriptor *config; 3240141cc406Sopenharmony_ci 3241141cc406Sopenharmony_ci result = usb_manager_get_config_descriptor (dev, c, &config); 3242141cc406Sopenharmony_ci if (result < 0) 3243141cc406Sopenharmony_ci { 3244141cc406Sopenharmony_ci DBG (1, 3245141cc406Sopenharmony_ci "sanei_usb_open: could not get config[%d] descriptor for device `%s' (err %d)\n", 3246141cc406Sopenharmony_ci c, devname, result); 3247141cc406Sopenharmony_ci continue; 3248141cc406Sopenharmony_ci } 3249141cc406Sopenharmony_ci 3250141cc406Sopenharmony_ci /* Loop through all of the interfaces */ 3251141cc406Sopenharmony_ci for (i = 0; i < config->bNumInterfaces; i++) 3252141cc406Sopenharmony_ci { 3253141cc406Sopenharmony_ci /* Loop through all of the alternate settings */ 3254141cc406Sopenharmony_ci for (a = 0; a < config->interface[i].num_altsetting; a++) 3255141cc406Sopenharmony_ci { 3256141cc406Sopenharmony_ci const struct usb_manager_interface_descriptor *interface; 3257141cc406Sopenharmony_ci 3258141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: configuration nr: %d\n", c); 3259141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: interface nr: %d\n", i); 3260141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: alt_setting nr: %d\n", a); 3261141cc406Sopenharmony_ci 3262141cc406Sopenharmony_ci /* Start by interfaces found in sanei_usb_init */ 3263141cc406Sopenharmony_ci if (c == 0 && i != devices[devcount].interface_nr) 3264141cc406Sopenharmony_ci { 3265141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: interface %d not detected as " 3266141cc406Sopenharmony_ci "a scanner by sanei_usb_init, ignoring.\n", i); 3267141cc406Sopenharmony_ci continue; 3268141cc406Sopenharmony_ci } 3269141cc406Sopenharmony_ci 3270141cc406Sopenharmony_ci interface = &config->interface[i].altsetting[a]; 3271141cc406Sopenharmony_ci 3272141cc406Sopenharmony_ci /* Now we look for usable endpoints */ 3273141cc406Sopenharmony_ci for (num = 0; num < interface->bNumEndpoints; num++) 3274141cc406Sopenharmony_ci { 3275141cc406Sopenharmony_ci const struct usb_manager_endpoint_descriptor *endpoint; 3276141cc406Sopenharmony_ci int direction, transfer_type, transfer_type_usb_manager; 3277141cc406Sopenharmony_ci 3278141cc406Sopenharmony_ci endpoint = &interface->endpoint[num]; 3279141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: endpoint nr: %d\n", num); 3280141cc406Sopenharmony_ci 3281141cc406Sopenharmony_ci transfer_type_usb_manager = 3282141cc406Sopenharmony_ci endpoint->bmAttributes & USB_MANAGER_TRANSFER_TYPE_MASK; 3283141cc406Sopenharmony_ci direction = endpoint->bEndpointAddress & USB_MANAGER_ENDPOINT_DIR_MASK; 3284141cc406Sopenharmony_ci 3285141cc406Sopenharmony_ci // don't rely on USB_MANAGER_TRANSFER_TYPE_* mapping to 3286141cc406Sopenharmony_ci // USB_ENDPOINT_TYPE_* even though they'll most likely be 3287141cc406Sopenharmony_ci // the same 3288141cc406Sopenharmony_ci switch (transfer_type_usb_manager) 3289141cc406Sopenharmony_ci { 3290141cc406Sopenharmony_ci case USB_MANAGER_TRANSFER_TYPE_INTERRUPT: 3291141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_INTERRUPT; 3292141cc406Sopenharmony_ci break; 3293141cc406Sopenharmony_ci case USB_MANAGER_TRANSFER_TYPE_BULK: 3294141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_BULK; 3295141cc406Sopenharmony_ci break; 3296141cc406Sopenharmony_ci case USB_MANAGER_TRANSFER_TYPE_ISOCHRONOUS: 3297141cc406Sopenharmony_ci transfer_type = USB_MANAGER_TRANSFER_TYPE_ISOCHRONOUS; 3298141cc406Sopenharmony_ci break; 3299141cc406Sopenharmony_ci case USB_MANAGER_TRANSFER_TYPE_CONTROL: 3300141cc406Sopenharmony_ci transfer_type = USB_ENDPOINT_TYPE_CONTROL; 3301141cc406Sopenharmony_ci break; 3302141cc406Sopenharmony_ci 3303141cc406Sopenharmony_ci } 3304141cc406Sopenharmony_ci 3305141cc406Sopenharmony_ci sanei_usb_add_endpoint(&devices[devcount], 3306141cc406Sopenharmony_ci transfer_type, 3307141cc406Sopenharmony_ci endpoint->bEndpointAddress, 3308141cc406Sopenharmony_ci direction); 3309141cc406Sopenharmony_ci } 3310141cc406Sopenharmony_ci } 3311141cc406Sopenharmony_ci } 3312141cc406Sopenharmony_ci 3313141cc406Sopenharmony_ci usb_manager_free_config_descriptor (config); 3314141cc406Sopenharmony_ci } 3315141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 3316141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't open device `%s': " 3317141cc406Sopenharmony_ci "libusb support missing\n", devname); 3318141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 3319141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 3320141cc406Sopenharmony_ci } 3321141cc406Sopenharmony_ci else if (devices[devcount].method == sanei_usb_method_scanner_driver) 3322141cc406Sopenharmony_ci { 3323141cc406Sopenharmony_ci#ifdef FD_CLOEXEC 3324141cc406Sopenharmony_ci long int flag; 3325141cc406Sopenharmony_ci#endif 3326141cc406Sopenharmony_ci /* Using kernel scanner driver */ 3327141cc406Sopenharmony_ci devices[devcount].fd = -1; 3328141cc406Sopenharmony_ci#ifdef HAVE_RESMGR 3329141cc406Sopenharmony_ci devices[devcount].fd = rsm_open_device (devname, O_RDWR); 3330141cc406Sopenharmony_ci#endif 3331141cc406Sopenharmony_ci if (devices[devcount].fd == -1) 3332141cc406Sopenharmony_ci devices[devcount].fd = open (devname, O_RDWR); 3333141cc406Sopenharmony_ci if (devices[devcount].fd < 0) 3334141cc406Sopenharmony_ci { 3335141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 3336141cc406Sopenharmony_ci 3337141cc406Sopenharmony_ci if (errno == EACCES) 3338141cc406Sopenharmony_ci status = SANE_STATUS_ACCESS_DENIED; 3339141cc406Sopenharmony_ci else if (errno == ENOENT) 3340141cc406Sopenharmony_ci { 3341141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: open of `%s' failed: %s\n", 3342141cc406Sopenharmony_ci devname, strerror (errno)); 3343141cc406Sopenharmony_ci return status; 3344141cc406Sopenharmony_ci } 3345141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: open of `%s' failed: %s\n", 3346141cc406Sopenharmony_ci devname, strerror (errno)); 3347141cc406Sopenharmony_ci return status; 3348141cc406Sopenharmony_ci } 3349141cc406Sopenharmony_ci#ifdef FD_CLOEXEC 3350141cc406Sopenharmony_ci flag = fcntl (devices[devcount].fd, F_GETFD); 3351141cc406Sopenharmony_ci if (flag >= 0) 3352141cc406Sopenharmony_ci { 3353141cc406Sopenharmony_ci if (fcntl (devices[devcount].fd, F_SETFD, flag | FD_CLOEXEC) < 0) 3354141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: fcntl of `%s' failed: %s\n", 3355141cc406Sopenharmony_ci devname, strerror (errno)); 3356141cc406Sopenharmony_ci } 3357141cc406Sopenharmony_ci#endif 3358141cc406Sopenharmony_ci } 3359141cc406Sopenharmony_ci else if (devices[devcount].method == sanei_usb_method_usbcalls) 3360141cc406Sopenharmony_ci { 3361141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 3362141cc406Sopenharmony_ci CHAR ucData[2048]; 3363141cc406Sopenharmony_ci struct usb_device_descriptor *pDevDesc; 3364141cc406Sopenharmony_ci struct usb_config_descriptor *pCfgDesc; 3365141cc406Sopenharmony_ci struct usb_interface_descriptor *interface; 3366141cc406Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 3367141cc406Sopenharmony_ci struct usb_descriptor_header *pDescHead; 3368141cc406Sopenharmony_ci 3369141cc406Sopenharmony_ci ULONG ulBufLen; 3370141cc406Sopenharmony_ci ulBufLen = sizeof(ucData); 3371141cc406Sopenharmony_ci memset(&ucData,0,sizeof(ucData)); 3372141cc406Sopenharmony_ci 3373141cc406Sopenharmony_ci int result, rc; 3374141cc406Sopenharmony_ci int address, direction, transfer_type; 3375141cc406Sopenharmony_ci 3376141cc406Sopenharmony_ci DBG (5, "devname = %s, devcount = %d\n",devices[devcount].devname,devcount); 3377141cc406Sopenharmony_ci DBG (5, "USBCalls device number to open = %d\n",devices[devcount].fd); 3378141cc406Sopenharmony_ci DBG (5, "USBCalls Vendor/Product to open = 0x%04x/0x%04x\n", 3379141cc406Sopenharmony_ci devices[devcount].vendor,devices[devcount].product); 3380141cc406Sopenharmony_ci 3381141cc406Sopenharmony_ci rc = UsbOpen (&dh, 3382141cc406Sopenharmony_ci devices[devcount].vendor, 3383141cc406Sopenharmony_ci devices[devcount].product, 3384141cc406Sopenharmony_ci USB_ANY_PRODUCTVERSION, 3385141cc406Sopenharmony_ci USB_OPEN_FIRST_UNUSED); 3386141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: UsbOpen rc = %d\n",rc); 3387141cc406Sopenharmony_ci if (rc!=0) 3388141cc406Sopenharmony_ci { 3389141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL; 3390141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't open device `%s': %s\n", 3391141cc406Sopenharmony_ci devname, strerror (rc)); 3392141cc406Sopenharmony_ci return status; 3393141cc406Sopenharmony_ci } 3394141cc406Sopenharmony_ci rc = UsbQueryDeviceReport( devices[devcount].fd, 3395141cc406Sopenharmony_ci &ulBufLen, 3396141cc406Sopenharmony_ci ucData); 3397141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: UsbQueryDeviceReport rc = %d\n",rc); 3398141cc406Sopenharmony_ci pDevDesc = (struct usb_device_descriptor*)ucData; 3399141cc406Sopenharmony_ci pCfgDesc = (struct usb_config_descriptor*) (ucData+sizeof(struct usb_device_descriptor)); 3400141cc406Sopenharmony_ci UCHAR *pCurPtr = (UCHAR*) pCfgDesc; 3401141cc406Sopenharmony_ci UCHAR *pEndPtr = pCurPtr+ pCfgDesc->wTotalLength; 3402141cc406Sopenharmony_ci pDescHead = (struct usb_descriptor_header *) (pCurPtr+pCfgDesc->bLength); 3403141cc406Sopenharmony_ci /* Set the configuration */ 3404141cc406Sopenharmony_ci if (pDevDesc->bNumConfigurations > 1) 3405141cc406Sopenharmony_ci { 3406141cc406Sopenharmony_ci DBG (3, "sanei_usb_open: more than one " 3407141cc406Sopenharmony_ci "configuration (%d), choosing first config (%d)\n", 3408141cc406Sopenharmony_ci pDevDesc->bNumConfigurations, 3409141cc406Sopenharmony_ci pCfgDesc->bConfigurationValue); 3410141cc406Sopenharmony_ci } 3411141cc406Sopenharmony_ci DBG (5, "UsbDeviceSetConfiguration parameters: dh = %p, bConfigurationValue = %d\n", 3412141cc406Sopenharmony_ci dh,pCfgDesc->bConfigurationValue); 3413141cc406Sopenharmony_ci result = UsbDeviceSetConfiguration (dh, 3414141cc406Sopenharmony_ci pCfgDesc->bConfigurationValue); 3415141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: UsbDeviceSetConfiguration rc = %d\n",result); 3416141cc406Sopenharmony_ci if (result) 3417141cc406Sopenharmony_ci { 3418141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: usbcalls complained on UsbDeviceSetConfiguration, rc= %d\n", result); 3419141cc406Sopenharmony_ci UsbClose (dh); 3420141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 3421141cc406Sopenharmony_ci } 3422141cc406Sopenharmony_ci 3423141cc406Sopenharmony_ci /* Now we look for usable endpoints */ 3424141cc406Sopenharmony_ci 3425141cc406Sopenharmony_ci for (pDescHead = (struct usb_descriptor_header *) (pCurPtr+pCfgDesc->bLength); 3426141cc406Sopenharmony_ci pDescHead;pDescHead = GetNextDescriptor(pDescHead,pEndPtr) ) 3427141cc406Sopenharmony_ci { 3428141cc406Sopenharmony_ci switch(pDescHead->bDescriptorType) 3429141cc406Sopenharmony_ci { 3430141cc406Sopenharmony_ci case USB_DT_INTERFACE: 3431141cc406Sopenharmony_ci interface = (struct usb_interface_descriptor *) pDescHead; 3432141cc406Sopenharmony_ci DBG (5, "Found %d endpoints\n",interface->bNumEndpoints); 3433141cc406Sopenharmony_ci DBG (5, "bAlternateSetting = %d\n",interface->bAlternateSetting); 3434141cc406Sopenharmony_ci break; 3435141cc406Sopenharmony_ci case USB_DT_ENDPOINT: 3436141cc406Sopenharmony_ci endpoint = (struct usb_endpoint_descriptor*)pDescHead; 3437141cc406Sopenharmony_ci direction = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK; 3438141cc406Sopenharmony_ci transfer_type = endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK; 3439141cc406Sopenharmony_ci 3440141cc406Sopenharmony_ci if (transfer_type == USB_ENDPOINT_TYPE_INTERRUPT || 3441141cc406Sopenharmony_ci transfer_type == USB_ENDPOINT_TYPE_BULK) 3442141cc406Sopenharmony_ci { 3443141cc406Sopenharmony_ci sanei_usb_add_endpoint(&devices[devcount], transfer_type, 3444141cc406Sopenharmony_ci endpoint->bEndpointAddress, direction); 3445141cc406Sopenharmony_ci } 3446141cc406Sopenharmony_ci /* ignore currently unsupported endpoints */ 3447141cc406Sopenharmony_ci else { 3448141cc406Sopenharmony_ci DBG (5, "sanei_usb_open: ignoring %s-%s endpoint " 3449141cc406Sopenharmony_ci "(address: %d)\n", 3450141cc406Sopenharmony_ci sanei_usb_transfer_type_desc(transfer_type), 3451141cc406Sopenharmony_ci direction ? "in" : "out", address); 3452141cc406Sopenharmony_ci continue; 3453141cc406Sopenharmony_ci } 3454141cc406Sopenharmony_ci break; 3455141cc406Sopenharmony_ci } 3456141cc406Sopenharmony_ci } 3457141cc406Sopenharmony_ci#else 3458141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: can't open device `%s': " 3459141cc406Sopenharmony_ci "usbcalls support missing\n", devname); 3460141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 3461141cc406Sopenharmony_ci#endif /* HAVE_USBCALLS */ 3462141cc406Sopenharmony_ci } 3463141cc406Sopenharmony_ci else 3464141cc406Sopenharmony_ci { 3465141cc406Sopenharmony_ci DBG (1, "sanei_usb_open: access method %d not implemented\n", 3466141cc406Sopenharmony_ci devices[devcount].method); 3467141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3468141cc406Sopenharmony_ci } 3469141cc406Sopenharmony_ci 3470141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 3471141cc406Sopenharmony_ci { 3472141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 3473141cc406Sopenharmony_ci sanei_usb_record_open(devcount); 3474141cc406Sopenharmony_ci#else 3475141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 3476141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 3477141cc406Sopenharmony_ci#endif 3478141cc406Sopenharmony_ci } 3479141cc406Sopenharmony_ci 3480141cc406Sopenharmony_ci devices[devcount].open = SANE_TRUE; 3481141cc406Sopenharmony_ci *dn = devcount; 3482141cc406Sopenharmony_ci DBG (3, "sanei_usb_open: opened usb device `%s' (*dn=%d)\n", 3483141cc406Sopenharmony_ci devname, devcount); 3484141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3485141cc406Sopenharmony_ci} 3486141cc406Sopenharmony_ci 3487141cc406Sopenharmony_civoid 3488141cc406Sopenharmony_cisanei_usb_close (SANE_Int dn) 3489141cc406Sopenharmony_ci{ 3490141cc406Sopenharmony_ci char *env; 3491141cc406Sopenharmony_ci int workaround = 0; 3492141cc406Sopenharmony_ci 3493141cc406Sopenharmony_ci DBG (5, "sanei_usb_close: evaluating environment variable SANE_USB_WORKAROUND\n"); 3494141cc406Sopenharmony_ci env = getenv ("SANE_USB_WORKAROUND"); 3495141cc406Sopenharmony_ci if (env) 3496141cc406Sopenharmony_ci { 3497141cc406Sopenharmony_ci workaround = atoi(env); 3498141cc406Sopenharmony_ci DBG (5, "sanei_usb_close: workaround: %d\n", workaround); 3499141cc406Sopenharmony_ci } 3500141cc406Sopenharmony_ci 3501141cc406Sopenharmony_ci DBG (5, "sanei_usb_close: closing device %d\n", dn); 3502141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 3503141cc406Sopenharmony_ci { 3504141cc406Sopenharmony_ci DBG (1, "sanei_usb_close: dn >= device number || dn < 0\n"); 3505141cc406Sopenharmony_ci return; 3506141cc406Sopenharmony_ci } 3507141cc406Sopenharmony_ci if (!devices[dn].open) 3508141cc406Sopenharmony_ci { 3509141cc406Sopenharmony_ci DBG (1, "sanei_usb_close: device %d already closed or never opened\n", 3510141cc406Sopenharmony_ci dn); 3511141cc406Sopenharmony_ci return; 3512141cc406Sopenharmony_ci } 3513141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 3514141cc406Sopenharmony_ci { 3515141cc406Sopenharmony_ci DBG (1, "sanei_usb_close: closing fake USB device\n"); 3516141cc406Sopenharmony_ci } 3517141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 3518141cc406Sopenharmony_ci close (devices[dn].fd); 3519141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_usbcalls) 3520141cc406Sopenharmony_ci { 3521141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 3522141cc406Sopenharmony_ci int rc; 3523141cc406Sopenharmony_ci rc=UsbClose (dh); 3524141cc406Sopenharmony_ci DBG (5,"rc of UsbClose = %d\n",rc); 3525141cc406Sopenharmony_ci#else 3526141cc406Sopenharmony_ci DBG (1, "sanei_usb_close: usbcalls support missing\n"); 3527141cc406Sopenharmony_ci#endif 3528141cc406Sopenharmony_ci } 3529141cc406Sopenharmony_ci else 3530141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 3531141cc406Sopenharmony_ci { 3532141cc406Sopenharmony_ci /* This call seems to be required by Linux xhci driver 3533141cc406Sopenharmony_ci * even though it should be a no-op. Without it, the 3534141cc406Sopenharmony_ci * host or driver does not reset it's data toggle bit. 3535141cc406Sopenharmony_ci * We intentionally ignore the return val */ 3536141cc406Sopenharmony_ci if (workaround) 3537141cc406Sopenharmony_ci { 3538141cc406Sopenharmony_ci sanei_usb_set_altinterface (dn, devices[dn].alt_setting); 3539141cc406Sopenharmony_ci } 3540141cc406Sopenharmony_ci 3541141cc406Sopenharmony_ci usb_release_interface (devices[dn].libusb_handle, 3542141cc406Sopenharmony_ci devices[dn].interface_nr); 3543141cc406Sopenharmony_ci usb_close (devices[dn].libusb_handle); 3544141cc406Sopenharmony_ci } 3545141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 3546141cc406Sopenharmony_ci { 3547141cc406Sopenharmony_ci /* This call seems to be required by Linux xhci driver 3548141cc406Sopenharmony_ci * even though it should be a no-op. Without it, the 3549141cc406Sopenharmony_ci * host or driver does not reset it's data toggle bit. 3550141cc406Sopenharmony_ci * We intentionally ignore the return val */ 3551141cc406Sopenharmony_ci if (workaround) 3552141cc406Sopenharmony_ci { 3553141cc406Sopenharmony_ci sanei_usb_set_altinterface (dn, devices[dn].alt_setting); 3554141cc406Sopenharmony_ci } 3555141cc406Sopenharmony_ci 3556141cc406Sopenharmony_ci libusb_release_interface (devices[dn].lu_handle, 3557141cc406Sopenharmony_ci devices[dn].interface_nr); 3558141cc406Sopenharmony_ci libusb_close (devices[dn].lu_handle); 3559141cc406Sopenharmony_ci } 3560141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 3561141cc406Sopenharmony_ci { 3562141cc406Sopenharmony_ci /* This call seems to be required by Linux xhci driver 3563141cc406Sopenharmony_ci * even though it should be a no-op. Without it, the 3564141cc406Sopenharmony_ci * host or driver does not reset it's data toggle bit. 3565141cc406Sopenharmony_ci * We intentionally ignore the return val */ 3566141cc406Sopenharmony_ci if (workaround) 3567141cc406Sopenharmony_ci { 3568141cc406Sopenharmony_ci sanei_usb_set_altinterface (dn, devices[dn].alt_setting); 3569141cc406Sopenharmony_ci } 3570141cc406Sopenharmony_ci 3571141cc406Sopenharmony_ci usb_manager_release_interface (devices[dn].usb_manager_handle, 3572141cc406Sopenharmony_ci devices[dn].interface_nr); 3573141cc406Sopenharmony_ci usb_manager_close (devices[dn].usb_manager_handle); 3574141cc406Sopenharmony_ci } 3575141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 3576141cc406Sopenharmony_ci DBG (1, "sanei_usb_close: libusb support missing\n"); 3577141cc406Sopenharmony_ci#endif 3578141cc406Sopenharmony_ci devices[dn].open = SANE_FALSE; 3579141cc406Sopenharmony_ci return; 3580141cc406Sopenharmony_ci} 3581141cc406Sopenharmony_ci 3582141cc406Sopenharmony_civoid 3583141cc406Sopenharmony_cisanei_usb_set_timeout (SANE_Int __sane_unused__ timeout) 3584141cc406Sopenharmony_ci{ 3585141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 3586141cc406Sopenharmony_ci return; 3587141cc406Sopenharmony_ci 3588141cc406Sopenharmony_ci#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) 3589141cc406Sopenharmony_ci libusb_timeout = timeout; 3590141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 3591141cc406Sopenharmony_ci usb_manager_timeout = timeout; 3592141cc406Sopenharmony_ci#else 3593141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_timeout: libusb support missing\n"); 3594141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USB_MANAGER */ 3595141cc406Sopenharmony_ci} 3596141cc406Sopenharmony_ci 3597141cc406Sopenharmony_ciSANE_Status 3598141cc406Sopenharmony_cisanei_usb_clear_halt (SANE_Int dn) 3599141cc406Sopenharmony_ci{ 3600141cc406Sopenharmony_ci char *env; 3601141cc406Sopenharmony_ci int workaround = 0; 3602141cc406Sopenharmony_ci 3603141cc406Sopenharmony_ci DBG (5, "sanei_usb_clear_halt: evaluating environment variable SANE_USB_WORKAROUND\n"); 3604141cc406Sopenharmony_ci env = getenv ("SANE_USB_WORKAROUND"); 3605141cc406Sopenharmony_ci if (env) 3606141cc406Sopenharmony_ci { 3607141cc406Sopenharmony_ci workaround = atoi(env); 3608141cc406Sopenharmony_ci DBG (5, "sanei_usb_clear_halt: workaround: %d\n", workaround); 3609141cc406Sopenharmony_ci } 3610141cc406Sopenharmony_ci 3611141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 3612141cc406Sopenharmony_ci { 3613141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: dn >= device number || dn < 0\n"); 3614141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3615141cc406Sopenharmony_ci } 3616141cc406Sopenharmony_ci 3617141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 3618141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3619141cc406Sopenharmony_ci 3620141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 3621141cc406Sopenharmony_ci int ret; 3622141cc406Sopenharmony_ci 3623141cc406Sopenharmony_ci /* This call seems to be required by Linux xhci driver 3624141cc406Sopenharmony_ci * even though it should be a no-op. Without it, the 3625141cc406Sopenharmony_ci * host or driver does not send the clear to the device. 3626141cc406Sopenharmony_ci * We intentionally ignore the return val */ 3627141cc406Sopenharmony_ci if (workaround) 3628141cc406Sopenharmony_ci { 3629141cc406Sopenharmony_ci sanei_usb_set_altinterface (dn, devices[dn].alt_setting); 3630141cc406Sopenharmony_ci } 3631141cc406Sopenharmony_ci 3632141cc406Sopenharmony_ci ret = usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_in_ep); 3633141cc406Sopenharmony_ci if (ret){ 3634141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: BULK_IN ret=%d\n", ret); 3635141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3636141cc406Sopenharmony_ci } 3637141cc406Sopenharmony_ci 3638141cc406Sopenharmony_ci ret = usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_out_ep); 3639141cc406Sopenharmony_ci if (ret){ 3640141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: BULK_OUT ret=%d\n", ret); 3641141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3642141cc406Sopenharmony_ci } 3643141cc406Sopenharmony_ci 3644141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 3645141cc406Sopenharmony_ci int ret; 3646141cc406Sopenharmony_ci 3647141cc406Sopenharmony_ci /* This call seems to be required by Linux xhci driver 3648141cc406Sopenharmony_ci * even though it should be a no-op. Without it, the 3649141cc406Sopenharmony_ci * host or driver does not send the clear to the device. 3650141cc406Sopenharmony_ci * We intentionally ignore the return val */ 3651141cc406Sopenharmony_ci if (workaround) 3652141cc406Sopenharmony_ci { 3653141cc406Sopenharmony_ci sanei_usb_set_altinterface (dn, devices[dn].alt_setting); 3654141cc406Sopenharmony_ci } 3655141cc406Sopenharmony_ci 3656141cc406Sopenharmony_ci ret = libusb_clear_halt (devices[dn].lu_handle, devices[dn].bulk_in_ep); 3657141cc406Sopenharmony_ci if (ret){ 3658141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: BULK_IN ret=%d\n", ret); 3659141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3660141cc406Sopenharmony_ci } 3661141cc406Sopenharmony_ci 3662141cc406Sopenharmony_ci ret = libusb_clear_halt (devices[dn].lu_handle, devices[dn].bulk_out_ep); 3663141cc406Sopenharmony_ci if (ret){ 3664141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: BULK_OUT ret=%d\n", ret); 3665141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3666141cc406Sopenharmony_ci } 3667141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 3668141cc406Sopenharmony_ci int ret; 3669141cc406Sopenharmony_ci 3670141cc406Sopenharmony_ci /* This call seems to be required by Linux xhci driver 3671141cc406Sopenharmony_ci * even though it should be a no-op. Without it, the 3672141cc406Sopenharmony_ci * host or driver does not send the clear to the device. 3673141cc406Sopenharmony_ci * We intentionally ignore the return val */ 3674141cc406Sopenharmony_ci if (workaround) 3675141cc406Sopenharmony_ci { 3676141cc406Sopenharmony_ci sanei_usb_set_altinterface (dn, devices[dn].alt_setting); 3677141cc406Sopenharmony_ci } 3678141cc406Sopenharmony_ci 3679141cc406Sopenharmony_ci ret = usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_in_ep); 3680141cc406Sopenharmony_ci if (ret){ 3681141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: BULK_IN ret=%d\n", ret); 3682141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3683141cc406Sopenharmony_ci } 3684141cc406Sopenharmony_ci 3685141cc406Sopenharmony_ci ret = usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_out_ep); 3686141cc406Sopenharmony_ci if (ret){ 3687141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: BULK_OUT ret=%d\n", ret); 3688141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3689141cc406Sopenharmony_ci } 3690141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 3691141cc406Sopenharmony_ci DBG (1, "sanei_usb_clear_halt: libusb support missing\n"); 3692141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USB_MANAGER */ 3693141cc406Sopenharmony_ci 3694141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3695141cc406Sopenharmony_ci} 3696141cc406Sopenharmony_ci 3697141cc406Sopenharmony_ciSANE_Status 3698141cc406Sopenharmony_cisanei_usb_reset (SANE_Int __sane_unused__ dn) 3699141cc406Sopenharmony_ci{ 3700141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 3701141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3702141cc406Sopenharmony_ci 3703141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 3704141cc406Sopenharmony_ci int ret; 3705141cc406Sopenharmony_ci 3706141cc406Sopenharmony_ci ret = usb_reset (devices[dn].libusb_handle); 3707141cc406Sopenharmony_ci if (ret){ 3708141cc406Sopenharmony_ci DBG (1, "sanei_usb_reset: ret=%d\n", ret); 3709141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3710141cc406Sopenharmony_ci } 3711141cc406Sopenharmony_ci 3712141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 3713141cc406Sopenharmony_ci int ret; 3714141cc406Sopenharmony_ci 3715141cc406Sopenharmony_ci ret = libusb_reset_device (devices[dn].lu_handle); 3716141cc406Sopenharmony_ci if (ret){ 3717141cc406Sopenharmony_ci DBG (1, "sanei_usb_reset: ret=%d\n", ret); 3718141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3719141cc406Sopenharmony_ci } 3720141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 3721141cc406Sopenharmony_ci int ret; 3722141cc406Sopenharmony_ci 3723141cc406Sopenharmony_ci ret = usb_manager_reset_device (devices[dn].usb_manager_handle); 3724141cc406Sopenharmony_ci if (ret){ 3725141cc406Sopenharmony_ci DBG (1, "sanei_usb_reset: ret=%d\n", ret); 3726141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3727141cc406Sopenharmony_ci } 3728141cc406Sopenharmony_ci 3729141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 3730141cc406Sopenharmony_ci DBG (1, "sanei_usb_reset: libusb support missing\n"); 3731141cc406Sopenharmony_ci#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USB_MANAGER */ 3732141cc406Sopenharmony_ci 3733141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 3734141cc406Sopenharmony_ci} 3735141cc406Sopenharmony_ci 3736141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 3737141cc406Sopenharmony_ci// returns non-negative value on success, -1 on failure 3738141cc406Sopenharmony_cistatic int sanei_usb_replay_next_read_bulk_packet_size(SANE_Int dn) 3739141cc406Sopenharmony_ci{ 3740141cc406Sopenharmony_ci xmlNode* node = sanei_xml_peek_next_tx_node(); 3741141cc406Sopenharmony_ci if (node == NULL) 3742141cc406Sopenharmony_ci return -1; 3743141cc406Sopenharmony_ci 3744141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"bulk_tx") != 0) 3745141cc406Sopenharmony_ci { 3746141cc406Sopenharmony_ci return -1; 3747141cc406Sopenharmony_ci } 3748141cc406Sopenharmony_ci 3749141cc406Sopenharmony_ci if (!sanei_usb_attr_is(node, "direction", "IN")) 3750141cc406Sopenharmony_ci return -1; 3751141cc406Sopenharmony_ci if (!sanei_usb_attr_is_uint(node, "endpoint_number", 3752141cc406Sopenharmony_ci devices[dn].bulk_in_ep & 0x0f)) 3753141cc406Sopenharmony_ci return -1; 3754141cc406Sopenharmony_ci 3755141cc406Sopenharmony_ci size_t got_size = 0; 3756141cc406Sopenharmony_ci char* got_data = sanei_xml_get_hex_data(node, &got_size); 3757141cc406Sopenharmony_ci free(got_data); 3758141cc406Sopenharmony_ci return got_size; 3759141cc406Sopenharmony_ci} 3760141cc406Sopenharmony_ci 3761141cc406Sopenharmony_cistatic void sanei_usb_record_read_bulk(xmlNode* node, SANE_Int dn, 3762141cc406Sopenharmony_ci SANE_Byte* buffer, 3763141cc406Sopenharmony_ci size_t size, ssize_t read_size) 3764141cc406Sopenharmony_ci{ 3765141cc406Sopenharmony_ci int node_was_null = node == NULL; 3766141cc406Sopenharmony_ci if (node_was_null) 3767141cc406Sopenharmony_ci node = testing_append_commands_node; 3768141cc406Sopenharmony_ci 3769141cc406Sopenharmony_ci xmlNode* e_tx = xmlNewNode(NULL, (const xmlChar*)"bulk_tx"); 3770141cc406Sopenharmony_ci sanei_xml_command_common_props(e_tx, devices[dn].bulk_in_ep & 0x0f, "IN"); 3771141cc406Sopenharmony_ci 3772141cc406Sopenharmony_ci if (buffer == NULL) 3773141cc406Sopenharmony_ci { 3774141cc406Sopenharmony_ci const int buf_size = 128; 3775141cc406Sopenharmony_ci char buf[buf_size]; 3776141cc406Sopenharmony_ci snprintf(buf, buf_size, "(unknown read of allowed size %ld)", size); 3777141cc406Sopenharmony_ci xmlNode* e_content = xmlNewText((const xmlChar*)buf); 3778141cc406Sopenharmony_ci xmlAddChild(e_tx, e_content); 3779141cc406Sopenharmony_ci } 3780141cc406Sopenharmony_ci else 3781141cc406Sopenharmony_ci { 3782141cc406Sopenharmony_ci if (read_size >= 0) 3783141cc406Sopenharmony_ci { 3784141cc406Sopenharmony_ci sanei_xml_set_hex_data(e_tx, (const char*)buffer, read_size); 3785141cc406Sopenharmony_ci } 3786141cc406Sopenharmony_ci else 3787141cc406Sopenharmony_ci { 3788141cc406Sopenharmony_ci xmlNewProp(e_tx, (const xmlChar*)"error", (const xmlChar*)"timeout"); 3789141cc406Sopenharmony_ci } 3790141cc406Sopenharmony_ci } 3791141cc406Sopenharmony_ci 3792141cc406Sopenharmony_ci node = sanei_xml_append_command(node, node_was_null, e_tx); 3793141cc406Sopenharmony_ci 3794141cc406Sopenharmony_ci if (node_was_null) 3795141cc406Sopenharmony_ci testing_append_commands_node = node; 3796141cc406Sopenharmony_ci} 3797141cc406Sopenharmony_ci 3798141cc406Sopenharmony_cistatic void sanei_usb_record_replace_read_bulk(xmlNode* node, SANE_Int dn, 3799141cc406Sopenharmony_ci SANE_Byte* buffer, 3800141cc406Sopenharmony_ci size_t size, size_t read_size) 3801141cc406Sopenharmony_ci{ 3802141cc406Sopenharmony_ci if (!testing_development_mode) 3803141cc406Sopenharmony_ci return; 3804141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 3805141cc406Sopenharmony_ci testing_last_known_seq--; 3806141cc406Sopenharmony_ci sanei_usb_record_read_bulk(node, dn, buffer, size, read_size); 3807141cc406Sopenharmony_ci xmlUnlinkNode(node); 3808141cc406Sopenharmony_ci xmlFreeNode(node); 3809141cc406Sopenharmony_ci} 3810141cc406Sopenharmony_ci 3811141cc406Sopenharmony_cistatic int sanei_usb_replay_read_bulk(SANE_Int dn, SANE_Byte* buffer, 3812141cc406Sopenharmony_ci size_t size) 3813141cc406Sopenharmony_ci{ 3814141cc406Sopenharmony_ci // libusb may potentially combine multiple IN packets into a single transfer. 3815141cc406Sopenharmony_ci // We recontruct that by looking into the next packet. If it can be 3816141cc406Sopenharmony_ci // included into the current transfer without 3817141cc406Sopenharmony_ci size_t wanted_size = size; 3818141cc406Sopenharmony_ci size_t total_got_size = 0; 3819141cc406Sopenharmony_ci while (wanted_size > 0) 3820141cc406Sopenharmony_ci { 3821141cc406Sopenharmony_ci if (testing_known_commands_input_failed) 3822141cc406Sopenharmony_ci return -1; 3823141cc406Sopenharmony_ci 3824141cc406Sopenharmony_ci xmlNode* node = sanei_xml_get_next_tx_node(); 3825141cc406Sopenharmony_ci if (node == NULL) 3826141cc406Sopenharmony_ci { 3827141cc406Sopenharmony_ci FAIL_TEST(__func__, "no more transactions\n"); 3828141cc406Sopenharmony_ci return -1; 3829141cc406Sopenharmony_ci } 3830141cc406Sopenharmony_ci 3831141cc406Sopenharmony_ci if (sanei_xml_is_known_commands_end(node)) 3832141cc406Sopenharmony_ci { 3833141cc406Sopenharmony_ci sanei_usb_record_read_bulk(NULL, dn, NULL, 0, size); 3834141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 3835141cc406Sopenharmony_ci return -1; 3836141cc406Sopenharmony_ci } 3837141cc406Sopenharmony_ci 3838141cc406Sopenharmony_ci sanei_xml_record_seq(node); 3839141cc406Sopenharmony_ci sanei_xml_break_if_needed(node); 3840141cc406Sopenharmony_ci 3841141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"bulk_tx") != 0) 3842141cc406Sopenharmony_ci { 3843141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", 3844141cc406Sopenharmony_ci (const char*) node->name); 3845141cc406Sopenharmony_ci sanei_usb_record_replace_read_bulk(node, dn, NULL, 0, wanted_size); 3846141cc406Sopenharmony_ci return -1; 3847141cc406Sopenharmony_ci } 3848141cc406Sopenharmony_ci 3849141cc406Sopenharmony_ci if (!sanei_usb_check_attr(node, "direction", "IN", __func__)) 3850141cc406Sopenharmony_ci { 3851141cc406Sopenharmony_ci sanei_usb_record_replace_read_bulk(node, dn, NULL, 0, wanted_size); 3852141cc406Sopenharmony_ci return -1; 3853141cc406Sopenharmony_ci } 3854141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "endpoint_number", 3855141cc406Sopenharmony_ci devices[dn].bulk_in_ep & 0x0f, 3856141cc406Sopenharmony_ci __func__)) 3857141cc406Sopenharmony_ci { 3858141cc406Sopenharmony_ci sanei_usb_record_replace_read_bulk(node, dn, NULL, 0, wanted_size); 3859141cc406Sopenharmony_ci return -1; 3860141cc406Sopenharmony_ci } 3861141cc406Sopenharmony_ci 3862141cc406Sopenharmony_ci size_t got_size = 0; 3863141cc406Sopenharmony_ci char* got_data = sanei_xml_get_hex_data(node, &got_size); 3864141cc406Sopenharmony_ci 3865141cc406Sopenharmony_ci if (got_size > wanted_size) 3866141cc406Sopenharmony_ci { 3867141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, 3868141cc406Sopenharmony_ci "got more data than wanted (%lu vs %lu)\n", 3869141cc406Sopenharmony_ci got_size, wanted_size); 3870141cc406Sopenharmony_ci free(got_data); 3871141cc406Sopenharmony_ci sanei_usb_record_replace_read_bulk(node, dn, NULL, 0, wanted_size); 3872141cc406Sopenharmony_ci return -1; 3873141cc406Sopenharmony_ci } 3874141cc406Sopenharmony_ci 3875141cc406Sopenharmony_ci memcpy(buffer + total_got_size, got_data, got_size); 3876141cc406Sopenharmony_ci free(got_data); 3877141cc406Sopenharmony_ci total_got_size += got_size; 3878141cc406Sopenharmony_ci wanted_size -= got_size; 3879141cc406Sopenharmony_ci 3880141cc406Sopenharmony_ci int next_size = sanei_usb_replay_next_read_bulk_packet_size(dn); 3881141cc406Sopenharmony_ci if (next_size < 0) 3882141cc406Sopenharmony_ci return total_got_size; 3883141cc406Sopenharmony_ci if ((size_t) next_size > wanted_size) 3884141cc406Sopenharmony_ci return total_got_size; 3885141cc406Sopenharmony_ci } 3886141cc406Sopenharmony_ci return total_got_size; 3887141cc406Sopenharmony_ci} 3888141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 3889141cc406Sopenharmony_ci 3890141cc406Sopenharmony_ciSANE_Status 3891141cc406Sopenharmony_cisanei_usb_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) 3892141cc406Sopenharmony_ci{ 3893141cc406Sopenharmony_ci ssize_t read_size = 0; 3894141cc406Sopenharmony_ci 3895141cc406Sopenharmony_ci if (!size) 3896141cc406Sopenharmony_ci { 3897141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: size == NULL\n"); 3898141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3899141cc406Sopenharmony_ci } 3900141cc406Sopenharmony_ci 3901141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 3902141cc406Sopenharmony_ci { 3903141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: dn >= device number || dn < 0\n"); 3904141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3905141cc406Sopenharmony_ci } 3906141cc406Sopenharmony_ci DBG (5, "sanei_usb_read_bulk: trying to read %lu bytes\n", 3907141cc406Sopenharmony_ci (unsigned long) *size); 3908141cc406Sopenharmony_ci 3909141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 3910141cc406Sopenharmony_ci { 3911141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 3912141cc406Sopenharmony_ci read_size = sanei_usb_replay_read_bulk(dn, buffer, *size); 3913141cc406Sopenharmony_ci#else 3914141cc406Sopenharmony_ci DBG(1, "%s: USB record-replay mode support missing\n", __func__); 3915141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 3916141cc406Sopenharmony_ci#endif 3917141cc406Sopenharmony_ci } 3918141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 3919141cc406Sopenharmony_ci { 3920141cc406Sopenharmony_ci read_size = read (devices[dn].fd, buffer, *size); 3921141cc406Sopenharmony_ci 3922141cc406Sopenharmony_ci if (read_size < 0) 3923141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: read failed: %s\n", 3924141cc406Sopenharmony_ci strerror (errno)); 3925141cc406Sopenharmony_ci } 3926141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 3927141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 3928141cc406Sopenharmony_ci { 3929141cc406Sopenharmony_ci if (devices[dn].bulk_in_ep) 3930141cc406Sopenharmony_ci { 3931141cc406Sopenharmony_ci read_size = usb_bulk_read (devices[dn].libusb_handle, 3932141cc406Sopenharmony_ci devices[dn].bulk_in_ep, (char *) buffer, 3933141cc406Sopenharmony_ci (int) *size, libusb_timeout); 3934141cc406Sopenharmony_ci 3935141cc406Sopenharmony_ci if (read_size < 0) 3936141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: read failed: %s\n", 3937141cc406Sopenharmony_ci strerror (errno)); 3938141cc406Sopenharmony_ci } 3939141cc406Sopenharmony_ci else 3940141cc406Sopenharmony_ci { 3941141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in " 3942141cc406Sopenharmony_ci "endpoint\n"); 3943141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3944141cc406Sopenharmony_ci } 3945141cc406Sopenharmony_ci } 3946141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 3947141cc406Sopenharmony_ci { 3948141cc406Sopenharmony_ci if (devices[dn].bulk_in_ep) 3949141cc406Sopenharmony_ci { 3950141cc406Sopenharmony_ci int ret, rsize; 3951141cc406Sopenharmony_ci ret = libusb_bulk_transfer (devices[dn].lu_handle, 3952141cc406Sopenharmony_ci devices[dn].bulk_in_ep, buffer, 3953141cc406Sopenharmony_ci (int) *size, &rsize, 3954141cc406Sopenharmony_ci libusb_timeout); 3955141cc406Sopenharmony_ci 3956141cc406Sopenharmony_ci if (ret < 0) 3957141cc406Sopenharmony_ci { 3958141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: read failed (still got %d bytes): %s\n", 3959141cc406Sopenharmony_ci rsize, sanei_libusb_strerror (ret)); 3960141cc406Sopenharmony_ci 3961141cc406Sopenharmony_ci read_size = -1; 3962141cc406Sopenharmony_ci } 3963141cc406Sopenharmony_ci else 3964141cc406Sopenharmony_ci { 3965141cc406Sopenharmony_ci read_size = rsize; 3966141cc406Sopenharmony_ci } 3967141cc406Sopenharmony_ci } 3968141cc406Sopenharmony_ci else 3969141cc406Sopenharmony_ci { 3970141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in " 3971141cc406Sopenharmony_ci "endpoint\n"); 3972141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 3973141cc406Sopenharmony_ci } 3974141cc406Sopenharmony_ci } 3975141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 3976141cc406Sopenharmony_ci { 3977141cc406Sopenharmony_ci if (devices[dn].bulk_in_ep) 3978141cc406Sopenharmony_ci { 3979141cc406Sopenharmony_ci int ret, rsize; 3980141cc406Sopenharmony_ci ret = usb_manager_bulk_transfer (devices[dn].usb_manager_handle, 3981141cc406Sopenharmony_ci devices[dn].bulk_in_ep, buffer, 3982141cc406Sopenharmony_ci (int) *size, &rsize, 3983141cc406Sopenharmony_ci usb_manager_timeout); 3984141cc406Sopenharmony_ci 3985141cc406Sopenharmony_ci if (ret < 0) 3986141cc406Sopenharmony_ci { 3987141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: read failed (still got %d bytes): %s\n", 3988141cc406Sopenharmony_ci rsize, sanei_usb_manager_strerror (ret)); 3989141cc406Sopenharmony_ci 3990141cc406Sopenharmony_ci read_size = -1; 3991141cc406Sopenharmony_ci } 3992141cc406Sopenharmony_ci else 3993141cc406Sopenharmony_ci { 3994141cc406Sopenharmony_ci read_size = rsize; 3995141cc406Sopenharmony_ci } 3996141cc406Sopenharmony_ci } 3997141cc406Sopenharmony_ci else 3998141cc406Sopenharmony_ci { 3999141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in " 4000141cc406Sopenharmony_ci "endpoint\n"); 4001141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4002141cc406Sopenharmony_ci } 4003141cc406Sopenharmony_ci } 4004141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 4005141cc406Sopenharmony_ci { 4006141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: libusb support missing\n"); 4007141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4008141cc406Sopenharmony_ci } 4009141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY */ 4010141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_usbcalls) 4011141cc406Sopenharmony_ci { 4012141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 4013141cc406Sopenharmony_ci int rc; 4014141cc406Sopenharmony_ci char* buffer_ptr = (char*) buffer; 4015141cc406Sopenharmony_ci size_t requested_size = *size; 4016141cc406Sopenharmony_ci while (requested_size) 4017141cc406Sopenharmony_ci { 4018141cc406Sopenharmony_ci ULONG ulToRead = (requested_size>MAX_RW)?MAX_RW:requested_size; 4019141cc406Sopenharmony_ci ULONG ulNum = ulToRead; 4020141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkRead with dn = %d\n",dn); 4021141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkRead with dh = %p\n",dh); 4022141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkRead with bulk_in_ep = 0x%02x\n",devices[dn].bulk_in_ep); 4023141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkRead with interface_nr = %d\n",devices[dn].interface_nr); 4024141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkRead with usbcalls_timeout = %d\n",usbcalls_timeout); 4025141cc406Sopenharmony_ci 4026141cc406Sopenharmony_ci if (devices[dn].bulk_in_ep){ 4027141cc406Sopenharmony_ci rc = UsbBulkRead (dh, devices[dn].bulk_in_ep, devices[dn].interface_nr, 4028141cc406Sopenharmony_ci &ulToRead, buffer_ptr, usbcalls_timeout); 4029141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: rc = %d\n",rc);} 4030141cc406Sopenharmony_ci else 4031141cc406Sopenharmony_ci { 4032141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in endpoint\n"); 4033141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4034141cc406Sopenharmony_ci } 4035141cc406Sopenharmony_ci if (rc || (ulNum!=ulToRead)) return SANE_STATUS_INVAL; 4036141cc406Sopenharmony_ci requested_size -=ulToRead; 4037141cc406Sopenharmony_ci buffer_ptr += ulToRead; 4038141cc406Sopenharmony_ci read_size += ulToRead; 4039141cc406Sopenharmony_ci } 4040141cc406Sopenharmony_ci#else /* not HAVE_USBCALLS */ 4041141cc406Sopenharmony_ci { 4042141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: usbcalls support missing\n"); 4043141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4044141cc406Sopenharmony_ci } 4045141cc406Sopenharmony_ci#endif /* not HAVE_USBCALLS */ 4046141cc406Sopenharmony_ci } 4047141cc406Sopenharmony_ci else 4048141cc406Sopenharmony_ci { 4049141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_bulk: access method %d not implemented\n", 4050141cc406Sopenharmony_ci devices[dn].method); 4051141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4052141cc406Sopenharmony_ci } 4053141cc406Sopenharmony_ci 4054141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 4055141cc406Sopenharmony_ci { 4056141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4057141cc406Sopenharmony_ci sanei_usb_record_read_bulk(NULL, dn, buffer, *size, read_size); 4058141cc406Sopenharmony_ci#else 4059141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 4060141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4061141cc406Sopenharmony_ci#endif 4062141cc406Sopenharmony_ci } 4063141cc406Sopenharmony_ci 4064141cc406Sopenharmony_ci if (read_size < 0) 4065141cc406Sopenharmony_ci { 4066141cc406Sopenharmony_ci *size = 0; 4067141cc406Sopenharmony_ci if (testing_mode != sanei_usb_testing_mode_disabled) 4068141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4069141cc406Sopenharmony_ci 4070141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 4071141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_libusb) 4072141cc406Sopenharmony_ci usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_in_ep); 4073141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 4074141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_libusb) 4075141cc406Sopenharmony_ci libusb_clear_halt (devices[dn].lu_handle, devices[dn].bulk_in_ep); 4076141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 4077141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_usb_manager) 4078141cc406Sopenharmony_ci usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_in_ep); 4079141cc406Sopenharmony_ci#endif 4080141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4081141cc406Sopenharmony_ci } 4082141cc406Sopenharmony_ci if (read_size == 0) 4083141cc406Sopenharmony_ci { 4084141cc406Sopenharmony_ci DBG (3, "sanei_usb_read_bulk: read returned EOF\n"); 4085141cc406Sopenharmony_ci *size = 0; 4086141cc406Sopenharmony_ci return SANE_STATUS_EOF; 4087141cc406Sopenharmony_ci } 4088141cc406Sopenharmony_ci if (debug_level > 10) 4089141cc406Sopenharmony_ci print_buffer (buffer, read_size); 4090141cc406Sopenharmony_ci DBG (5, "sanei_usb_read_bulk: wanted %lu bytes, got %ld bytes\n", 4091141cc406Sopenharmony_ci (unsigned long) *size, (unsigned long) read_size); 4092141cc406Sopenharmony_ci *size = read_size; 4093141cc406Sopenharmony_ci 4094141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 4095141cc406Sopenharmony_ci} 4096141cc406Sopenharmony_ci 4097141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4098141cc406Sopenharmony_cistatic int sanei_usb_record_write_bulk(xmlNode* node, SANE_Int dn, 4099141cc406Sopenharmony_ci const SANE_Byte* buffer, 4100141cc406Sopenharmony_ci size_t size, size_t write_size) 4101141cc406Sopenharmony_ci{ 4102141cc406Sopenharmony_ci int node_was_null = node == NULL; 4103141cc406Sopenharmony_ci if (node_was_null) 4104141cc406Sopenharmony_ci node = testing_append_commands_node; 4105141cc406Sopenharmony_ci 4106141cc406Sopenharmony_ci xmlNode* e_tx = xmlNewNode(NULL, (const xmlChar*)"bulk_tx"); 4107141cc406Sopenharmony_ci sanei_xml_command_common_props(e_tx, devices[dn].bulk_out_ep & 0x0f, "OUT"); 4108141cc406Sopenharmony_ci sanei_xml_set_hex_data(e_tx, (const char*)buffer, size); 4109141cc406Sopenharmony_ci // FIXME: output write_size 4110141cc406Sopenharmony_ci 4111141cc406Sopenharmony_ci node = sanei_xml_append_command(node, node_was_null, e_tx); 4112141cc406Sopenharmony_ci 4113141cc406Sopenharmony_ci if (node_was_null) 4114141cc406Sopenharmony_ci testing_append_commands_node = node; 4115141cc406Sopenharmony_ci return write_size; 4116141cc406Sopenharmony_ci} 4117141cc406Sopenharmony_ci 4118141cc406Sopenharmony_cistatic void sanei_usb_record_replace_write_bulk(xmlNode* node, SANE_Int dn, 4119141cc406Sopenharmony_ci const SANE_Byte* buffer, 4120141cc406Sopenharmony_ci size_t size, size_t write_size) 4121141cc406Sopenharmony_ci{ 4122141cc406Sopenharmony_ci if (!testing_development_mode) 4123141cc406Sopenharmony_ci return; 4124141cc406Sopenharmony_ci testing_last_known_seq--; 4125141cc406Sopenharmony_ci sanei_usb_record_write_bulk(node, dn, buffer, size, write_size); 4126141cc406Sopenharmony_ci xmlUnlinkNode(node); 4127141cc406Sopenharmony_ci xmlFreeNode(node); 4128141cc406Sopenharmony_ci} 4129141cc406Sopenharmony_ci 4130141cc406Sopenharmony_ci// returns non-negative value on success, -1 on failure 4131141cc406Sopenharmony_cistatic int sanei_usb_replay_next_write_bulk_packet_size(SANE_Int dn) 4132141cc406Sopenharmony_ci{ 4133141cc406Sopenharmony_ci xmlNode* node = sanei_xml_peek_next_tx_node(); 4134141cc406Sopenharmony_ci if (node == NULL) 4135141cc406Sopenharmony_ci return -1; 4136141cc406Sopenharmony_ci 4137141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"bulk_tx") != 0) 4138141cc406Sopenharmony_ci { 4139141cc406Sopenharmony_ci return -1; 4140141cc406Sopenharmony_ci } 4141141cc406Sopenharmony_ci 4142141cc406Sopenharmony_ci if (!sanei_usb_attr_is(node, "direction", "OUT")) 4143141cc406Sopenharmony_ci return -1; 4144141cc406Sopenharmony_ci if (!sanei_usb_attr_is_uint(node, "endpoint_number", 4145141cc406Sopenharmony_ci devices[dn].bulk_out_ep & 0x0f)) 4146141cc406Sopenharmony_ci return -1; 4147141cc406Sopenharmony_ci 4148141cc406Sopenharmony_ci size_t got_size = 0; 4149141cc406Sopenharmony_ci char* got_data = sanei_xml_get_hex_data(node, &got_size); 4150141cc406Sopenharmony_ci free(got_data); 4151141cc406Sopenharmony_ci return got_size; 4152141cc406Sopenharmony_ci} 4153141cc406Sopenharmony_ci 4154141cc406Sopenharmony_cistatic int sanei_usb_replay_write_bulk(SANE_Int dn, const SANE_Byte* buffer, 4155141cc406Sopenharmony_ci size_t size) 4156141cc406Sopenharmony_ci{ 4157141cc406Sopenharmony_ci size_t wanted_size = size; 4158141cc406Sopenharmony_ci size_t total_wrote_size = 0; 4159141cc406Sopenharmony_ci while (wanted_size > 0) 4160141cc406Sopenharmony_ci { 4161141cc406Sopenharmony_ci if (testing_known_commands_input_failed) 4162141cc406Sopenharmony_ci return -1; 4163141cc406Sopenharmony_ci 4164141cc406Sopenharmony_ci xmlNode* node = sanei_xml_get_next_tx_node(); 4165141cc406Sopenharmony_ci if (node == NULL) 4166141cc406Sopenharmony_ci { 4167141cc406Sopenharmony_ci FAIL_TEST(__func__, "no more transactions\n"); 4168141cc406Sopenharmony_ci return -1; 4169141cc406Sopenharmony_ci } 4170141cc406Sopenharmony_ci 4171141cc406Sopenharmony_ci if (sanei_xml_is_known_commands_end(node)) 4172141cc406Sopenharmony_ci { 4173141cc406Sopenharmony_ci sanei_usb_record_write_bulk(NULL, dn, buffer, size, size); 4174141cc406Sopenharmony_ci return size; 4175141cc406Sopenharmony_ci } 4176141cc406Sopenharmony_ci 4177141cc406Sopenharmony_ci sanei_xml_record_seq(node); 4178141cc406Sopenharmony_ci sanei_xml_break_if_needed(node); 4179141cc406Sopenharmony_ci 4180141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"bulk_tx") != 0) 4181141cc406Sopenharmony_ci { 4182141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", 4183141cc406Sopenharmony_ci (const char*) node->name); 4184141cc406Sopenharmony_ci sanei_usb_record_replace_write_bulk(node, dn, buffer, size, size); 4185141cc406Sopenharmony_ci return -1; 4186141cc406Sopenharmony_ci } 4187141cc406Sopenharmony_ci 4188141cc406Sopenharmony_ci if (!sanei_usb_check_attr(node, "direction", "OUT", __func__)) 4189141cc406Sopenharmony_ci { 4190141cc406Sopenharmony_ci sanei_usb_record_replace_write_bulk(node, dn, buffer, size, size); 4191141cc406Sopenharmony_ci return -1; 4192141cc406Sopenharmony_ci } 4193141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "endpoint_number", 4194141cc406Sopenharmony_ci devices[dn].bulk_out_ep & 0x0f, 4195141cc406Sopenharmony_ci __func__)) 4196141cc406Sopenharmony_ci { 4197141cc406Sopenharmony_ci sanei_usb_record_replace_write_bulk(node, dn, buffer, size, size); 4198141cc406Sopenharmony_ci return -1; 4199141cc406Sopenharmony_ci } 4200141cc406Sopenharmony_ci 4201141cc406Sopenharmony_ci size_t wrote_size = 0; 4202141cc406Sopenharmony_ci char* wrote_data = sanei_xml_get_hex_data(node, &wrote_size); 4203141cc406Sopenharmony_ci 4204141cc406Sopenharmony_ci if (wrote_size > wanted_size) 4205141cc406Sopenharmony_ci { 4206141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, 4207141cc406Sopenharmony_ci "wrote more data than wanted (%lu vs %lu)\n", 4208141cc406Sopenharmony_ci wrote_size, wanted_size); 4209141cc406Sopenharmony_ci if (!testing_development_mode) 4210141cc406Sopenharmony_ci { 4211141cc406Sopenharmony_ci free(wrote_data); 4212141cc406Sopenharmony_ci return -1; 4213141cc406Sopenharmony_ci } 4214141cc406Sopenharmony_ci sanei_usb_record_replace_write_bulk(node, dn, buffer, size, size); 4215141cc406Sopenharmony_ci wrote_size = size; 4216141cc406Sopenharmony_ci } 4217141cc406Sopenharmony_ci else if (!sanei_usb_check_data_equal(node, 4218141cc406Sopenharmony_ci ((const char*) buffer) + 4219141cc406Sopenharmony_ci total_wrote_size, 4220141cc406Sopenharmony_ci wrote_size, 4221141cc406Sopenharmony_ci wrote_data, wrote_size, 4222141cc406Sopenharmony_ci __func__)) 4223141cc406Sopenharmony_ci { 4224141cc406Sopenharmony_ci if (!testing_development_mode) 4225141cc406Sopenharmony_ci { 4226141cc406Sopenharmony_ci free(wrote_data); 4227141cc406Sopenharmony_ci return -1; 4228141cc406Sopenharmony_ci } 4229141cc406Sopenharmony_ci sanei_usb_record_replace_write_bulk(node, dn, buffer, size, 4230141cc406Sopenharmony_ci size); 4231141cc406Sopenharmony_ci wrote_size = size; 4232141cc406Sopenharmony_ci } 4233141cc406Sopenharmony_ci 4234141cc406Sopenharmony_ci free(wrote_data); 4235141cc406Sopenharmony_ci if (wrote_size < wanted_size && 4236141cc406Sopenharmony_ci sanei_usb_replay_next_write_bulk_packet_size(dn) < 0) 4237141cc406Sopenharmony_ci { 4238141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, 4239141cc406Sopenharmony_ci "wrote less data than wanted (%lu vs %lu)\n", 4240141cc406Sopenharmony_ci wrote_size, wanted_size); 4241141cc406Sopenharmony_ci if (!testing_development_mode) 4242141cc406Sopenharmony_ci { 4243141cc406Sopenharmony_ci return -1; 4244141cc406Sopenharmony_ci } 4245141cc406Sopenharmony_ci sanei_usb_record_replace_write_bulk(node, dn, buffer, size, 4246141cc406Sopenharmony_ci size); 4247141cc406Sopenharmony_ci wrote_size = size; 4248141cc406Sopenharmony_ci } 4249141cc406Sopenharmony_ci total_wrote_size += wrote_size; 4250141cc406Sopenharmony_ci wanted_size -= wrote_size; 4251141cc406Sopenharmony_ci } 4252141cc406Sopenharmony_ci return total_wrote_size; 4253141cc406Sopenharmony_ci} 4254141cc406Sopenharmony_ci#endif 4255141cc406Sopenharmony_ci 4256141cc406Sopenharmony_ciSANE_Status 4257141cc406Sopenharmony_cisanei_usb_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size) 4258141cc406Sopenharmony_ci{ 4259141cc406Sopenharmony_ci ssize_t write_size = 0; 4260141cc406Sopenharmony_ci 4261141cc406Sopenharmony_ci if (!size) 4262141cc406Sopenharmony_ci { 4263141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: size == NULL\n"); 4264141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4265141cc406Sopenharmony_ci } 4266141cc406Sopenharmony_ci 4267141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 4268141cc406Sopenharmony_ci { 4269141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: dn >= device number || dn < 0\n"); 4270141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4271141cc406Sopenharmony_ci } 4272141cc406Sopenharmony_ci DBG (5, "sanei_usb_write_bulk: trying to write %lu bytes\n", 4273141cc406Sopenharmony_ci (unsigned long) *size); 4274141cc406Sopenharmony_ci if (debug_level > 10) 4275141cc406Sopenharmony_ci print_buffer (buffer, *size); 4276141cc406Sopenharmony_ci 4277141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 4278141cc406Sopenharmony_ci { 4279141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4280141cc406Sopenharmony_ci write_size = sanei_usb_replay_write_bulk(dn, buffer, *size); 4281141cc406Sopenharmony_ci#else 4282141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 4283141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4284141cc406Sopenharmony_ci#endif 4285141cc406Sopenharmony_ci } 4286141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 4287141cc406Sopenharmony_ci { 4288141cc406Sopenharmony_ci write_size = write (devices[dn].fd, buffer, *size); 4289141cc406Sopenharmony_ci 4290141cc406Sopenharmony_ci if (write_size < 0) 4291141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: write failed: %s\n", 4292141cc406Sopenharmony_ci strerror (errno)); 4293141cc406Sopenharmony_ci } 4294141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 4295141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 4296141cc406Sopenharmony_ci { 4297141cc406Sopenharmony_ci if (devices[dn].bulk_out_ep) 4298141cc406Sopenharmony_ci { 4299141cc406Sopenharmony_ci write_size = usb_bulk_write (devices[dn].libusb_handle, 4300141cc406Sopenharmony_ci devices[dn].bulk_out_ep, 4301141cc406Sopenharmony_ci (const char *) buffer, 4302141cc406Sopenharmony_ci (int) *size, libusb_timeout); 4303141cc406Sopenharmony_ci if (write_size < 0) 4304141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: write failed: %s\n", 4305141cc406Sopenharmony_ci strerror (errno)); 4306141cc406Sopenharmony_ci } 4307141cc406Sopenharmony_ci else 4308141cc406Sopenharmony_ci { 4309141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: can't write without a bulk-out " 4310141cc406Sopenharmony_ci "endpoint\n"); 4311141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4312141cc406Sopenharmony_ci } 4313141cc406Sopenharmony_ci } 4314141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 4315141cc406Sopenharmony_ci { 4316141cc406Sopenharmony_ci if (devices[dn].bulk_out_ep) 4317141cc406Sopenharmony_ci { 4318141cc406Sopenharmony_ci int ret; 4319141cc406Sopenharmony_ci int trans_bytes; 4320141cc406Sopenharmony_ci ret = libusb_bulk_transfer (devices[dn].lu_handle, 4321141cc406Sopenharmony_ci devices[dn].bulk_out_ep, 4322141cc406Sopenharmony_ci (unsigned char *) buffer, 4323141cc406Sopenharmony_ci (int) *size, &trans_bytes, 4324141cc406Sopenharmony_ci libusb_timeout); 4325141cc406Sopenharmony_ci if (ret < 0) 4326141cc406Sopenharmony_ci { 4327141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: write failed: %s\n", 4328141cc406Sopenharmony_ci sanei_libusb_strerror (ret)); 4329141cc406Sopenharmony_ci 4330141cc406Sopenharmony_ci write_size = -1; 4331141cc406Sopenharmony_ci } 4332141cc406Sopenharmony_ci else 4333141cc406Sopenharmony_ci write_size = trans_bytes; 4334141cc406Sopenharmony_ci } 4335141cc406Sopenharmony_ci else 4336141cc406Sopenharmony_ci { 4337141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: can't write without a bulk-out " 4338141cc406Sopenharmony_ci "endpoint\n"); 4339141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4340141cc406Sopenharmony_ci } 4341141cc406Sopenharmony_ci } 4342141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 4343141cc406Sopenharmony_ci { 4344141cc406Sopenharmony_ci if (devices[dn].bulk_out_ep) 4345141cc406Sopenharmony_ci { 4346141cc406Sopenharmony_ci int ret; 4347141cc406Sopenharmony_ci int trans_bytes; 4348141cc406Sopenharmony_ci ret = usb_manager_bulk_transfer (devices[dn].usb_manager_handle, 4349141cc406Sopenharmony_ci devices[dn].bulk_out_ep, 4350141cc406Sopenharmony_ci (unsigned char *) buffer, 4351141cc406Sopenharmony_ci (int) *size, &trans_bytes, 4352141cc406Sopenharmony_ci usb_manager_timeout); 4353141cc406Sopenharmony_ci if (ret < 0) 4354141cc406Sopenharmony_ci { 4355141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: write failed: %s\n", 4356141cc406Sopenharmony_ci sanei_usb_manager_strerror (ret)); 4357141cc406Sopenharmony_ci 4358141cc406Sopenharmony_ci write_size = -1; 4359141cc406Sopenharmony_ci } 4360141cc406Sopenharmony_ci else 4361141cc406Sopenharmony_ci write_size = trans_bytes; 4362141cc406Sopenharmony_ci } 4363141cc406Sopenharmony_ci else 4364141cc406Sopenharmony_ci { 4365141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: can't write without a bulk-out " 4366141cc406Sopenharmony_ci "endpoint\n"); 4367141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4368141cc406Sopenharmony_ci } 4369141cc406Sopenharmony_ci } 4370141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 4371141cc406Sopenharmony_ci { 4372141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: libusb support missing\n"); 4373141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4374141cc406Sopenharmony_ci } 4375141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 4376141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_usbcalls) 4377141cc406Sopenharmony_ci { 4378141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 4379141cc406Sopenharmony_ci int rc; 4380141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkWrite with dn = %d\n",dn); 4381141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkWrite with dh = %p\n",dh); 4382141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkWrite with bulk_out_ep = 0x%02x\n",devices[dn].bulk_out_ep); 4383141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkWrite with interface_nr = %d\n",devices[dn].interface_nr); 4384141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbBulkWrite with usbcalls_timeout = %d\n",usbcalls_timeout); 4385141cc406Sopenharmony_ci size_t requested_size = *size; 4386141cc406Sopenharmony_ci while (requested_size) 4387141cc406Sopenharmony_ci { 4388141cc406Sopenharmony_ci ULONG ulToWrite = (requested_size>MAX_RW)?MAX_RW:requested_size; 4389141cc406Sopenharmony_ci 4390141cc406Sopenharmony_ci DBG (5, "size requested to write = %lu, ulToWrite = %lu\n",(unsigned long) requested_size,ulToWrite); 4391141cc406Sopenharmony_ci if (devices[dn].bulk_out_ep){ 4392141cc406Sopenharmony_ci rc = UsbBulkWrite (dh, devices[dn].bulk_out_ep, devices[dn].interface_nr, 4393141cc406Sopenharmony_ci ulToWrite, (char*) buffer, usbcalls_timeout); 4394141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: rc = %d\n",rc); 4395141cc406Sopenharmony_ci } 4396141cc406Sopenharmony_ci else 4397141cc406Sopenharmony_ci { 4398141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: can't read without a bulk-out endpoint\n"); 4399141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4400141cc406Sopenharmony_ci } 4401141cc406Sopenharmony_ci if (rc) return SANE_STATUS_INVAL; 4402141cc406Sopenharmony_ci requested_size -=ulToWrite; 4403141cc406Sopenharmony_ci buffer += ulToWrite; 4404141cc406Sopenharmony_ci write_size += ulToWrite; 4405141cc406Sopenharmony_ci DBG (5, "size = %d, write_size = %d\n", requested_size, write_size); 4406141cc406Sopenharmony_ci } 4407141cc406Sopenharmony_ci#else /* not HAVE_USBCALLS */ 4408141cc406Sopenharmony_ci { 4409141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: usbcalls support missing\n"); 4410141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4411141cc406Sopenharmony_ci } 4412141cc406Sopenharmony_ci#endif /* not HAVE_USBCALLS */ 4413141cc406Sopenharmony_ci } 4414141cc406Sopenharmony_ci else 4415141cc406Sopenharmony_ci { 4416141cc406Sopenharmony_ci DBG (1, "sanei_usb_write_bulk: access method %d not implemented\n", 4417141cc406Sopenharmony_ci devices[dn].method); 4418141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4419141cc406Sopenharmony_ci } 4420141cc406Sopenharmony_ci 4421141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 4422141cc406Sopenharmony_ci { 4423141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4424141cc406Sopenharmony_ci sanei_usb_record_write_bulk(NULL, dn, buffer, *size, write_size); 4425141cc406Sopenharmony_ci#else 4426141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 4427141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4428141cc406Sopenharmony_ci#endif 4429141cc406Sopenharmony_ci } 4430141cc406Sopenharmony_ci 4431141cc406Sopenharmony_ci if (write_size < 0) 4432141cc406Sopenharmony_ci { 4433141cc406Sopenharmony_ci *size = 0; 4434141cc406Sopenharmony_ci if (testing_mode != sanei_usb_testing_mode_disabled) 4435141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4436141cc406Sopenharmony_ci 4437141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 4438141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_libusb) 4439141cc406Sopenharmony_ci usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_out_ep); 4440141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 4441141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_libusb) 4442141cc406Sopenharmony_ci libusb_clear_halt (devices[dn].lu_handle, devices[dn].bulk_out_ep); 4443141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 4444141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_usb_manager) 4445141cc406Sopenharmony_ci usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_out_ep); 4446141cc406Sopenharmony_ci#endif 4447141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4448141cc406Sopenharmony_ci } 4449141cc406Sopenharmony_ci DBG (5, "sanei_usb_write_bulk: wanted %lu bytes, wrote %ld bytes\n", 4450141cc406Sopenharmony_ci (unsigned long) *size, (unsigned long) write_size); 4451141cc406Sopenharmony_ci *size = write_size; 4452141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 4453141cc406Sopenharmony_ci} 4454141cc406Sopenharmony_ci 4455141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4456141cc406Sopenharmony_cistatic void 4457141cc406Sopenharmony_cisanei_usb_record_control_msg(xmlNode* node, 4458141cc406Sopenharmony_ci SANE_Int dn, SANE_Int rtype, SANE_Int req, 4459141cc406Sopenharmony_ci SANE_Int value, SANE_Int index, SANE_Int len, 4460141cc406Sopenharmony_ci const SANE_Byte* data) 4461141cc406Sopenharmony_ci{ 4462141cc406Sopenharmony_ci (void) dn; 4463141cc406Sopenharmony_ci 4464141cc406Sopenharmony_ci int node_was_null = node == NULL; 4465141cc406Sopenharmony_ci if (node_was_null) 4466141cc406Sopenharmony_ci node = testing_append_commands_node; 4467141cc406Sopenharmony_ci 4468141cc406Sopenharmony_ci xmlNode* e_tx = xmlNewNode(NULL, (const xmlChar*)"control_tx"); 4469141cc406Sopenharmony_ci 4470141cc406Sopenharmony_ci int direction_is_in = (rtype & 0x80) == 0x80; 4471141cc406Sopenharmony_ci sanei_xml_command_common_props(e_tx, rtype & 0x1f, 4472141cc406Sopenharmony_ci direction_is_in ? "IN" : "OUT"); 4473141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "bmRequestType", rtype); 4474141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "bRequest", req); 4475141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "wValue", value); 4476141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "wIndex", index); 4477141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "wLength", len); 4478141cc406Sopenharmony_ci 4479141cc406Sopenharmony_ci if (direction_is_in && data == NULL) 4480141cc406Sopenharmony_ci { 4481141cc406Sopenharmony_ci const int buf_size = 128; 4482141cc406Sopenharmony_ci char buf[buf_size]; 4483141cc406Sopenharmony_ci snprintf(buf, buf_size, "(unknown read of size %d)", len); 4484141cc406Sopenharmony_ci xmlNode* e_content = xmlNewText((const xmlChar*)buf); 4485141cc406Sopenharmony_ci xmlAddChild(e_tx, e_content); 4486141cc406Sopenharmony_ci } 4487141cc406Sopenharmony_ci else 4488141cc406Sopenharmony_ci { 4489141cc406Sopenharmony_ci sanei_xml_set_hex_data(e_tx, (const char*)data, len); 4490141cc406Sopenharmony_ci } 4491141cc406Sopenharmony_ci 4492141cc406Sopenharmony_ci node = sanei_xml_append_command(node, node_was_null, e_tx); 4493141cc406Sopenharmony_ci 4494141cc406Sopenharmony_ci if (node_was_null) 4495141cc406Sopenharmony_ci testing_append_commands_node = node; 4496141cc406Sopenharmony_ci} 4497141cc406Sopenharmony_ci 4498141cc406Sopenharmony_ci 4499141cc406Sopenharmony_cistatic SANE_Status 4500141cc406Sopenharmony_cisanei_usb_record_replace_control_msg(xmlNode* node, 4501141cc406Sopenharmony_ci SANE_Int dn, SANE_Int rtype, SANE_Int req, 4502141cc406Sopenharmony_ci SANE_Int value, SANE_Int index, SANE_Int len, 4503141cc406Sopenharmony_ci const SANE_Byte* data) 4504141cc406Sopenharmony_ci{ 4505141cc406Sopenharmony_ci if (!testing_development_mode) 4506141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4507141cc406Sopenharmony_ci 4508141cc406Sopenharmony_ci SANE_Status ret = SANE_STATUS_GOOD; 4509141cc406Sopenharmony_ci int direction_is_in = (rtype & 0x80) == 0x80; 4510141cc406Sopenharmony_ci if (direction_is_in) 4511141cc406Sopenharmony_ci { 4512141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 4513141cc406Sopenharmony_ci ret = SANE_STATUS_IO_ERROR; 4514141cc406Sopenharmony_ci } 4515141cc406Sopenharmony_ci 4516141cc406Sopenharmony_ci testing_last_known_seq--; 4517141cc406Sopenharmony_ci sanei_usb_record_control_msg(node, dn, rtype, req, value, index, len, data); 4518141cc406Sopenharmony_ci xmlUnlinkNode(node); 4519141cc406Sopenharmony_ci xmlFreeNode(node); 4520141cc406Sopenharmony_ci return ret; 4521141cc406Sopenharmony_ci} 4522141cc406Sopenharmony_ci 4523141cc406Sopenharmony_cistatic SANE_Status 4524141cc406Sopenharmony_cisanei_usb_replay_control_msg(SANE_Int dn, SANE_Int rtype, SANE_Int req, 4525141cc406Sopenharmony_ci SANE_Int value, SANE_Int index, SANE_Int len, 4526141cc406Sopenharmony_ci SANE_Byte* data) 4527141cc406Sopenharmony_ci{ 4528141cc406Sopenharmony_ci (void) dn; 4529141cc406Sopenharmony_ci 4530141cc406Sopenharmony_ci if (testing_known_commands_input_failed) 4531141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4532141cc406Sopenharmony_ci 4533141cc406Sopenharmony_ci xmlNode* node = sanei_xml_get_next_tx_node(); 4534141cc406Sopenharmony_ci if (node == NULL) 4535141cc406Sopenharmony_ci { 4536141cc406Sopenharmony_ci FAIL_TEST(__func__, "no more transactions\n"); 4537141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4538141cc406Sopenharmony_ci } 4539141cc406Sopenharmony_ci 4540141cc406Sopenharmony_ci int direction_is_in = (rtype & 0x80) == 0x80; 4541141cc406Sopenharmony_ci SANE_Byte* rdata = direction_is_in ? NULL : data; 4542141cc406Sopenharmony_ci 4543141cc406Sopenharmony_ci if (sanei_xml_is_known_commands_end(node)) 4544141cc406Sopenharmony_ci { 4545141cc406Sopenharmony_ci sanei_usb_record_control_msg(NULL, dn, rtype, req, value, index, len, 4546141cc406Sopenharmony_ci rdata); 4547141cc406Sopenharmony_ci if (direction_is_in) 4548141cc406Sopenharmony_ci { 4549141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 4550141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4551141cc406Sopenharmony_ci } 4552141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 4553141cc406Sopenharmony_ci } 4554141cc406Sopenharmony_ci 4555141cc406Sopenharmony_ci sanei_xml_record_seq(node); 4556141cc406Sopenharmony_ci sanei_xml_break_if_needed(node); 4557141cc406Sopenharmony_ci 4558141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"control_tx") != 0) 4559141cc406Sopenharmony_ci { 4560141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", 4561141cc406Sopenharmony_ci (const char*) node->name); 4562141cc406Sopenharmony_ci return sanei_usb_record_replace_control_msg(node, dn, rtype, req, value, 4563141cc406Sopenharmony_ci index, len, rdata); 4564141cc406Sopenharmony_ci } 4565141cc406Sopenharmony_ci 4566141cc406Sopenharmony_ci if (!sanei_usb_check_attr(node, "direction", direction_is_in ? "IN" : "OUT", 4567141cc406Sopenharmony_ci __func__) || 4568141cc406Sopenharmony_ci !sanei_usb_check_attr_uint(node, "bmRequestType", rtype, __func__) || 4569141cc406Sopenharmony_ci !sanei_usb_check_attr_uint(node, "bRequest", req, __func__) || 4570141cc406Sopenharmony_ci !sanei_usb_check_attr_uint(node, "wValue", value, __func__) || 4571141cc406Sopenharmony_ci !sanei_usb_check_attr_uint(node, "wIndex", index, __func__) || 4572141cc406Sopenharmony_ci !sanei_usb_check_attr_uint(node, "wLength", len, __func__)) 4573141cc406Sopenharmony_ci { 4574141cc406Sopenharmony_ci return sanei_usb_record_replace_control_msg(node, dn, rtype, req, value, 4575141cc406Sopenharmony_ci index, len, rdata); 4576141cc406Sopenharmony_ci } 4577141cc406Sopenharmony_ci 4578141cc406Sopenharmony_ci size_t tx_data_size = 0; 4579141cc406Sopenharmony_ci char* tx_data = sanei_xml_get_hex_data(node, &tx_data_size); 4580141cc406Sopenharmony_ci 4581141cc406Sopenharmony_ci if (direction_is_in) 4582141cc406Sopenharmony_ci { 4583141cc406Sopenharmony_ci if (tx_data_size != (size_t)len) 4584141cc406Sopenharmony_ci { 4585141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, 4586141cc406Sopenharmony_ci "got different amount of data than wanted (%lu vs %lu)\n", 4587141cc406Sopenharmony_ci tx_data_size, (size_t)len); 4588141cc406Sopenharmony_ci free(tx_data); 4589141cc406Sopenharmony_ci return sanei_usb_record_replace_control_msg(node, dn, rtype, req, 4590141cc406Sopenharmony_ci value, index, len, rdata); 4591141cc406Sopenharmony_ci } 4592141cc406Sopenharmony_ci memcpy(data, tx_data, tx_data_size); 4593141cc406Sopenharmony_ci } 4594141cc406Sopenharmony_ci else 4595141cc406Sopenharmony_ci { 4596141cc406Sopenharmony_ci if (!sanei_usb_check_data_equal(node, 4597141cc406Sopenharmony_ci (const char*)data, len, 4598141cc406Sopenharmony_ci tx_data, tx_data_size, __func__)) 4599141cc406Sopenharmony_ci { 4600141cc406Sopenharmony_ci free(tx_data); 4601141cc406Sopenharmony_ci return sanei_usb_record_replace_control_msg(node, dn, rtype, req, 4602141cc406Sopenharmony_ci value, index, len, rdata); 4603141cc406Sopenharmony_ci } 4604141cc406Sopenharmony_ci } 4605141cc406Sopenharmony_ci free(tx_data); 4606141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 4607141cc406Sopenharmony_ci} 4608141cc406Sopenharmony_ci#endif 4609141cc406Sopenharmony_ci 4610141cc406Sopenharmony_ciSANE_Status 4611141cc406Sopenharmony_cisanei_usb_control_msg (SANE_Int dn, SANE_Int rtype, SANE_Int req, 4612141cc406Sopenharmony_ci SANE_Int value, SANE_Int index, SANE_Int len, 4613141cc406Sopenharmony_ci SANE_Byte * data) 4614141cc406Sopenharmony_ci{ 4615141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 4616141cc406Sopenharmony_ci { 4617141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: dn >= device number || dn < 0, dn=%d\n", 4618141cc406Sopenharmony_ci dn); 4619141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4620141cc406Sopenharmony_ci } 4621141cc406Sopenharmony_ci 4622141cc406Sopenharmony_ci DBG (5, "sanei_usb_control_msg: rtype = 0x%02x, req = %d, value = %d, " 4623141cc406Sopenharmony_ci "index = %d, len = %d\n", rtype, req, value, index, len); 4624141cc406Sopenharmony_ci if (!(rtype & 0x80) && debug_level > 10) 4625141cc406Sopenharmony_ci print_buffer (data, len); 4626141cc406Sopenharmony_ci 4627141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 4628141cc406Sopenharmony_ci { 4629141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4630141cc406Sopenharmony_ci return sanei_usb_replay_control_msg(dn, rtype, req, value, index, len, 4631141cc406Sopenharmony_ci data); 4632141cc406Sopenharmony_ci#else 4633141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 4634141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4635141cc406Sopenharmony_ci#endif 4636141cc406Sopenharmony_ci } 4637141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_scanner_driver) 4638141cc406Sopenharmony_ci { 4639141cc406Sopenharmony_ci#if defined(__linux__) 4640141cc406Sopenharmony_ci struct ctrlmsg_ioctl c; 4641141cc406Sopenharmony_ci 4642141cc406Sopenharmony_ci c.req.requesttype = rtype; 4643141cc406Sopenharmony_ci c.req.request = req; 4644141cc406Sopenharmony_ci c.req.value = value; 4645141cc406Sopenharmony_ci c.req.index = index; 4646141cc406Sopenharmony_ci c.req.length = len; 4647141cc406Sopenharmony_ci c.data = data; 4648141cc406Sopenharmony_ci 4649141cc406Sopenharmony_ci if (ioctl (devices[dn].fd, SCANNER_IOCTL_CTRLMSG, &c) < 0) 4650141cc406Sopenharmony_ci { 4651141cc406Sopenharmony_ci DBG (5, "sanei_usb_control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n", 4652141cc406Sopenharmony_ci strerror (errno)); 4653141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4654141cc406Sopenharmony_ci } 4655141cc406Sopenharmony_ci if ((rtype & 0x80) && debug_level > 10) 4656141cc406Sopenharmony_ci print_buffer (data, len); 4657141cc406Sopenharmony_ci#elif defined(__BEOS__) 4658141cc406Sopenharmony_ci struct usb_scanner_ioctl_ctrlmsg c; 4659141cc406Sopenharmony_ci 4660141cc406Sopenharmony_ci c.req.request_type = rtype; 4661141cc406Sopenharmony_ci c.req.request = req; 4662141cc406Sopenharmony_ci c.req.value = value; 4663141cc406Sopenharmony_ci c.req.index = index; 4664141cc406Sopenharmony_ci c.req.length = len; 4665141cc406Sopenharmony_ci c.data = data; 4666141cc406Sopenharmony_ci 4667141cc406Sopenharmony_ci if (ioctl (devices[dn].fd, B_SCANNER_IOCTL_CTRLMSG, &c) < 0) 4668141cc406Sopenharmony_ci { 4669141cc406Sopenharmony_ci DBG (5, "sanei_usb_control_msg: SCANNER_IOCTL_CTRLMSG error - %s\n", 4670141cc406Sopenharmony_ci strerror (errno)); 4671141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 4672141cc406Sopenharmony_ci } 4673141cc406Sopenharmony_ci if ((rtype & 0x80) && debug_level > 10) 4674141cc406Sopenharmony_ci print_buffer (data, len); 4675141cc406Sopenharmony_ci#else /* not __linux__ */ 4676141cc406Sopenharmony_ci DBG (5, "sanei_usb_control_msg: not supported on this OS\n"); 4677141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4678141cc406Sopenharmony_ci#endif /* not __linux__ */ 4679141cc406Sopenharmony_ci } 4680141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 4681141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 4682141cc406Sopenharmony_ci { 4683141cc406Sopenharmony_ci int result; 4684141cc406Sopenharmony_ci 4685141cc406Sopenharmony_ci result = usb_control_msg (devices[dn].libusb_handle, rtype, req, 4686141cc406Sopenharmony_ci value, index, (char *) data, len, 4687141cc406Sopenharmony_ci libusb_timeout); 4688141cc406Sopenharmony_ci if (result < 0) 4689141cc406Sopenharmony_ci { 4690141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: libusb complained: %s\n", 4691141cc406Sopenharmony_ci usb_strerror ()); 4692141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4693141cc406Sopenharmony_ci } 4694141cc406Sopenharmony_ci if ((rtype & 0x80) && debug_level > 10) 4695141cc406Sopenharmony_ci print_buffer (data, len); 4696141cc406Sopenharmony_ci } 4697141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 4698141cc406Sopenharmony_ci { 4699141cc406Sopenharmony_ci int result; 4700141cc406Sopenharmony_ci 4701141cc406Sopenharmony_ci result = libusb_control_transfer (devices[dn].lu_handle, rtype, req, 4702141cc406Sopenharmony_ci value, index, data, len, 4703141cc406Sopenharmony_ci libusb_timeout); 4704141cc406Sopenharmony_ci if (result < 0) 4705141cc406Sopenharmony_ci { 4706141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: libusb complained: %s\n", 4707141cc406Sopenharmony_ci sanei_libusb_strerror (result)); 4708141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4709141cc406Sopenharmony_ci } 4710141cc406Sopenharmony_ci if ((rtype & 0x80) && debug_level > 10) 4711141cc406Sopenharmony_ci print_buffer (data, len); 4712141cc406Sopenharmony_ci } 4713141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 4714141cc406Sopenharmony_ci { 4715141cc406Sopenharmony_ci int result; 4716141cc406Sopenharmony_ci 4717141cc406Sopenharmony_ci result = usb_manager_control_transfer (devices[dn].usb_manager_handle, rtype, req, 4718141cc406Sopenharmony_ci value, index, data, len, 4719141cc406Sopenharmony_ci usb_manager_timeout); 4720141cc406Sopenharmony_ci if (result < 0) 4721141cc406Sopenharmony_ci { 4722141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: libusb complained: %s\n", 4723141cc406Sopenharmony_ci sanei_usb_manager_strerror (result)); 4724141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4725141cc406Sopenharmony_ci } 4726141cc406Sopenharmony_ci if ((rtype & 0x80) && debug_level > 10) 4727141cc406Sopenharmony_ci print_buffer (data, len); 4728141cc406Sopenharmony_ci } 4729141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ 4730141cc406Sopenharmony_ci { 4731141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: libusb support missing\n"); 4732141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4733141cc406Sopenharmony_ci } 4734141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 4735141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_usbcalls) 4736141cc406Sopenharmony_ci { 4737141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 4738141cc406Sopenharmony_ci int result; 4739141cc406Sopenharmony_ci 4740141cc406Sopenharmony_ci result = UsbCtrlMessage (dh, rtype, req, 4741141cc406Sopenharmony_ci value, index, len, (char *) data, 4742141cc406Sopenharmony_ci usbcalls_timeout); 4743141cc406Sopenharmony_ci DBG (5, "rc of usb_control_msg = %d\n",result); 4744141cc406Sopenharmony_ci if (result < 0) 4745141cc406Sopenharmony_ci { 4746141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: usbcalls complained: %d\n",result); 4747141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4748141cc406Sopenharmony_ci } 4749141cc406Sopenharmony_ci if ((rtype & 0x80) && debug_level > 10) 4750141cc406Sopenharmony_ci print_buffer (data, len); 4751141cc406Sopenharmony_ci#else /* not HAVE_USBCALLS */ 4752141cc406Sopenharmony_ci { 4753141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: usbcalls support missing\n"); 4754141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4755141cc406Sopenharmony_ci } 4756141cc406Sopenharmony_ci#endif /* not HAVE_USBCALLS */ 4757141cc406Sopenharmony_ci } 4758141cc406Sopenharmony_ci else 4759141cc406Sopenharmony_ci { 4760141cc406Sopenharmony_ci DBG (1, "sanei_usb_control_msg: access method %d not implemented\n", 4761141cc406Sopenharmony_ci devices[dn].method); 4762141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4763141cc406Sopenharmony_ci } 4764141cc406Sopenharmony_ci 4765141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 4766141cc406Sopenharmony_ci { 4767141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4768141cc406Sopenharmony_ci // TODO: record in the error code path too 4769141cc406Sopenharmony_ci sanei_usb_record_control_msg(NULL, dn, rtype, req, value, index, len, 4770141cc406Sopenharmony_ci data); 4771141cc406Sopenharmony_ci#else 4772141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 4773141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4774141cc406Sopenharmony_ci#endif 4775141cc406Sopenharmony_ci } 4776141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 4777141cc406Sopenharmony_ci} 4778141cc406Sopenharmony_ci 4779141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4780141cc406Sopenharmony_cistatic void sanei_usb_record_read_int(xmlNode* node, 4781141cc406Sopenharmony_ci SANE_Int dn, SANE_Byte* buffer, 4782141cc406Sopenharmony_ci size_t size, ssize_t read_size) 4783141cc406Sopenharmony_ci{ 4784141cc406Sopenharmony_ci (void) size; 4785141cc406Sopenharmony_ci 4786141cc406Sopenharmony_ci int node_was_null = node == NULL; 4787141cc406Sopenharmony_ci if (node_was_null) 4788141cc406Sopenharmony_ci node = testing_append_commands_node; 4789141cc406Sopenharmony_ci 4790141cc406Sopenharmony_ci xmlNode* e_tx = xmlNewNode(NULL, (const xmlChar*)"interrupt_tx"); 4791141cc406Sopenharmony_ci 4792141cc406Sopenharmony_ci sanei_xml_command_common_props(e_tx, devices[dn].int_in_ep & 0x0f, "IN"); 4793141cc406Sopenharmony_ci 4794141cc406Sopenharmony_ci if (buffer == NULL) 4795141cc406Sopenharmony_ci { 4796141cc406Sopenharmony_ci const int buf_size = 128; 4797141cc406Sopenharmony_ci char buf[buf_size]; 4798141cc406Sopenharmony_ci snprintf(buf, buf_size, "(unknown read of wanted size %ld)", read_size); 4799141cc406Sopenharmony_ci xmlNode* e_content = xmlNewText((const xmlChar*)buf); 4800141cc406Sopenharmony_ci xmlAddChild(e_tx, e_content); 4801141cc406Sopenharmony_ci } 4802141cc406Sopenharmony_ci else 4803141cc406Sopenharmony_ci { 4804141cc406Sopenharmony_ci if (read_size >= 0) 4805141cc406Sopenharmony_ci { 4806141cc406Sopenharmony_ci sanei_xml_set_hex_data(e_tx, (const char*)buffer, read_size); 4807141cc406Sopenharmony_ci } 4808141cc406Sopenharmony_ci else 4809141cc406Sopenharmony_ci { 4810141cc406Sopenharmony_ci xmlNewProp(e_tx, (const xmlChar*)"error", (const xmlChar*)"timeout"); 4811141cc406Sopenharmony_ci } 4812141cc406Sopenharmony_ci } 4813141cc406Sopenharmony_ci 4814141cc406Sopenharmony_ci node = sanei_xml_append_command(node, node_was_null, e_tx); 4815141cc406Sopenharmony_ci 4816141cc406Sopenharmony_ci if (node_was_null) 4817141cc406Sopenharmony_ci testing_append_commands_node = node; 4818141cc406Sopenharmony_ci} 4819141cc406Sopenharmony_ci 4820141cc406Sopenharmony_cistatic void sanei_usb_record_replace_read_int(xmlNode* node, 4821141cc406Sopenharmony_ci SANE_Int dn, SANE_Byte* buffer, 4822141cc406Sopenharmony_ci size_t size, size_t read_size) 4823141cc406Sopenharmony_ci{ 4824141cc406Sopenharmony_ci if (!testing_development_mode) 4825141cc406Sopenharmony_ci return; 4826141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 4827141cc406Sopenharmony_ci testing_last_known_seq--; 4828141cc406Sopenharmony_ci sanei_usb_record_read_int(node, dn, buffer, size, read_size); 4829141cc406Sopenharmony_ci xmlUnlinkNode(node); 4830141cc406Sopenharmony_ci xmlFreeNode(node); 4831141cc406Sopenharmony_ci} 4832141cc406Sopenharmony_ci 4833141cc406Sopenharmony_cistatic int sanei_usb_replay_read_int(SANE_Int dn, SANE_Byte* buffer, 4834141cc406Sopenharmony_ci size_t size) 4835141cc406Sopenharmony_ci{ 4836141cc406Sopenharmony_ci if (testing_known_commands_input_failed) 4837141cc406Sopenharmony_ci return -1; 4838141cc406Sopenharmony_ci 4839141cc406Sopenharmony_ci size_t wanted_size = size; 4840141cc406Sopenharmony_ci 4841141cc406Sopenharmony_ci xmlNode* node = sanei_xml_get_next_tx_node(); 4842141cc406Sopenharmony_ci if (node == NULL) 4843141cc406Sopenharmony_ci { 4844141cc406Sopenharmony_ci FAIL_TEST(__func__, "no more transactions\n"); 4845141cc406Sopenharmony_ci return -1; 4846141cc406Sopenharmony_ci } 4847141cc406Sopenharmony_ci 4848141cc406Sopenharmony_ci if (sanei_xml_is_known_commands_end(node)) 4849141cc406Sopenharmony_ci { 4850141cc406Sopenharmony_ci sanei_usb_record_read_int(NULL, dn, NULL, 0, size); 4851141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 4852141cc406Sopenharmony_ci return -1; 4853141cc406Sopenharmony_ci } 4854141cc406Sopenharmony_ci 4855141cc406Sopenharmony_ci sanei_xml_record_seq(node); 4856141cc406Sopenharmony_ci sanei_xml_break_if_needed(node); 4857141cc406Sopenharmony_ci 4858141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"interrupt_tx") != 0) 4859141cc406Sopenharmony_ci { 4860141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", 4861141cc406Sopenharmony_ci (const char*) node->name); 4862141cc406Sopenharmony_ci sanei_usb_record_replace_read_int(node, dn, NULL, 0, size); 4863141cc406Sopenharmony_ci return -1; 4864141cc406Sopenharmony_ci } 4865141cc406Sopenharmony_ci 4866141cc406Sopenharmony_ci if (!sanei_usb_check_attr(node, "direction", "IN", __func__)) 4867141cc406Sopenharmony_ci { 4868141cc406Sopenharmony_ci sanei_usb_record_replace_read_int(node, dn, NULL, 0, size); 4869141cc406Sopenharmony_ci return -1; 4870141cc406Sopenharmony_ci } 4871141cc406Sopenharmony_ci 4872141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "endpoint_number", 4873141cc406Sopenharmony_ci devices[dn].int_in_ep & 0x0f, 4874141cc406Sopenharmony_ci __func__)) 4875141cc406Sopenharmony_ci { 4876141cc406Sopenharmony_ci sanei_usb_record_replace_read_int(node, dn, NULL, 0, size); 4877141cc406Sopenharmony_ci return -1; 4878141cc406Sopenharmony_ci } 4879141cc406Sopenharmony_ci 4880141cc406Sopenharmony_ci if (sanei_usb_check_attr(node, "error", "timeout", __func__)) 4881141cc406Sopenharmony_ci { 4882141cc406Sopenharmony_ci return -1; 4883141cc406Sopenharmony_ci } 4884141cc406Sopenharmony_ci 4885141cc406Sopenharmony_ci size_t tx_data_size = 0; 4886141cc406Sopenharmony_ci char* tx_data = sanei_xml_get_hex_data(node, &tx_data_size); 4887141cc406Sopenharmony_ci 4888141cc406Sopenharmony_ci if (tx_data_size > wanted_size) 4889141cc406Sopenharmony_ci { 4890141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, 4891141cc406Sopenharmony_ci "got more data than wanted (%lu vs %lu)\n", 4892141cc406Sopenharmony_ci tx_data_size, wanted_size); 4893141cc406Sopenharmony_ci sanei_usb_record_replace_read_int(node, dn, NULL, 0, size); 4894141cc406Sopenharmony_ci free(tx_data); 4895141cc406Sopenharmony_ci return -1; 4896141cc406Sopenharmony_ci } 4897141cc406Sopenharmony_ci 4898141cc406Sopenharmony_ci memcpy((char*) buffer, tx_data, tx_data_size); 4899141cc406Sopenharmony_ci free(tx_data); 4900141cc406Sopenharmony_ci return tx_data_size; 4901141cc406Sopenharmony_ci} 4902141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 4903141cc406Sopenharmony_ci 4904141cc406Sopenharmony_ciSANE_Status 4905141cc406Sopenharmony_cisanei_usb_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) 4906141cc406Sopenharmony_ci{ 4907141cc406Sopenharmony_ci ssize_t read_size = 0; 4908141cc406Sopenharmony_ci#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) || defined(HAVE_USB_MANAGER) 4909141cc406Sopenharmony_ci SANE_Bool stalled = SANE_FALSE; 4910141cc406Sopenharmony_ci#endif 4911141cc406Sopenharmony_ci 4912141cc406Sopenharmony_ci if (!size) 4913141cc406Sopenharmony_ci { 4914141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: size == NULL\n"); 4915141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4916141cc406Sopenharmony_ci } 4917141cc406Sopenharmony_ci 4918141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 4919141cc406Sopenharmony_ci { 4920141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: dn >= device number || dn < 0\n"); 4921141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4922141cc406Sopenharmony_ci } 4923141cc406Sopenharmony_ci 4924141cc406Sopenharmony_ci DBG (5, "sanei_usb_read_int: trying to read %lu bytes\n", 4925141cc406Sopenharmony_ci (unsigned long) *size); 4926141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 4927141cc406Sopenharmony_ci { 4928141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 4929141cc406Sopenharmony_ci read_size = sanei_usb_replay_read_int(dn, buffer, *size); 4930141cc406Sopenharmony_ci#else 4931141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 4932141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 4933141cc406Sopenharmony_ci#endif 4934141cc406Sopenharmony_ci } 4935141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 4936141cc406Sopenharmony_ci { 4937141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: access method %d not implemented\n", 4938141cc406Sopenharmony_ci devices[dn].method); 4939141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4940141cc406Sopenharmony_ci } 4941141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 4942141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 4943141cc406Sopenharmony_ci { 4944141cc406Sopenharmony_ci if (devices[dn].int_in_ep) 4945141cc406Sopenharmony_ci { 4946141cc406Sopenharmony_ci read_size = usb_interrupt_read (devices[dn].libusb_handle, 4947141cc406Sopenharmony_ci devices[dn].int_in_ep, 4948141cc406Sopenharmony_ci (char *) buffer, (int) *size, 4949141cc406Sopenharmony_ci libusb_timeout); 4950141cc406Sopenharmony_ci 4951141cc406Sopenharmony_ci if (read_size < 0) 4952141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: read failed: %s\n", 4953141cc406Sopenharmony_ci strerror (errno)); 4954141cc406Sopenharmony_ci 4955141cc406Sopenharmony_ci stalled = (read_size == -EPIPE); 4956141cc406Sopenharmony_ci } 4957141cc406Sopenharmony_ci else 4958141cc406Sopenharmony_ci { 4959141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: can't read without an int " 4960141cc406Sopenharmony_ci "endpoint\n"); 4961141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4962141cc406Sopenharmony_ci } 4963141cc406Sopenharmony_ci } 4964141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 4965141cc406Sopenharmony_ci { 4966141cc406Sopenharmony_ci if (devices[dn].int_in_ep) 4967141cc406Sopenharmony_ci { 4968141cc406Sopenharmony_ci int ret; 4969141cc406Sopenharmony_ci int trans_bytes; 4970141cc406Sopenharmony_ci ret = libusb_interrupt_transfer (devices[dn].lu_handle, 4971141cc406Sopenharmony_ci devices[dn].int_in_ep, 4972141cc406Sopenharmony_ci buffer, (int) *size, 4973141cc406Sopenharmony_ci &trans_bytes, libusb_timeout); 4974141cc406Sopenharmony_ci 4975141cc406Sopenharmony_ci if (ret < 0) 4976141cc406Sopenharmony_ci read_size = -1; 4977141cc406Sopenharmony_ci else 4978141cc406Sopenharmony_ci read_size = trans_bytes; 4979141cc406Sopenharmony_ci 4980141cc406Sopenharmony_ci stalled = (ret == LIBUSB_ERROR_PIPE); 4981141cc406Sopenharmony_ci } 4982141cc406Sopenharmony_ci else 4983141cc406Sopenharmony_ci { 4984141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: can't read without an int " 4985141cc406Sopenharmony_ci "endpoint\n"); 4986141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 4987141cc406Sopenharmony_ci } 4988141cc406Sopenharmony_ci } 4989141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 4990141cc406Sopenharmony_ci { 4991141cc406Sopenharmony_ci if (devices[dn].int_in_ep) 4992141cc406Sopenharmony_ci { 4993141cc406Sopenharmony_ci int ret; 4994141cc406Sopenharmony_ci int trans_bytes; 4995141cc406Sopenharmony_ci ret = usb_manager_interrupt_transfer (devices[dn].usb_manager_handle, 4996141cc406Sopenharmony_ci devices[dn].int_in_ep, 4997141cc406Sopenharmony_ci buffer, (int) *size, 4998141cc406Sopenharmony_ci &trans_bytes, usb_manager_timeout); 4999141cc406Sopenharmony_ci 5000141cc406Sopenharmony_ci if (ret < 0) 5001141cc406Sopenharmony_ci read_size = -1; 5002141cc406Sopenharmony_ci else 5003141cc406Sopenharmony_ci read_size = trans_bytes; 5004141cc406Sopenharmony_ci 5005141cc406Sopenharmony_ci stalled = (ret == USB_MANAGER_ERROR_PIPE); 5006141cc406Sopenharmony_ci } 5007141cc406Sopenharmony_ci else 5008141cc406Sopenharmony_ci { 5009141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: can't read without an int " 5010141cc406Sopenharmony_ci "endpoint\n"); 5011141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5012141cc406Sopenharmony_ci } 5013141cc406Sopenharmony_ci } 5014141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ 5015141cc406Sopenharmony_ci { 5016141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: libusb support missing\n"); 5017141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5018141cc406Sopenharmony_ci } 5019141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5020141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_usbcalls) 5021141cc406Sopenharmony_ci { 5022141cc406Sopenharmony_ci#ifdef HAVE_USBCALLS 5023141cc406Sopenharmony_ci int rc; 5024141cc406Sopenharmony_ci USHORT usNumBytes=*size; 5025141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbIrqStart with dn = %d\n",dn); 5026141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbIrqStart with dh = %p\n",dh); 5027141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbIrqStart with int_in_ep = 0x%02x\n",devices[dn].int_in_ep); 5028141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbIrqStart with interface_nr = %d\n",devices[dn].interface_nr); 5029141cc406Sopenharmony_ci DBG (5, "Entered usbcalls UsbIrqStart with bytes to read = %u\n",usNumBytes); 5030141cc406Sopenharmony_ci 5031141cc406Sopenharmony_ci if (devices[dn].int_in_ep){ 5032141cc406Sopenharmony_ci rc = UsbIrqStart (dh,devices[dn].int_in_ep,devices[dn].interface_nr, 5033141cc406Sopenharmony_ci usNumBytes, (char *) buffer, pUsbIrqStartHev); 5034141cc406Sopenharmony_ci DBG (5, "rc of UsbIrqStart = %d\n",rc); 5035141cc406Sopenharmony_ci } 5036141cc406Sopenharmony_ci else 5037141cc406Sopenharmony_ci { 5038141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: can't read without an int " 5039141cc406Sopenharmony_ci "endpoint\n"); 5040141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5041141cc406Sopenharmony_ci } 5042141cc406Sopenharmony_ci if (rc) return SANE_STATUS_INVAL; 5043141cc406Sopenharmony_ci read_size += usNumBytes; 5044141cc406Sopenharmony_ci#else 5045141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: usbcalls support missing\n"); 5046141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5047141cc406Sopenharmony_ci#endif /* HAVE_USBCALLS */ 5048141cc406Sopenharmony_ci } 5049141cc406Sopenharmony_ci else 5050141cc406Sopenharmony_ci { 5051141cc406Sopenharmony_ci DBG (1, "sanei_usb_read_int: access method %d not implemented\n", 5052141cc406Sopenharmony_ci devices[dn].method); 5053141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5054141cc406Sopenharmony_ci } 5055141cc406Sopenharmony_ci 5056141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 5057141cc406Sopenharmony_ci { 5058141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 5059141cc406Sopenharmony_ci sanei_usb_record_read_int(NULL, dn, buffer, *size, read_size); 5060141cc406Sopenharmony_ci#else 5061141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 5062141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5063141cc406Sopenharmony_ci#endif 5064141cc406Sopenharmony_ci } 5065141cc406Sopenharmony_ci 5066141cc406Sopenharmony_ci if (read_size < 0) 5067141cc406Sopenharmony_ci { 5068141cc406Sopenharmony_ci *size = 0; 5069141cc406Sopenharmony_ci if (testing_mode != sanei_usb_testing_mode_disabled) 5070141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5071141cc406Sopenharmony_ci 5072141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 5073141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_libusb) 5074141cc406Sopenharmony_ci if (stalled) 5075141cc406Sopenharmony_ci usb_clear_halt (devices[dn].libusb_handle, devices[dn].int_in_ep); 5076141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 5077141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_libusb) 5078141cc406Sopenharmony_ci if (stalled) 5079141cc406Sopenharmony_ci libusb_clear_halt (devices[dn].lu_handle, devices[dn].int_in_ep); 5080141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 5081141cc406Sopenharmony_ci if (devices[dn].method == sanei_usb_method_usb_manager) 5082141cc406Sopenharmony_ci if (stalled) 5083141cc406Sopenharmony_ci usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].int_in_ep); 5084141cc406Sopenharmony_ci#endif 5085141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5086141cc406Sopenharmony_ci } 5087141cc406Sopenharmony_ci if (read_size == 0) 5088141cc406Sopenharmony_ci { 5089141cc406Sopenharmony_ci DBG (3, "sanei_usb_read_int: read returned EOF\n"); 5090141cc406Sopenharmony_ci *size = 0; 5091141cc406Sopenharmony_ci return SANE_STATUS_EOF; 5092141cc406Sopenharmony_ci } 5093141cc406Sopenharmony_ci DBG (5, "sanei_usb_read_int: wanted %lu bytes, got %ld bytes\n", 5094141cc406Sopenharmony_ci (unsigned long) *size, (unsigned long) read_size); 5095141cc406Sopenharmony_ci *size = read_size; 5096141cc406Sopenharmony_ci if (debug_level > 10) 5097141cc406Sopenharmony_ci print_buffer (buffer, read_size); 5098141cc406Sopenharmony_ci 5099141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5100141cc406Sopenharmony_ci} 5101141cc406Sopenharmony_ci 5102141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 5103141cc406Sopenharmony_cistatic SANE_Status sanei_usb_replay_set_configuration(SANE_Int dn, 5104141cc406Sopenharmony_ci SANE_Int configuration) 5105141cc406Sopenharmony_ci{ 5106141cc406Sopenharmony_ci (void) dn; 5107141cc406Sopenharmony_ci 5108141cc406Sopenharmony_ci xmlNode* node = sanei_xml_get_next_tx_node(); 5109141cc406Sopenharmony_ci if (node == NULL) 5110141cc406Sopenharmony_ci { 5111141cc406Sopenharmony_ci FAIL_TEST(__func__, "no more transactions\n"); 5112141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5113141cc406Sopenharmony_ci } 5114141cc406Sopenharmony_ci 5115141cc406Sopenharmony_ci sanei_xml_record_seq(node); 5116141cc406Sopenharmony_ci sanei_xml_break_if_needed(node); 5117141cc406Sopenharmony_ci 5118141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"control_tx") != 0) 5119141cc406Sopenharmony_ci { 5120141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", 5121141cc406Sopenharmony_ci (const char*) node->name); 5122141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5123141cc406Sopenharmony_ci } 5124141cc406Sopenharmony_ci 5125141cc406Sopenharmony_ci if (!sanei_usb_check_attr(node, "direction", "OUT", __func__)) 5126141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5127141cc406Sopenharmony_ci 5128141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "bmRequestType", 0, __func__)) 5129141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5130141cc406Sopenharmony_ci 5131141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "bRequest", 9, __func__)) 5132141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5133141cc406Sopenharmony_ci 5134141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "wValue", configuration, __func__)) 5135141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5136141cc406Sopenharmony_ci 5137141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "wIndex", 0, __func__)) 5138141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5139141cc406Sopenharmony_ci 5140141cc406Sopenharmony_ci if (!sanei_usb_check_attr_uint(node, "wLength", 0, __func__)) 5141141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5142141cc406Sopenharmony_ci 5143141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5144141cc406Sopenharmony_ci} 5145141cc406Sopenharmony_ci 5146141cc406Sopenharmony_cistatic void sanei_usb_record_set_configuration(SANE_Int dn, 5147141cc406Sopenharmony_ci SANE_Int configuration) 5148141cc406Sopenharmony_ci{ 5149141cc406Sopenharmony_ci (void) dn; (void) configuration; 5150141cc406Sopenharmony_ci // TODO 5151141cc406Sopenharmony_ci} 5152141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 5153141cc406Sopenharmony_ci 5154141cc406Sopenharmony_ciSANE_Status 5155141cc406Sopenharmony_cisanei_usb_set_configuration (SANE_Int dn, SANE_Int configuration) 5156141cc406Sopenharmony_ci{ 5157141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 5158141cc406Sopenharmony_ci { 5159141cc406Sopenharmony_ci DBG (1, 5160141cc406Sopenharmony_ci "sanei_usb_set_configuration: dn >= device number || dn < 0, dn=%d\n", 5161141cc406Sopenharmony_ci dn); 5162141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5163141cc406Sopenharmony_ci } 5164141cc406Sopenharmony_ci 5165141cc406Sopenharmony_ci DBG (5, "sanei_usb_set_configuration: configuration = %d\n", configuration); 5166141cc406Sopenharmony_ci 5167141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 5168141cc406Sopenharmony_ci { 5169141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 5170141cc406Sopenharmony_ci sanei_usb_record_set_configuration(dn, configuration); 5171141cc406Sopenharmony_ci#else 5172141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 5173141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5174141cc406Sopenharmony_ci#endif 5175141cc406Sopenharmony_ci } 5176141cc406Sopenharmony_ci 5177141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 5178141cc406Sopenharmony_ci { 5179141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 5180141cc406Sopenharmony_ci return sanei_usb_replay_set_configuration(dn, configuration); 5181141cc406Sopenharmony_ci#else 5182141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 5183141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5184141cc406Sopenharmony_ci#endif 5185141cc406Sopenharmony_ci } 5186141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 5187141cc406Sopenharmony_ci { 5188141cc406Sopenharmony_ci#if defined(__linux__) 5189141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5190141cc406Sopenharmony_ci#else /* not __linux__ */ 5191141cc406Sopenharmony_ci DBG (5, "sanei_usb_set_configuration: not supported on this OS\n"); 5192141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5193141cc406Sopenharmony_ci#endif /* not __linux__ */ 5194141cc406Sopenharmony_ci } 5195141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 5196141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 5197141cc406Sopenharmony_ci { 5198141cc406Sopenharmony_ci int result; 5199141cc406Sopenharmony_ci 5200141cc406Sopenharmony_ci result = 5201141cc406Sopenharmony_ci usb_set_configuration (devices[dn].libusb_handle, configuration); 5202141cc406Sopenharmony_ci if (result < 0) 5203141cc406Sopenharmony_ci { 5204141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_configuration: libusb complained: %s\n", 5205141cc406Sopenharmony_ci usb_strerror ()); 5206141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5207141cc406Sopenharmony_ci } 5208141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5209141cc406Sopenharmony_ci } 5210141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 5211141cc406Sopenharmony_ci { 5212141cc406Sopenharmony_ci int result; 5213141cc406Sopenharmony_ci 5214141cc406Sopenharmony_ci result = libusb_set_configuration (devices[dn].lu_handle, configuration); 5215141cc406Sopenharmony_ci if (result < 0) 5216141cc406Sopenharmony_ci { 5217141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_configuration: libusb complained: %s\n", 5218141cc406Sopenharmony_ci sanei_libusb_strerror (result)); 5219141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5220141cc406Sopenharmony_ci } 5221141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5222141cc406Sopenharmony_ci } 5223141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 5224141cc406Sopenharmony_ci { 5225141cc406Sopenharmony_ci int result; 5226141cc406Sopenharmony_ci 5227141cc406Sopenharmony_ci result = usb_manager_set_configuration (devices[dn].usb_manager_handle, configuration); 5228141cc406Sopenharmony_ci if (result < 0) 5229141cc406Sopenharmony_ci { 5230141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_configuration: libusb complained: %s\n", 5231141cc406Sopenharmony_ci sanei_usb_manager_strerror (result)); 5232141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5233141cc406Sopenharmony_ci } 5234141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5235141cc406Sopenharmony_ci } 5236141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5237141cc406Sopenharmony_ci { 5238141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_configuration: libusb support missing\n"); 5239141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5240141cc406Sopenharmony_ci } 5241141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5242141cc406Sopenharmony_ci else 5243141cc406Sopenharmony_ci { 5244141cc406Sopenharmony_ci DBG (1, 5245141cc406Sopenharmony_ci "sanei_usb_set_configuration: access method %d not implemented\n", 5246141cc406Sopenharmony_ci devices[dn].method); 5247141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5248141cc406Sopenharmony_ci } 5249141cc406Sopenharmony_ci} 5250141cc406Sopenharmony_ci 5251141cc406Sopenharmony_ciSANE_Status 5252141cc406Sopenharmony_cisanei_usb_claim_interface (SANE_Int dn, SANE_Int interface_number) 5253141cc406Sopenharmony_ci{ 5254141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 5255141cc406Sopenharmony_ci { 5256141cc406Sopenharmony_ci DBG (1, 5257141cc406Sopenharmony_ci "sanei_usb_claim_interface: dn >= device number || dn < 0, dn=%d\n", 5258141cc406Sopenharmony_ci dn); 5259141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5260141cc406Sopenharmony_ci } 5261141cc406Sopenharmony_ci if (devices[dn].missing) 5262141cc406Sopenharmony_ci { 5263141cc406Sopenharmony_ci DBG (1, "sanei_usb_claim_interface: device dn=%d is missing\n", dn); 5264141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5265141cc406Sopenharmony_ci } 5266141cc406Sopenharmony_ci 5267141cc406Sopenharmony_ci DBG (5, "sanei_usb_claim_interface: interface_number = %d\n", interface_number); 5268141cc406Sopenharmony_ci 5269141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 5270141cc406Sopenharmony_ci { 5271141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5272141cc406Sopenharmony_ci } 5273141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 5274141cc406Sopenharmony_ci { 5275141cc406Sopenharmony_ci#if defined(__linux__) 5276141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5277141cc406Sopenharmony_ci#else /* not __linux__ */ 5278141cc406Sopenharmony_ci DBG (5, "sanei_usb_claim_interface: not supported on this OS\n"); 5279141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5280141cc406Sopenharmony_ci#endif /* not __linux__ */ 5281141cc406Sopenharmony_ci } 5282141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 5283141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 5284141cc406Sopenharmony_ci { 5285141cc406Sopenharmony_ci int result; 5286141cc406Sopenharmony_ci 5287141cc406Sopenharmony_ci result = usb_claim_interface (devices[dn].libusb_handle, interface_number); 5288141cc406Sopenharmony_ci if (result < 0) 5289141cc406Sopenharmony_ci { 5290141cc406Sopenharmony_ci DBG (1, "sanei_usb_claim_interface: libusb complained: %s\n", 5291141cc406Sopenharmony_ci usb_strerror ()); 5292141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5293141cc406Sopenharmony_ci } 5294141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5295141cc406Sopenharmony_ci } 5296141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 5297141cc406Sopenharmony_ci { 5298141cc406Sopenharmony_ci int result; 5299141cc406Sopenharmony_ci 5300141cc406Sopenharmony_ci result = libusb_claim_interface (devices[dn].lu_handle, interface_number); 5301141cc406Sopenharmony_ci if (result < 0) 5302141cc406Sopenharmony_ci { 5303141cc406Sopenharmony_ci DBG (1, "sanei_usb_claim_interface: libusb complained: %s\n", 5304141cc406Sopenharmony_ci sanei_libusb_strerror (result)); 5305141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5306141cc406Sopenharmony_ci } 5307141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5308141cc406Sopenharmony_ci } 5309141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 5310141cc406Sopenharmony_ci { 5311141cc406Sopenharmony_ci int result; 5312141cc406Sopenharmony_ci 5313141cc406Sopenharmony_ci result = usb_manager_claim_interface (devices[dn].usb_manager_handle, interface_number); 5314141cc406Sopenharmony_ci if (result < 0) 5315141cc406Sopenharmony_ci { 5316141cc406Sopenharmony_ci DBG (1, "sanei_usb_claim_interface: libusb complained: %s\n", 5317141cc406Sopenharmony_ci sanei_usb_manager_strerror (result)); 5318141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5319141cc406Sopenharmony_ci } 5320141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5321141cc406Sopenharmony_ci } 5322141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5323141cc406Sopenharmony_ci { 5324141cc406Sopenharmony_ci DBG (1, "sanei_usb_claim_interface: libusb support missing\n"); 5325141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5326141cc406Sopenharmony_ci } 5327141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ 5328141cc406Sopenharmony_ci else 5329141cc406Sopenharmony_ci { 5330141cc406Sopenharmony_ci DBG (1, "sanei_usb_claim_interface: access method %d not implemented\n", 5331141cc406Sopenharmony_ci devices[dn].method); 5332141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5333141cc406Sopenharmony_ci } 5334141cc406Sopenharmony_ci} 5335141cc406Sopenharmony_ci 5336141cc406Sopenharmony_ciSANE_Status 5337141cc406Sopenharmony_cisanei_usb_release_interface (SANE_Int dn, SANE_Int interface_number) 5338141cc406Sopenharmony_ci{ 5339141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 5340141cc406Sopenharmony_ci { 5341141cc406Sopenharmony_ci DBG (1, 5342141cc406Sopenharmony_ci "sanei_usb_release_interface: dn >= device number || dn < 0, dn=%d\n", 5343141cc406Sopenharmony_ci dn); 5344141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5345141cc406Sopenharmony_ci } 5346141cc406Sopenharmony_ci if (devices[dn].missing) 5347141cc406Sopenharmony_ci { 5348141cc406Sopenharmony_ci DBG (1, "sanei_usb_release_interface: device dn=%d is missing\n", dn); 5349141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5350141cc406Sopenharmony_ci } 5351141cc406Sopenharmony_ci DBG (5, "sanei_usb_release_interface: interface_number = %d\n", interface_number); 5352141cc406Sopenharmony_ci 5353141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 5354141cc406Sopenharmony_ci { 5355141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5356141cc406Sopenharmony_ci } 5357141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 5358141cc406Sopenharmony_ci { 5359141cc406Sopenharmony_ci#if defined(__linux__) 5360141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5361141cc406Sopenharmony_ci#else /* not __linux__ */ 5362141cc406Sopenharmony_ci DBG (5, "sanei_usb_release_interface: not supported on this OS\n"); 5363141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5364141cc406Sopenharmony_ci#endif /* not __linux__ */ 5365141cc406Sopenharmony_ci } 5366141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 5367141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 5368141cc406Sopenharmony_ci { 5369141cc406Sopenharmony_ci int result; 5370141cc406Sopenharmony_ci 5371141cc406Sopenharmony_ci result = usb_release_interface (devices[dn].libusb_handle, interface_number); 5372141cc406Sopenharmony_ci if (result < 0) 5373141cc406Sopenharmony_ci { 5374141cc406Sopenharmony_ci DBG (1, "sanei_usb_release_interface: libusb complained: %s\n", 5375141cc406Sopenharmony_ci usb_strerror ()); 5376141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5377141cc406Sopenharmony_ci } 5378141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5379141cc406Sopenharmony_ci } 5380141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 5381141cc406Sopenharmony_ci { 5382141cc406Sopenharmony_ci int result; 5383141cc406Sopenharmony_ci 5384141cc406Sopenharmony_ci result = libusb_release_interface (devices[dn].lu_handle, interface_number); 5385141cc406Sopenharmony_ci if (result < 0) 5386141cc406Sopenharmony_ci { 5387141cc406Sopenharmony_ci DBG (1, "sanei_usb_release_interface: libusb complained: %s\n", 5388141cc406Sopenharmony_ci sanei_libusb_strerror (result)); 5389141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5390141cc406Sopenharmony_ci } 5391141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5392141cc406Sopenharmony_ci } 5393141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 5394141cc406Sopenharmony_ci { 5395141cc406Sopenharmony_ci int result; 5396141cc406Sopenharmony_ci 5397141cc406Sopenharmony_ci result = usb_manager_release_interface (devices[dn].usb_manager_handle, interface_number); 5398141cc406Sopenharmony_ci if (result < 0) 5399141cc406Sopenharmony_ci { 5400141cc406Sopenharmony_ci DBG (1, "sanei_usb_release_interface: libusb complained: %s\n", 5401141cc406Sopenharmony_ci sanei_usb_manager_strerror (result)); 5402141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5403141cc406Sopenharmony_ci } 5404141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5405141cc406Sopenharmony_ci } 5406141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5407141cc406Sopenharmony_ci { 5408141cc406Sopenharmony_ci DBG (1, "sanei_usb_release_interface: libusb support missing\n"); 5409141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5410141cc406Sopenharmony_ci } 5411141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5412141cc406Sopenharmony_ci else 5413141cc406Sopenharmony_ci { 5414141cc406Sopenharmony_ci DBG (1, 5415141cc406Sopenharmony_ci "sanei_usb_release_interface: access method %d not implemented\n", 5416141cc406Sopenharmony_ci devices[dn].method); 5417141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5418141cc406Sopenharmony_ci } 5419141cc406Sopenharmony_ci} 5420141cc406Sopenharmony_ci 5421141cc406Sopenharmony_ciSANE_Status 5422141cc406Sopenharmony_cisanei_usb_set_altinterface (SANE_Int dn, SANE_Int alternate) 5423141cc406Sopenharmony_ci{ 5424141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 5425141cc406Sopenharmony_ci { 5426141cc406Sopenharmony_ci DBG (1, 5427141cc406Sopenharmony_ci "sanei_usb_set_altinterface: dn >= device number || dn < 0, dn=%d\n", 5428141cc406Sopenharmony_ci dn); 5429141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5430141cc406Sopenharmony_ci } 5431141cc406Sopenharmony_ci 5432141cc406Sopenharmony_ci DBG (5, "sanei_usb_set_altinterface: alternate = %d\n", alternate); 5433141cc406Sopenharmony_ci 5434141cc406Sopenharmony_ci devices[dn].alt_setting = alternate; 5435141cc406Sopenharmony_ci 5436141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 5437141cc406Sopenharmony_ci { 5438141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5439141cc406Sopenharmony_ci } 5440141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_scanner_driver) 5441141cc406Sopenharmony_ci { 5442141cc406Sopenharmony_ci#if defined(__linux__) 5443141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5444141cc406Sopenharmony_ci#else /* not __linux__ */ 5445141cc406Sopenharmony_ci DBG (5, "sanei_usb_set_altinterface: not supported on this OS\n"); 5446141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5447141cc406Sopenharmony_ci#endif /* not __linux__ */ 5448141cc406Sopenharmony_ci } 5449141cc406Sopenharmony_ci else if (devices[dn].method == sanei_usb_method_libusb) 5450141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 5451141cc406Sopenharmony_ci { 5452141cc406Sopenharmony_ci int result; 5453141cc406Sopenharmony_ci 5454141cc406Sopenharmony_ci result = usb_set_altinterface (devices[dn].libusb_handle, alternate); 5455141cc406Sopenharmony_ci if (result < 0) 5456141cc406Sopenharmony_ci { 5457141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_altinterface: libusb complained: %s\n", 5458141cc406Sopenharmony_ci usb_strerror ()); 5459141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5460141cc406Sopenharmony_ci } 5461141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5462141cc406Sopenharmony_ci } 5463141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 5464141cc406Sopenharmony_ci { 5465141cc406Sopenharmony_ci int result; 5466141cc406Sopenharmony_ci 5467141cc406Sopenharmony_ci result = libusb_set_interface_alt_setting (devices[dn].lu_handle, 5468141cc406Sopenharmony_ci devices[dn].interface_nr, alternate); 5469141cc406Sopenharmony_ci if (result < 0) 5470141cc406Sopenharmony_ci { 5471141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_altinterface: libusb complained: %s\n", 5472141cc406Sopenharmony_ci sanei_libusb_strerror (result)); 5473141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5474141cc406Sopenharmony_ci } 5475141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5476141cc406Sopenharmony_ci } 5477141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 5478141cc406Sopenharmony_ci { 5479141cc406Sopenharmony_ci int result; 5480141cc406Sopenharmony_ci 5481141cc406Sopenharmony_ci result = usb_manager_set_interface_alt_setting (devices[dn].usb_manager_handle, 5482141cc406Sopenharmony_ci devices[dn].interface_nr, alternate); 5483141cc406Sopenharmony_ci if (result < 0) 5484141cc406Sopenharmony_ci { 5485141cc406Sopenharmony_ci DBG (1, "sanei_usb_set_altinterface: usb_manager complained: %s\n", 5486141cc406Sopenharmony_ci sanei_usb_manager_strerror (result)); 5487141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5488141cc406Sopenharmony_ci } 5489141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5490141cc406Sopenharmony_ci } 5491141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ 5492141cc406Sopenharmony_ci { 5493141cc406Sopenharmony_ci DBG (1, "sanei_set_altinterface: libusb support missing\n"); 5494141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5495141cc406Sopenharmony_ci } 5496141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5497141cc406Sopenharmony_ci else 5498141cc406Sopenharmony_ci { 5499141cc406Sopenharmony_ci DBG (1, 5500141cc406Sopenharmony_ci "sanei_usb_set_altinterface: access method %d not implemented\n", 5501141cc406Sopenharmony_ci devices[dn].method); 5502141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5503141cc406Sopenharmony_ci } 5504141cc406Sopenharmony_ci} 5505141cc406Sopenharmony_ci 5506141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 5507141cc406Sopenharmony_ci 5508141cc406Sopenharmony_cistatic SANE_Status 5509141cc406Sopenharmony_cisanei_usb_replay_get_descriptor(SANE_Int dn, 5510141cc406Sopenharmony_ci struct sanei_usb_dev_descriptor *desc) 5511141cc406Sopenharmony_ci{ 5512141cc406Sopenharmony_ci (void) dn; 5513141cc406Sopenharmony_ci 5514141cc406Sopenharmony_ci if (testing_known_commands_input_failed) 5515141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5516141cc406Sopenharmony_ci 5517141cc406Sopenharmony_ci xmlNode* node = sanei_xml_get_next_tx_node(); 5518141cc406Sopenharmony_ci if (node == NULL) 5519141cc406Sopenharmony_ci { 5520141cc406Sopenharmony_ci FAIL_TEST(__func__, "no more transactions\n"); 5521141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5522141cc406Sopenharmony_ci } 5523141cc406Sopenharmony_ci 5524141cc406Sopenharmony_ci if (sanei_xml_is_known_commands_end(node)) 5525141cc406Sopenharmony_ci { 5526141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 5527141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5528141cc406Sopenharmony_ci } 5529141cc406Sopenharmony_ci 5530141cc406Sopenharmony_ci sanei_xml_record_seq(node); 5531141cc406Sopenharmony_ci sanei_xml_break_if_needed(node); 5532141cc406Sopenharmony_ci 5533141cc406Sopenharmony_ci if (xmlStrcmp(node->name, (const xmlChar*)"get_descriptor") != 0) 5534141cc406Sopenharmony_ci { 5535141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "unexpected transaction type %s\n", 5536141cc406Sopenharmony_ci (const char*) node->name); 5537141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 5538141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5539141cc406Sopenharmony_ci } 5540141cc406Sopenharmony_ci 5541141cc406Sopenharmony_ci int desc_type = sanei_xml_get_prop_uint(node, "descriptor_type"); 5542141cc406Sopenharmony_ci int bcd_usb = sanei_xml_get_prop_uint(node, "bcd_usb"); 5543141cc406Sopenharmony_ci int bcd_dev = sanei_xml_get_prop_uint(node, "bcd_device"); 5544141cc406Sopenharmony_ci int dev_class = sanei_xml_get_prop_uint(node, "device_class"); 5545141cc406Sopenharmony_ci int dev_sub_class = sanei_xml_get_prop_uint(node, "device_sub_class"); 5546141cc406Sopenharmony_ci int dev_protocol = sanei_xml_get_prop_uint(node, "device_protocol"); 5547141cc406Sopenharmony_ci int max_packet_size = sanei_xml_get_prop_uint(node, "max_packet_size"); 5548141cc406Sopenharmony_ci 5549141cc406Sopenharmony_ci if (desc_type < 0 || bcd_usb < 0 || bcd_dev < 0 || dev_class < 0 || 5550141cc406Sopenharmony_ci dev_sub_class < 0 || dev_protocol < 0 || max_packet_size < 0) 5551141cc406Sopenharmony_ci { 5552141cc406Sopenharmony_ci FAIL_TEST_TX(__func__, node, "get_descriptor recorded block is missing attributes\n"); 5553141cc406Sopenharmony_ci testing_known_commands_input_failed = 1; 5554141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 5555141cc406Sopenharmony_ci } 5556141cc406Sopenharmony_ci 5557141cc406Sopenharmony_ci desc->desc_type = desc_type; 5558141cc406Sopenharmony_ci desc->bcd_usb = bcd_usb; 5559141cc406Sopenharmony_ci desc->bcd_dev = bcd_dev; 5560141cc406Sopenharmony_ci desc->dev_class = dev_class; 5561141cc406Sopenharmony_ci desc->dev_sub_class = dev_sub_class; 5562141cc406Sopenharmony_ci desc->dev_protocol = dev_protocol; 5563141cc406Sopenharmony_ci desc->max_packet_size = max_packet_size; 5564141cc406Sopenharmony_ci 5565141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5566141cc406Sopenharmony_ci} 5567141cc406Sopenharmony_ci 5568141cc406Sopenharmony_cistatic void 5569141cc406Sopenharmony_cisanei_usb_record_get_descriptor(SANE_Int dn, 5570141cc406Sopenharmony_ci struct sanei_usb_dev_descriptor *desc) 5571141cc406Sopenharmony_ci{ 5572141cc406Sopenharmony_ci (void) dn; 5573141cc406Sopenharmony_ci 5574141cc406Sopenharmony_ci xmlNode* node = testing_append_commands_node; 5575141cc406Sopenharmony_ci 5576141cc406Sopenharmony_ci xmlNode* e_tx = xmlNewNode(NULL, (const xmlChar*)"get_descriptor"); 5577141cc406Sopenharmony_ci 5578141cc406Sopenharmony_ci xmlNewProp(e_tx, (const xmlChar*)"time_usec", (const xmlChar*)"0"); 5579141cc406Sopenharmony_ci sanei_xml_set_uint_attr(node, "seq", ++testing_last_known_seq); 5580141cc406Sopenharmony_ci 5581141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "descriptor_type", desc->desc_type); 5582141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "bcd_usb", desc->bcd_usb); 5583141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "bcd_device", desc->bcd_dev); 5584141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "device_class", desc->dev_class); 5585141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "device_sub_class", desc->dev_sub_class); 5586141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "device_protocol", desc->dev_protocol); 5587141cc406Sopenharmony_ci sanei_xml_set_hex_attr(e_tx, "max_packet_size", desc->max_packet_size); 5588141cc406Sopenharmony_ci 5589141cc406Sopenharmony_ci node = sanei_xml_append_command(node, 1, e_tx); 5590141cc406Sopenharmony_ci testing_append_commands_node = node; 5591141cc406Sopenharmony_ci} 5592141cc406Sopenharmony_ci 5593141cc406Sopenharmony_ci#endif // WITH_USB_RECORD_REPLAY 5594141cc406Sopenharmony_ci 5595141cc406Sopenharmony_ciextern SANE_Status 5596141cc406Sopenharmony_cisanei_usb_get_descriptor( SANE_Int dn, 5597141cc406Sopenharmony_ci struct sanei_usb_dev_descriptor __sane_unused__ 5598141cc406Sopenharmony_ci *desc ) 5599141cc406Sopenharmony_ci{ 5600141cc406Sopenharmony_ci if (dn >= device_number || dn < 0) 5601141cc406Sopenharmony_ci { 5602141cc406Sopenharmony_ci DBG (1, 5603141cc406Sopenharmony_ci "sanei_usb_get_descriptor: dn >= device number || dn < 0, dn=%d\n", 5604141cc406Sopenharmony_ci dn); 5605141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5606141cc406Sopenharmony_ci } 5607141cc406Sopenharmony_ci 5608141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_replay) 5609141cc406Sopenharmony_ci { 5610141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 5611141cc406Sopenharmony_ci return sanei_usb_replay_get_descriptor(dn, desc); 5612141cc406Sopenharmony_ci#else 5613141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 5614141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5615141cc406Sopenharmony_ci#endif 5616141cc406Sopenharmony_ci } 5617141cc406Sopenharmony_ci 5618141cc406Sopenharmony_ci DBG (5, "sanei_usb_get_descriptor\n"); 5619141cc406Sopenharmony_ci#ifdef HAVE_LIBUSB_LEGACY 5620141cc406Sopenharmony_ci { 5621141cc406Sopenharmony_ci struct usb_device_descriptor *usb_descr; 5622141cc406Sopenharmony_ci 5623141cc406Sopenharmony_ci usb_descr = &(devices[dn].libusb_device->descriptor); 5624141cc406Sopenharmony_ci desc->desc_type = usb_descr->bDescriptorType; 5625141cc406Sopenharmony_ci desc->bcd_usb = usb_descr->bcdUSB; 5626141cc406Sopenharmony_ci desc->bcd_dev = usb_descr->bcdDevice; 5627141cc406Sopenharmony_ci desc->dev_class = usb_descr->bDeviceClass; 5628141cc406Sopenharmony_ci 5629141cc406Sopenharmony_ci desc->dev_sub_class = usb_descr->bDeviceSubClass; 5630141cc406Sopenharmony_ci desc->dev_protocol = usb_descr->bDeviceProtocol; 5631141cc406Sopenharmony_ci desc->max_packet_size = usb_descr->bMaxPacketSize0; 5632141cc406Sopenharmony_ci } 5633141cc406Sopenharmony_ci#elif defined(HAVE_LIBUSB) 5634141cc406Sopenharmony_ci { 5635141cc406Sopenharmony_ci struct libusb_device_descriptor lu_desc; 5636141cc406Sopenharmony_ci int ret; 5637141cc406Sopenharmony_ci 5638141cc406Sopenharmony_ci ret = libusb_get_device_descriptor (devices[dn].lu_device, &lu_desc); 5639141cc406Sopenharmony_ci if (ret < 0) 5640141cc406Sopenharmony_ci { 5641141cc406Sopenharmony_ci DBG (1, 5642141cc406Sopenharmony_ci "sanei_usb_get_descriptor: libusb error: %s\n", 5643141cc406Sopenharmony_ci sanei_libusb_strerror (ret)); 5644141cc406Sopenharmony_ci 5645141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5646141cc406Sopenharmony_ci } 5647141cc406Sopenharmony_ci 5648141cc406Sopenharmony_ci desc->desc_type = lu_desc.bDescriptorType; 5649141cc406Sopenharmony_ci desc->bcd_usb = lu_desc.bcdUSB; 5650141cc406Sopenharmony_ci desc->bcd_dev = lu_desc.bcdDevice; 5651141cc406Sopenharmony_ci desc->dev_class = lu_desc.bDeviceClass; 5652141cc406Sopenharmony_ci 5653141cc406Sopenharmony_ci desc->dev_sub_class = lu_desc.bDeviceSubClass; 5654141cc406Sopenharmony_ci desc->dev_protocol = lu_desc.bDeviceProtocol; 5655141cc406Sopenharmony_ci desc->max_packet_size = lu_desc.bMaxPacketSize0; 5656141cc406Sopenharmony_ci } 5657141cc406Sopenharmony_ci#elif defined(HAVE_USB_MANAGER) 5658141cc406Sopenharmony_ci { 5659141cc406Sopenharmony_ci struct usb_manager_device_descriptor usb_manager_desc; 5660141cc406Sopenharmony_ci int ret; 5661141cc406Sopenharmony_ci 5662141cc406Sopenharmony_ci ret = usb_manager_get_device_descriptor (devices[dn].usb_manager_device, &usb_manager_desc); 5663141cc406Sopenharmony_ci if (ret < 0) 5664141cc406Sopenharmony_ci { 5665141cc406Sopenharmony_ci DBG (1, 5666141cc406Sopenharmony_ci "sanei_usb_get_descriptor: libusb error: %s\n", 5667141cc406Sopenharmony_ci sanei_usb_manager_strerror (ret)); 5668141cc406Sopenharmony_ci 5669141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 5670141cc406Sopenharmony_ci } 5671141cc406Sopenharmony_ci 5672141cc406Sopenharmony_ci desc->desc_type = usb_manager_desc.bDescriptorType; 5673141cc406Sopenharmony_ci desc->bcd_usb = usb_manager_desc.bcdUSB; 5674141cc406Sopenharmony_ci desc->bcd_dev = usb_manager_desc.bcdDevice; 5675141cc406Sopenharmony_ci desc->dev_class = usb_manager_desc.bDeviceClass; 5676141cc406Sopenharmony_ci 5677141cc406Sopenharmony_ci desc->dev_sub_class = usb_manager_desc.bDeviceSubClass; 5678141cc406Sopenharmony_ci desc->dev_protocol = usb_manager_desc.bDeviceProtocol; 5679141cc406Sopenharmony_ci desc->max_packet_size = usb_manager_desc.bMaxPacketSize0; 5680141cc406Sopenharmony_ci } 5681141cc406Sopenharmony_ci#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ 5682141cc406Sopenharmony_ci { 5683141cc406Sopenharmony_ci DBG (1, "sanei_usb_get_descriptor: libusb support missing\n"); 5684141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5685141cc406Sopenharmony_ci } 5686141cc406Sopenharmony_ci#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ 5687141cc406Sopenharmony_ci 5688141cc406Sopenharmony_ci if (testing_mode == sanei_usb_testing_mode_record) 5689141cc406Sopenharmony_ci { 5690141cc406Sopenharmony_ci#if WITH_USB_RECORD_REPLAY 5691141cc406Sopenharmony_ci sanei_usb_record_get_descriptor(dn, desc); 5692141cc406Sopenharmony_ci#else 5693141cc406Sopenharmony_ci DBG (1, "USB record-replay mode support is missing\n"); 5694141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 5695141cc406Sopenharmony_ci#endif 5696141cc406Sopenharmony_ci } 5697141cc406Sopenharmony_ci 5698141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 5699141cc406Sopenharmony_ci} 5700