diff --git a/BUILD.gn b/BUILD.gn index ba4ac611b67433aed95e775d17dca5d4c0c59a55..812381cb883f1a0f585424f93df72fe227e1d78b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -20,9 +20,38 @@ SANE_V_MAJOR = 1 SANE_V_MINOR = 2 SANE_LIB_DIR = "/data/service/el1/public/print_service/sane/backend" enable_hilog = true +source_dir = "//third_party/backends" +target_dir = "${target_gen_dir}/sane" + +backends_usb_manager_source_file = [ + "$target_dir/src/sanei_usb.c", + "$target_dir/src/usb_manager.cpp" +] + +backends_usb_header_file = [ + "$target_dir/include/config.h", + "$target_dir/include/usb_manager.h", +] + +action("backends_action") { + print("backends_action is exec") + script = "//third_party/backends/install.py" + outputs = [] + outputs += backends_usb_manager_source_file + outputs += backends_usb_header_file + + inputs = [ "${source_dir}/patches/usbmanager.patch" ] + backends_source_dir = rebase_path("${source_dir}", root_build_dir) + backends_target_dir = rebase_path("${target_dir}", root_build_dir) + args = [ + "--gen-dir", + "$backends_target_dir", + "--source-dir", + "$backends_source_dir", + ] +} base_deps = [ - "//third_party/libusb:libusb", "//third_party/libxml2:xml2", "//third_party/libpng:libpng", "//third_party/libjpeg-turbo:turbojpeg", @@ -35,7 +64,6 @@ config("base_config") { "./include/sane", "//third_party/libxml2/libxml2-2.9.14/include", "//third_party/libjpeg-turbo", - "//third_party/libusb/libusb-1.0.26/libusb", "//third_party/libpng/libpng-1.6.37" ] @@ -100,7 +128,6 @@ sanei_names = [ "sanei_pio", "sanei_pa4s2", "sanei_auth", - "sanei_usb", "sanei_thread", "sanei_pv8630", "sanei_pp", @@ -132,6 +159,33 @@ foreach (name, sanei_names) { } } +ohos_source_set("sanei_usb") { + include_dirs = [ + "$target_dir/include" + ] + sources = [ + "$target_dir/src/sanei_usb.c", + "$target_dir/src/usb_manager.cpp" + ] + + deps = base_deps + deps += [ + ":backends_action" + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "usb_manager:usbsrv_client", + "bounds_checking_function:libsec_shared" + ] + + configs = [":base_config"] + + subsystem_name = "thirdparty" + part_name = "backends" +} + ohos_static_library("sanei") { sources = [] diff --git a/bundle.json b/bundle.json index bc514030d9d7e9ceea8b219aace85ae5c3063505..d76129bd4432089f43cbd064208dbd0410b18d21 100644 --- a/bundle.json +++ b/bundle.json @@ -19,10 +19,12 @@ "ram": "10KB", "deps": { "components": [ - "hilog" + "hilog", + "usb_manager", + "bounds_checking_function", + "c_utils" ], "third_party": [ - "libusb", "libxml2", "libpng", "libjpeg-turbo" diff --git a/install.py b/install.py new file mode 100755 index 0000000000000000000000000000000000000000..dae99bb1ff1cc902ee0a2167f1a465c5e5aef58d --- /dev/null +++ b/install.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import tarfile +import argparse +import os +import subprocess +import sys +import shutil + +def apply_patch(source_dir): + patch_list = [ + 'usbmanager.patch' + ] + + for patch in patch_list: + patch_dir = os.path.join(source_dir, 'patches', patch) + try : + patch_cmd = ['patch', '-p1', "--fuzz=0", "--no-backup-if-mismatch", '-i', patch_dir, '-d', source_dir] + subprocess.run(patch_cmd, check=True) + except Exception as e: + print("apply_patch error, revserse patch") + patch_cmd = ['patch', '-R', '-p1', "--fuzz=0", "--no-backup-if-mismatch", '-i', patch_dir, '-d', source_dir] + subprocess.run(patch_cmd, check=True) + continue + +def cp_file(source_dir, gen_dir): + src_list = [ + 'usb_manager.cpp', + 'sanei_usb.c' + ] + head_list = [ + 'usb_manager.h', + 'config.h' + ] + for src in src_list: + source_file = os.path.join(source_dir, 'sanei', src) + dest_file = os.path.join(gen_dir, 'src', src) + cp_cmd = ['cp', source_file, dest_file] + subprocess.run(cp_cmd, check=True) + for head in head_list: + source_file = os.path.join(source_dir, 'include', 'sane', head) + dest_file = os.path.join(gen_dir, 'include', head) + cp_cmd = ['cp', source_file, dest_file] + subprocess.run(cp_cmd, check=True) + +def main(): + cups_path = argparse.ArgumentParser() + cups_path.add_argument('--gen-dir', help='generate path of log', required=True) + cups_path.add_argument('--source-dir', help='generate path of log', required=True) + args = cups_path.parse_args() + # gen_dir = "${target_gen_dir}/sane" + gen_dir = args.gen_dir + # source_dir = //third_party/backends + source_dir = args.source_dir + apply_patch(source_dir) + cp_file(source_dir, gen_dir) + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/patches/usbmanager.patch b/patches/usbmanager.patch new file mode 100644 index 0000000000000000000000000000000000000000..3db91cb8ebba857850514b0d141a8e69c50ec6aa --- /dev/null +++ b/patches/usbmanager.patch @@ -0,0 +1,2219 @@ +From b7a532f007bb10e18536d64fc53a1b182da37f21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E5=88=98=E6=98=8A=E8=8B=8F?= +Date: Wed, 14 Aug 2024 09:45:08 +0800 +Subject: [PATCH] =?UTF-8?q?libusb=E6=8D=A2=E6=88=90usbmanager=20Signed-off?= + =?UTF-8?q?-by:liuhaosu@huawei.com?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: 刘昊苏 +--- + include/sane/config.h | 5 +- + include/sane/usb_manager.h | 421 ++++++++++++++++++ + sanei/sanei_usb.c | 865 ++++++++++++++++++++++++++++++++++--- + sanei/usb_manager.cpp | 572 ++++++++++++++++++++++++ + 4 files changed, 1794 insertions(+), 69 deletions(-) + create mode 100644 include/sane/usb_manager.h + create mode 100644 sanei/usb_manager.cpp + +diff --git a/include/sane/config.h b/include/sane/config.h +index 22234857f..08fa8accd 100644 +--- a/include/sane/config.h ++++ b/include/sane/config.h +@@ -207,7 +207,10 @@ + #define HAVE_LIBSNMP 0 + + /* Define to 1 if you have libusb-1.0 */ +-#define HAVE_LIBUSB 1 ++// #define HAVE_LIBUSB 1 ++ ++/* Define to 1 if you have usb_manager */ ++#define HAVE_USB_MANAGER 1 + + /* Define to 1 if you have libusb-0.1 */ + /* #undef HAVE_LIBUSB_LEGACY */ +diff --git a/include/sane/usb_manager.h b/include/sane/usb_manager.h +new file mode 100644 +index 000000000..a25e4f67c +--- /dev/null ++++ b/include/sane/usb_manager.h +@@ -0,0 +1,421 @@ ++/* ++ * Copyright (c) 2024 Huawei Device Co., Ltd. ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef USB_MANAGER_H ++#define USB_MANAGER_H ++ ++#include ++#include ++ ++#include "hilog/log.h" ++#define SANE_LOG_TAG "sanekit" ++#define SANE_HILOG_INFO(...) ((void)HiLogPrint(LOG_APP, LOG_INFO, 0, "sanekit", __VA_ARGS__)) ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define USB_MANAGER_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ ++#define USB_MANAGER_ENDPOINT_DIR_MASK 0x80 ++#define USB_DT_CONFIGURATION 0x02 ++#define USB_DT_INTERFACE 0x04 ++#define USB_DT_ENDPOINT 0x05 ++ ++enum usb_manager_option { ++ USB_MANAGER_OPTION_LOG_LEVEL = 0, ++}; ++ ++/** \ingroup usb_manager_desc ++ * Endpoint direction. Values for bit 7 of the ++ * \ref usb_manager_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. ++ */ ++enum usb_manager_endpoint_direction { ++ /** Out: host-to-device */ ++ USB_MANAGER_ENDPOINT_OUT = 0x00, ++ ++ /** In: device-to-host */ ++ USB_MANAGER_ENDPOINT_IN = 0x80 ++}; ++ ++enum usb_manager_transfer_type { ++ /** Control transfer */ ++ USB_MANAGER_TRANSFER_TYPE_CONTROL = 0U, ++ ++ /** Isochronous transfer */ ++ USB_MANAGER_TRANSFER_TYPE_ISOCHRONOUS = 1U, ++ ++ /** Bulk transfer */ ++ USB_MANAGER_TRANSFER_TYPE_BULK = 2U, ++ ++ /** Interrupt transfer */ ++ USB_MANAGER_TRANSFER_TYPE_INTERRUPT = 3U, ++ ++ /** Bulk stream transfer */ ++ USB_MANAGER_TRANSFER_TYPE_BULK_STREAM = 4U ++}; ++ ++enum usb_manager_error { ++ /** Success (no error) */ ++ USB_MANAGER_SUCCESS = 0, ++ ++ /** Input/output error */ ++ USB_MANAGER_ERROR_IO = -1, ++ ++ /** Invalid parameter */ ++ USB_MANAGER_ERROR_INVALID_PARAM = -2, ++ ++ /** Access denied (insufficient permissions) */ ++ USB_MANAGER_ERROR_ACCESS = -3, ++ ++ /** No such device (it may have been disconnected) */ ++ USB_MANAGER_ERROR_NO_DEVICE = -4, ++ ++ /** Entity not found */ ++ USB_MANAGER_ERROR_NOT_FOUND = -5, ++ ++ /** Resource busy */ ++ USB_MANAGER_ERROR_BUSY = -6, ++ ++ /** Operation timed out */ ++ USB_MANAGER_ERROR_TIMEOUT = -7, ++ ++ /** Overflow */ ++ USB_MANAGER_ERROR_OVERFLOW = -8, ++ ++ /** Pipe error */ ++ USB_MANAGER_ERROR_PIPE = -9, ++ ++ /** System call interrupted (perhaps due to signal) */ ++ USB_MANAGER_ERROR_INTERRUPTED = -10, ++ ++ /** Insufficient memory */ ++ USB_MANAGER_ERROR_NO_MEM = -11, ++ ++ /** Operation not supported or unimplemented on this platform */ ++ USB_MANAGER_ERROR_NOT_SUPPORTED = -12, ++ ++ /* NB: Remember to update USB_MANAGER_ERROR_COUNT below as well as the ++ message strings in strerror.c when adding new error codes here. */ ++ ++ /** Other error */ ++ USB_MANAGER_ERROR_OTHER = -99 ++}; ++ ++/** \ingroup usb_manager_desc ++ * Device and/or Interface Class codes */ ++enum usb_manager_class_code { ++ /** In the context of a \ref usb_manager_device_descriptor "device descriptor", ++ * this bDeviceClass value indicates that each interface specifies its ++ * own class information and all interfaces operate independently. ++ */ ++ USB_MANAGER_CLASS_PER_INTERFACE = 0x00, ++ ++ /** Audio class */ ++ USB_MANAGER_CLASS_AUDIO = 0x01, ++ ++ /** Communications class */ ++ USB_MANAGER_CLASS_COMM = 0x02, ++ ++ /** Human Interface Device class */ ++ USB_MANAGER_CLASS_HID = 0x03, ++ ++ /** Physical */ ++ USB_MANAGER_CLASS_PHYSICAL = 0x05, ++ ++ /** Image class */ ++ USB_MANAGER_CLASS_IMAGE = 0x06, ++ USB_MANAGER_CLASS_PTP = 0x06, /* legacy name from usb manager usb.h */ ++ ++ /** Printer class */ ++ USB_MANAGER_CLASS_PRINTER = 0x07, ++ ++ /** Mass storage class */ ++ USB_MANAGER_CLASS_MASS_STORAGE = 0x08, ++ ++ /** Hub class */ ++ USB_MANAGER_CLASS_HUB = 0x09, ++ ++ /** Data class */ ++ USB_MANAGER_CLASS_DATA = 0x0a, ++ ++ /** Smart Card */ ++ USB_MANAGER_CLASS_SMART_CARD = 0x0b, ++ ++ /** Content Security */ ++ USB_MANAGER_CLASS_CONTENT_SECURITY = 0x0d, ++ ++ /** Video */ ++ USB_MANAGER_CLASS_VIDEO = 0x0e, ++ ++ /** Personal Healthcare */ ++ USB_MANAGER_CLASS_PERSONAL_HEALTHCARE = 0x0f, ++ ++ /** Diagnostic Device */ ++ USB_MANAGER_CLASS_DIAGNOSTIC_DEVICE = 0xdc, ++ ++ /** Wireless class */ ++ USB_MANAGER_CLASS_WIRELESS = 0xe0, ++ ++ /** Miscellaneous class */ ++ USB_MANAGER_CLASS_MISCELLANEOUS = 0xef, ++ ++ /** Application class */ ++ USB_MANAGER_CLASS_APPLICATION = 0xfe, ++ ++ /** Class is vendor-specific */ ++ USB_MANAGER_CLASS_VENDOR_SPEC = 0xff ++}; ++ ++/** \ingroup usb_manager_desc ++ * A structure representing the standard USB device descriptor. This ++ * descriptor is documented in section 9.6.1 of the USB 3.0 specification. ++ * All multiple-byte fields are represented in host-endian format. ++ */ ++struct usb_manager_device_descriptor { ++ /** Size of this descriptor (in bytes) */ ++ uint8_t bLength; ++ ++ /** Descriptor type. Will have value ++ * \ref usb_manager_descriptor_type::USB_MANAGER_DT_DEVICE USB_MANAGER_DT_DEVICE in this ++ * context. */ ++ uint8_t bDescriptorType; ++ ++ /** USB specification release number in binary-coded decimal. A value of ++ * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ ++ uint16_t bcdUSB; ++ ++ /** USB-IF class code for the device. See \ref usb_manager_class_code. */ ++ uint8_t bDeviceClass; ++ ++ /** USB-IF subclass code for the device, qualified by the bDeviceClass ++ * value */ ++ uint8_t bDeviceSubClass; ++ ++ /** USB-IF protocol code for the device, qualified by the bDeviceClass and ++ * bDeviceSubClass values */ ++ uint8_t bDeviceProtocol; ++ ++ /** Maximum packet size for endpoint 0 */ ++ uint8_t bMaxPacketSize0; ++ ++ /** USB-IF vendor ID */ ++ uint16_t idVendor; ++ ++ /** USB-IF product ID */ ++ uint16_t idProduct; ++ ++ /** Device release number in binary-coded decimal */ ++ uint16_t bcdDevice; ++ ++ /** Index of string descriptor describing manufacturer */ ++ uint8_t iManufacturer; ++ ++ /** Index of string descriptor describing product */ ++ uint8_t iProduct; ++ ++ /** Index of string descriptor containing device serial number */ ++ uint8_t iSerialNumber; ++ ++ /** Number of possible configurations */ ++ uint8_t bNumConfigurations; ++}; ++ ++/** \ingroup usb_manager_desc ++ * A structure representing the standard USB endpoint descriptor. This ++ * descriptor is documented in section 9.6.6 of the USB 3.0 specification. ++ * All multiple-byte fields are represented in host-endian format. ++ */ ++struct usb_manager_endpoint_descriptor { ++ /** Size of this descriptor (in bytes) */ ++ uint8_t bLength; ++ ++ /** Descriptor type. Will have value ++ * \ref usb_manager_descriptor_type::USB_MANAGER_DT_ENDPOINT USB_MANAGER_DT_ENDPOINT in ++ * this context. */ ++ uint8_t bDescriptorType; ++ ++ /** The address of the endpoint described by this descriptor. Bits 0:3 are ++ * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, ++ * see \ref usb_manager_endpoint_direction. */ ++ uint8_t bEndpointAddress; ++ ++ /** Attributes which apply to the endpoint when it is configured using ++ * the bConfigurationValue. Bits 0:1 determine the transfer type and ++ * correspond to \ref usb_manager_endpoint_transfer_type. Bits 2:3 are only used ++ * for isochronous endpoints and correspond to \ref usb_manager_iso_sync_type. ++ * Bits 4:5 are also only used for isochronous endpoints and correspond to ++ * \ref usb_manager_iso_usage_type. Bits 6:7 are reserved. */ ++ uint8_t bmAttributes; ++ ++ /** Maximum packet size this endpoint is capable of sending/receiving. */ ++ uint16_t wMaxPacketSize; ++ ++ /** Interval for polling endpoint for data transfers. */ ++ uint8_t bInterval; ++ ++ /** For audio devices only: the rate at which synchronization feedback ++ * is provided. */ ++ uint8_t bRefresh; ++ ++ /** For audio devices only: the address if the synch endpoint */ ++ uint8_t bSynchAddress; ++}; ++ ++/** \ingroup usb_manager_desc ++ * A structure representing the standard USB interface descriptor. This ++ * descriptor is documented in section 9.6.5 of the USB 3.0 specification. ++ * All multiple-byte fields are represented in host-endian format. ++ */ ++struct usb_manager_interface_descriptor { ++ /** Size of this descriptor (in bytes) */ ++ uint8_t bLength; ++ ++ /** Descriptor type. Will have value ++ * \ref usb_manager_descriptor_type::USB_MANAGER_DT_INTERFACE USB_MANAGER_DT_INTERFACE ++ * in this context. */ ++ uint8_t bDescriptorType; ++ ++ /** Number of this interface */ ++ uint8_t bInterfaceNumber; ++ ++ /** Value used to select this alternate setting for this interface */ ++ uint8_t bAlternateSetting; ++ ++ /** Number of endpoints used by this interface (excluding the control ++ * endpoint). */ ++ uint8_t bNumEndpoints; ++ ++ /** USB-IF class code for this interface. See \ref usb_manager_class_code. */ ++ uint8_t bInterfaceClass; ++ ++ /** USB-IF subclass code for this interface, qualified by the ++ * bInterfaceClass value */ ++ uint8_t bInterfaceSubClass; ++ ++ /** USB-IF protocol code for this interface, qualified by the ++ * bInterfaceClass and bInterfaceSubClass values */ ++ uint8_t bInterfaceProtocol; ++ ++ /** Index of string descriptor describing this interface */ ++ uint8_t iInterface; ++ ++ /** Array of endpoint descriptors. This length of this array is determined ++ * by the bNumEndpoints field. */ ++ struct usb_manager_endpoint_descriptor *endpoint; ++}; ++ ++ ++/** \ingroup usb_manager_desc ++ * A collection of alternate settings for a particular USB interface. ++ */ ++struct usb_manager_interface { ++ /** Array of interface descriptors. The length of this array is determined ++ * by the num_altsetting field. */ ++ struct usb_manager_interface_descriptor *altsetting; ++ ++ /** The number of alternate settings that belong to this interface. ++ * Must be non-negative. */ ++ int num_altsetting; ++}; ++ ++/** \ingroup usb_manager_desc ++ * A structure representing the standard USB configuration descriptor. This ++ * descriptor is documented in section 9.6.3 of the USB 3.0 specification. ++ * All multiple-byte fields are represented in host-endian format. ++ */ ++struct usb_manager_config_descriptor { ++ /** Size of this descriptor (in bytes) */ ++ uint8_t bLength; ++ ++ /** Descriptor type. Will have value ++ * \ref usb_manager_descriptor_type::USB_MANAGER_DT_CONFIG USB_MANAGER_DT_CONFIG ++ * in this context. */ ++ uint8_t bDescriptorType; ++ ++ /** Total length of data returned for this configuration */ ++ uint16_t wTotalLength; ++ ++ /** Number of interfaces supported by this configuration */ ++ uint8_t bNumInterfaces; ++ ++ /** Identifier value for this configuration */ ++ uint8_t bConfigurationValue; ++ ++ /** Index of string descriptor describing this configuration */ ++ uint8_t iConfiguration; ++ ++ /** Configuration characteristics */ ++ uint8_t bmAttributes; ++ ++ /** Maximum power consumption of the USB device from this bus in this ++ * configuration when the device is fully operation. Expressed in units ++ * of 2 mA when the device is operating in high-speed mode and in units ++ * of 8 mA when the device is operating in super-speed mode. */ ++ uint8_t MaxPower; ++ ++ /** Array of interfaces supported by this configuration. The length of ++ * this array is determined by the bNumInterfaces field. */ ++ struct usb_manager_interface *interface; ++}; ++ ++struct usb_manager_device; ++ ++struct usb_manager_device_handle; ++ ++struct usb_manager_context { ++ struct usb_manager_device *devices; ++ uint32_t deviceCount; ++}; ++ ++typedef struct usb_manager_context usb_manager_context; ++typedef struct usb_manager_device usb_manager_device; ++typedef struct usb_manager_device_handle usb_manager_device_handle; ++typedef struct usb_manager_device_descriptor usb_manager_device_descriptor; ++typedef struct usb_manager_config_descriptor usb_manager_config_descriptor; ++ ++int usb_manager_init(usb_manager_context **ctx); ++int usb_manager_exit(usb_manager_context *ctx); ++ssize_t usb_manager_get_device_list(usb_manager_context *ctx, usb_manager_device ***list); ++int usb_manager_get_bus_number(usb_manager_device *dev); ++int usb_manager_get_device_address(usb_manager_device *dev); ++int usb_manager_get_device_descriptor(usb_manager_device *dev, usb_manager_device_descriptor *desc); ++int usb_manager_open(usb_manager_device *dev, usb_manager_device_handle **dev_handle); ++void usb_manager_close(usb_manager_device_handle *dev_handle); ++int usb_manager_get_configuration(usb_manager_device_handle *dev, int *config); ++int usb_manager_get_config_descriptor(usb_manager_device *dev, uint8_t config_index, ++ usb_manager_config_descriptor **config); ++void usb_manager_free_config_descriptor(usb_manager_config_descriptor *config); ++void usb_manager_free_device_list(usb_manager_device **list, int unref_devices); ++int usb_manager_set_configuration(usb_manager_device_handle *dev_handle, int configuration); ++int usb_manager_claim_interface(usb_manager_device_handle *dev_handle, int interface_number); ++int usb_manager_release_interface(usb_manager_device_handle *dev_handle, int interface_number); ++int usb_manager_clear_halt(usb_manager_device_handle *dev_handle, unsigned char endpoint); ++int usb_manager_reset_device(usb_manager_device_handle *dev_handle); ++int usb_manager_bulk_transfer(usb_manager_device_handle *dev_handle, unsigned char endpoint, ++ unsigned char *data, int length, int *transferred, unsigned int timeout); ++int usb_manager_control_transfer(usb_manager_device_handle *dev_handle, uint8_t request_type, ++ uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, ++ unsigned int timeout); ++int usb_manager_interrupt_transfer(usb_manager_device_handle *dev_handle, unsigned char endpoint, ++ unsigned char *data, int length, int *actual_length, unsigned int timeout); ++int usb_manager_set_interface_alt_setting(usb_manager_device_handle *dev_handle, int interface_number, ++ int alternate_setting); ++usb_manager_device * usb_manager_ref_device(usb_manager_device *dev); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* USB_MANAGER_H */ +\ No newline at end of file +diff --git a/sanei/sanei_usb.c b/sanei/sanei_usb.c +index 022f6fab9..66dbdb730 100644 +--- a/sanei/sanei_usb.c ++++ b/sanei/sanei_usb.c +@@ -84,6 +84,10 @@ + #include + #endif /* HAVE_LIBUSB */ + ++#ifdef HAVE_USB_MANAGER ++#include "usb_manager.h" ++#endif /* HAVE_USB_MANAGER */ ++ + #ifdef HAVE_USBCALLS + #include + #include +@@ -129,7 +133,9 @@ typedef enum + (Linux, BSD) */ + sanei_usb_method_libusb, + +- sanei_usb_method_usbcalls ++ sanei_usb_method_usbcalls, ++ ++ sanei_usb_method_usb_manager + } + sanei_usb_access_method_type; + +@@ -160,6 +166,11 @@ typedef struct + libusb_device *lu_device; + libusb_device_handle *lu_handle; + #endif /* HAVE_LIBUSB */ ++#ifdef HAVE_USB_MANAGER ++ usb_manager_device *usb_manager_device; ++ usb_manager_device_handle *usb_manager_handle; ++#endif /* HAVE_USB_MANAGER */ ++ + } + device_list_type; + +@@ -212,10 +223,19 @@ static xmlNode* testing_xml_next_tx_node = NULL; + static int libusb_timeout = 30 * 1000; /* 30 seconds */ + #endif /* HAVE_LIBUSB_LEGACY */ + ++#ifdef HAVE_USB_MANAGER ++static int usb_manager_timeout = 30 * 1000; /* 30 seconds */ ++#endif /* HAVE_USB_MANAGER */ ++ ++ + #ifdef HAVE_LIBUSB + static libusb_context *sanei_usb_ctx; + #endif /* HAVE_LIBUSB */ + ++#ifdef HAVE_USB_MANAGER ++static usb_manager_context *sanei_usb_ctx; ++#endif /* HAVE_USB_MANAGER */ ++ + #if defined (__APPLE__) + /* macOS won't configure several USB scanners (i.e. ScanSnap 300M) because their + * descriptors are vendor specific. As a result the device will get configured +@@ -299,7 +319,7 @@ print_buffer (const SANE_Byte * buffer, SANE_Int size) + } + } + +-#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) ++#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) + static void + kernel_get_vendor_product (int fd, const char *name, int *vendorID, int *productID) + { +@@ -373,7 +393,7 @@ kernel_get_vendor_product (int fd, const char *name, int *vendorID, int *product + #endif /* defined (__linux__), defined(__BEOS__), ... */ + /* put more os-dependant stuff ... */ + } +-#endif /* !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) */ ++#endif /* !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) */ + + /** + * store the given device in device list if it isn't already +@@ -405,6 +425,9 @@ store_device (device_list_type device) + #ifdef HAVE_LIBUSB + devices[i].lu_device = device.lu_device; + #endif ++#ifdef HAVE_USB_MANAGER ++ devices[i].usb_manager_device = device.usb_manager_device; ++#endif + + devices[i].missing=0; + DBG (3, "store_device: not storing device %s\n", device.devname); +@@ -497,6 +520,62 @@ sanei_libusb_strerror (int errcode) + } + #endif /* HAVE_LIBUSB */ + ++#ifdef HAVE_USB_MANAGER ++static char * ++sanei_usb_manager_strerror (int errcode) ++{ ++ /* Error codes & descriptions from the usb_manager documentation */ ++ ++ switch (errcode) ++ { ++ case USB_MANAGER_SUCCESS: ++ return "Success (no error)"; ++ ++ case USB_MANAGER_ERROR_IO: ++ return "Input/output error"; ++ ++ case USB_MANAGER_ERROR_INVALID_PARAM: ++ return "Invalid parameter"; ++ ++ case USB_MANAGER_ERROR_ACCESS: ++ return "Access denied (insufficient permissions)"; ++ ++ case USB_MANAGER_ERROR_NO_DEVICE: ++ return "No such device (it may have been disconnected)"; ++ ++ case USB_MANAGER_ERROR_NOT_FOUND: ++ return "Entity not found"; ++ ++ case USB_MANAGER_ERROR_BUSY: ++ return "Resource busy"; ++ ++ case USB_MANAGER_ERROR_TIMEOUT: ++ return "Operation timed out"; ++ ++ case USB_MANAGER_ERROR_OVERFLOW: ++ return "Overflow"; ++ ++ case USB_MANAGER_ERROR_PIPE: ++ return "Pipe error"; ++ ++ case USB_MANAGER_ERROR_INTERRUPTED: ++ return "System call interrupted (perhaps due to signal)"; ++ ++ case USB_MANAGER_ERROR_NO_MEM: ++ return "Insufficient memory"; ++ ++ case USB_MANAGER_ERROR_NOT_SUPPORTED: ++ return "Operation not supported or unimplemented on this platform"; ++ ++ case USB_MANAGER_ERROR_OTHER: ++ return "Other error"; ++ ++ default: ++ return "Unknown usb_manager error code"; ++ } ++} ++#endif /* HAVE_USB_MANAGER */ ++ + #if WITH_USB_RECORD_REPLAY + SANE_Status sanei_usb_testing_enable_replay(SANE_String_Const path, + int development_mode) +@@ -1380,9 +1459,9 @@ void sanei_usb_testing_record_message(SANE_String_Const message) + void + sanei_usb_init (void) + { +-#ifdef HAVE_LIBUSB ++#if defined(HAVE_LIBUSB) || defined(HAVE_USB_MANAGER) + int ret; +-#endif /* HAVE_LIBUSB */ ++#endif /* HAVE_LIBUSB || HAVE_USB_MANAGER */ + + DBG_INIT (); + #ifdef DBG_LEVEL +@@ -1451,7 +1530,22 @@ sanei_usb_init (void) + } + #endif /* HAVE_LIBUSB */ + +-#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) ++#ifdef HAVE_USB_MANAGER ++ if (!sanei_usb_ctx) ++ { ++ DBG (4, "%s: initializing usb_manager\n", __func__); ++ ret = usb_manager_init (&sanei_usb_ctx); ++ if (ret < 0) ++ { ++ DBG (1, ++ "%s: failed to initialize usb_manager, error %d\n", __func__, ++ ret); ++ return; ++ } ++ } ++#endif /* HAVE_USB_MANAGER */ ++ ++#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) + DBG (4, "%s: SANE is built without support for libusb\n", __func__); + #endif + +@@ -1498,14 +1592,21 @@ int i; + devices[i].devname=NULL; + } + } +-#ifdef HAVE_LIBUSB ++#if defined(HAVE_LIBUSB) + if (sanei_usb_ctx) + { + libusb_exit (sanei_usb_ctx); + /* reset libusb-1.0 context */ + sanei_usb_ctx=NULL; + } +-#endif ++#elif defined(HAVE_USB_MANAGER) ++ if (sanei_usb_ctx) ++ { ++ usb_manager_exit (sanei_usb_ctx); ++ /* reset usb_manager context */ ++ sanei_usb_ctx=NULL; ++ } ++#endif /* HAVE_LIBUSB || HAVE_USB_MANAGER */ + /* reset device_number */ + device_number=0; + } +@@ -1588,7 +1689,7 @@ static void usbcall_scan_devices(void) + } + #endif /* HAVE_USBCALLS */ + +-#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) ++#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) + /** scan for devices using kernel device. + * Check for devices using kernel device + */ +@@ -1687,7 +1788,7 @@ static void kernel_scan_devices(void) + closedir (dir); + } + } +-#endif /* !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) */ ++#endif /* !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) */ + + #ifdef HAVE_LIBUSB_LEGACY + /** scan for devices using old libusb +@@ -1980,6 +2081,183 @@ static void libusb_scan_devices(void) + } + #endif /* HAVE_LIBUSB */ + ++#ifdef HAVE_USB_MANAGER ++/** scan for devices using usb_manager ++ * Check for devices using usb_manager ++ */ ++static void libusb_scan_devices(void) ++{ ++ device_list_type device; ++ SANE_Char devname[1024]; ++ usb_manager_device **devlist; ++ ssize_t ndev; ++ usb_manager_device *dev; ++ usb_manager_device_handle *hdl; ++ struct usb_manager_device_descriptor desc; ++ struct usb_manager_config_descriptor *config0; ++ unsigned short vid, pid; ++ unsigned char busno, address; ++ int config; ++ int interface; ++ int ret; ++ int i; ++ ++ DBG (4, "%s: Looking for usb_manager devices\n", __func__); ++ ++ ndev = usb_manager_get_device_list (sanei_usb_ctx, &devlist); ++ if (ndev < 0) ++ { ++ DBG (1, ++ "%s: failed to get usb_manager device list, error %d\n", __func__, ++ (int) ndev); ++ return; ++ } ++ ++ for (i = 0; i < ndev; i++) ++ { ++ SANE_Bool found = SANE_FALSE; ++ ++ dev = devlist[i]; ++ ++ busno = usb_manager_get_bus_number (dev); ++ address = usb_manager_get_device_address (dev); ++ ++ ret = usb_manager_get_device_descriptor (dev, &desc); ++ if (ret < 0) ++ { ++ DBG (1, ++ "%s: could not get device descriptor for device at %03d:%03d (err %d)\n", __func__, ++ busno, address, ret); ++ continue; ++ } ++ ++ vid = desc.idVendor; ++ pid = desc.idProduct; ++ ++ if ((vid == 0) || (pid == 0)) ++ { ++ DBG (5, ++ "%s: device 0x%04x/0x%04x at %03d:%03d looks like a root hub\n", __func__, ++ vid, pid, busno, address); ++ continue; ++ } ++ ++ ret = usb_manager_open (dev, &hdl); ++ if (ret < 0) ++ { ++ DBG (1, ++ "%s: skipping device 0x%04x/0x%04x at %03d:%03d: cannot open: %s\n", __func__, ++ vid, pid, busno, address, sanei_usb_manager_strerror (ret)); ++ ++ continue; ++ } ++ ++ ret = usb_manager_get_configuration (hdl, &config); ++ ++ usb_manager_close (hdl); ++ ++ if (ret < 0) ++ { ++ DBG (1, ++ "%s: could not get configuration for device 0x%04x/0x%04x at %03d:%03d (err %d)\n", __func__, ++ vid, pid, busno, address, ret); ++ continue; ++ } ++ ++#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES) ++ if (config == 0) ++ { ++ DBG (1, ++ "%s: device 0x%04x/0x%04x at %03d:%03d is not configured\n", __func__, ++ vid, pid, busno, address); ++ continue; ++ } ++#endif ++ ++ ret = usb_manager_get_config_descriptor (dev, 0, &config0); ++ if (ret < 0) ++ { ++ DBG (1, ++ "%s: could not get config[0] descriptor for device 0x%04x/0x%04x at %03d:%03d (err %d)\n", __func__, ++ vid, pid, busno, address, ret); ++ continue; ++ } ++ ++ for (interface = 0; (interface < config0->bNumInterfaces) && !found; interface++) ++ { ++ switch (desc.bDeviceClass) ++ { ++ case USB_MANAGER_CLASS_VENDOR_SPEC: ++ found = SANE_TRUE; ++ break; ++ ++ case USB_MANAGER_CLASS_PER_INTERFACE: ++ if ((config0->interface[interface].num_altsetting == 0) ++ || !config0->interface[interface].altsetting) ++ { ++ DBG (1, "%s: device 0x%04x/0x%04x doesn't " ++ "have an altsetting for interface %d\n", __func__, ++ vid, pid, interface); ++ continue; ++ } ++ ++ switch (config0->interface[interface].altsetting[0].bInterfaceClass) ++ { ++ case USB_MANAGER_CLASS_VENDOR_SPEC: ++ case USB_MANAGER_CLASS_PER_INTERFACE: ++ case USB_MANAGER_CLASS_PTP: ++ case 16: /* data? */ ++ found = SANE_TRUE; ++ break; ++ } ++ break; ++ } ++ ++ if (!found) ++ DBG (5, ++ "%s: device 0x%04x/0x%04x, interface %d " ++ "doesn't look like a scanner (%d/%d)\n", __func__, ++ vid, pid, interface, desc.bDeviceClass, ++ (config0->interface[interface].num_altsetting != 0) ++ ? config0->interface[interface].altsetting[0].bInterfaceClass : -1); ++ } ++ ++ usb_manager_free_config_descriptor (config0); ++ ++ interface--; ++ ++ if (!found) ++ { ++ DBG (5, ++ "%s: device 0x%04x/0x%04x at %03d:%03d: no suitable interfaces\n", __func__, ++ vid, pid, busno, address); ++ continue; ++ } ++ ++ memset (&device, 0, sizeof (device)); ++ device.usb_manager_device = usb_manager_ref_device(dev); ++ snprintf (devname, sizeof (devname), "libusb:%03d:%03d", ++ busno, address); ++ device.devname = strdup (devname); ++ if (!device.devname) ++ return; ++ device.vendor = vid; ++ device.product = pid; ++ device.method = sanei_usb_method_libusb; ++ device.interface_nr = interface; ++ device.alt_setting = 0; ++ DBG (4, ++ "%s: found usb_manager device (0x%04x/0x%04x) interface " ++ "%d at %s\n", __func__, ++ vid, pid, interface, devname); ++ ++ store_device (device); ++ } ++ ++ usb_manager_free_device_list (devlist, 1); ++ ++} ++#endif /* HAVE_USB_MANAGER */ + + void + sanei_usb_scan_devices (void) +@@ -2009,11 +2287,11 @@ sanei_usb_scan_devices (void) + } + + /* Check for devices using the kernel scanner driver */ +-#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) ++#if !defined(HAVE_LIBUSB_LEGACY) && !defined(HAVE_LIBUSB) && !defined(HAVE_USB_MANAGER) + kernel_scan_devices(); + #endif + +-#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) ++#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) || defined(HAVE_USB_MANAGER) + /* Check for devices using libusb (old or new)*/ + libusb_scan_devices(); + #endif +@@ -2223,7 +2501,7 @@ sanei_usb_set_endpoint (SANE_Int dn, SANE_Int ep_type, SANE_Int ep) + } + } + +-#if HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USBCALLS || WITH_USB_RECORD_REPLAY ++#if HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USBCALLS || WITH_USB_RECORD_REPLAY || HAVE_USB_MANAGER + static const char* sanei_usb_transfer_type_desc(SANE_Int transfer_type) + { + switch (transfer_type) +@@ -2292,7 +2570,7 @@ static void sanei_usb_add_endpoint(device_list_type* device, + *ep_out = ep_address; + } + } +-#endif // HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USBCALLS ++#endif // HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USBCALLS || HAVE_USB_MANAGER + + SANE_Int + sanei_usb_get_endpoint (SANE_Int dn, SANE_Int ep_type) +@@ -2815,43 +3093,261 @@ sanei_usb_open (SANE_String_Const devname, SANE_Int * dn) + + libusb_free_config_descriptor (config); + } ++#elif defined(HAVE_USB_MANAGER) /* usb_manager */ + +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ +- DBG (1, "sanei_usb_open: can't open device `%s': " +- "libusb support missing\n", devname); +- return SANE_STATUS_UNSUPPORTED; +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ +- } +- else if (devices[devcount].method == sanei_usb_method_scanner_driver) +- { +-#ifdef FD_CLOEXEC +- long int flag; +-#endif +- /* Using kernel scanner driver */ +- devices[devcount].fd = -1; +-#ifdef HAVE_RESMGR +- devices[devcount].fd = rsm_open_device (devname, O_RDWR); +-#endif +- if (devices[devcount].fd == -1) +- devices[devcount].fd = open (devname, O_RDWR); +- if (devices[devcount].fd < 0) ++ int config; ++ usb_manager_device *dev; ++ struct usb_manager_device_descriptor desc; ++ struct usb_manager_config_descriptor *config0; ++ int result, num; ++ int c, i, a; ++ ++ dev = devices[devcount].usb_manager_device; ++ ++ result = usb_manager_open (dev, &devices[devcount].usb_manager_handle); ++ if (result < 0) + { + SANE_Status status = SANE_STATUS_INVAL; + +- if (errno == EACCES) +- status = SANE_STATUS_ACCESS_DENIED; +- else if (errno == ENOENT) ++ DBG (1, "sanei_usb_open: can't open device `%s': %s\n", ++ devname, sanei_usb_manager_strerror (result)); ++ if (result == USB_MANAGER_ERROR_ACCESS) + { +- DBG (5, "sanei_usb_open: open of `%s' failed: %s\n", +- devname, strerror (errno)); +- return status; ++ DBG (1, "Make sure you run as root or set appropriate " ++ "permissions\n"); ++ status = SANE_STATUS_ACCESS_DENIED; ++ } ++ else if (result == USB_MANAGER_ERROR_BUSY) ++ { ++ DBG (1, "Maybe the kernel scanner driver claims the " ++ "scanner's interface?\n"); ++ status = SANE_STATUS_DEVICE_BUSY; ++ } ++ else if (result == USB_MANAGER_ERROR_NO_MEM) ++ { ++ status = SANE_STATUS_NO_MEM; + } +- DBG (1, "sanei_usb_open: open of `%s' failed: %s\n", +- devname, strerror (errno)); + return status; + } +-#ifdef FD_CLOEXEC +- flag = fcntl (devices[devcount].fd, F_GETFD); ++ ++ result = usb_manager_get_configuration (devices[devcount].usb_manager_handle, &config); ++ if (result < 0) ++ { ++ DBG (1, ++ "sanei_usb_open: could not get configuration for device `%s' (err %d)\n", ++ devname, result); ++ return SANE_STATUS_INVAL; ++ } ++ ++#if !defined(SANEI_ALLOW_UNCONFIGURED_DEVICES) ++ if (config == 0) ++ { ++ DBG (1, "sanei_usb_open: device `%s' not configured?\n", devname); ++ return SANE_STATUS_INVAL; ++ } ++#endif ++ ++ result = usb_manager_get_device_descriptor (dev, &desc); ++ if (result < 0) ++ { ++ DBG (1, ++ "sanei_usb_open: could not get device descriptor for device `%s' (err %d)\n", ++ devname, result); ++ return SANE_STATUS_INVAL; ++ } ++ ++ result = usb_manager_get_config_descriptor (dev, 0, &config0); ++ if (result < 0) ++ { ++ DBG (1, ++ "sanei_usb_open: could not get config[0] descriptor for device `%s' (err %d)\n", ++ devname, result); ++ return SANE_STATUS_INVAL; ++ } ++ ++ /* Set the configuration */ ++ if (desc.bNumConfigurations > 1) ++ { ++ DBG (3, "sanei_usb_open: more than one " ++ "configuration (%d), choosing first config (%d)\n", ++ desc.bNumConfigurations, ++ config0->bConfigurationValue); ++ ++ result = 0; ++ if (config != config0->bConfigurationValue) ++ result = usb_manager_set_configuration (devices[devcount].usb_manager_handle, ++ config0->bConfigurationValue); ++ ++ if (result < 0) ++ { ++ SANE_Status status = SANE_STATUS_INVAL; ++ ++ DBG (1, "sanei_usb_open: usb_manager complained: %s\n", ++ sanei_usb_manager_strerror (result)); ++ if (result == USB_MANAGER_ERROR_ACCESS) ++ { ++ DBG (1, "Make sure you run as root or set appropriate " ++ "permissions\n"); ++ status = SANE_STATUS_ACCESS_DENIED; ++ } ++ else if (result == USB_MANAGER_ERROR_BUSY) ++ { ++ DBG (3, "Maybe the kernel scanner driver or usblp claims " ++ "the interface? Ignoring this error...\n"); ++ status = SANE_STATUS_GOOD; ++ } ++ ++ if (status != SANE_STATUS_GOOD) ++ { ++ usb_manager_close (devices[devcount].usb_manager_handle); ++ usb_manager_free_config_descriptor (config0); ++ return status; ++ } ++ } ++ } ++ usb_manager_free_config_descriptor (config0); ++ ++ /* Claim the interface */ ++ result = usb_manager_claim_interface (devices[devcount].usb_manager_handle, ++ devices[devcount].interface_nr); ++ if (result < 0) ++ { ++ SANE_Status status = SANE_STATUS_INVAL; ++ ++ DBG (1, "sanei_usb_open: usb_manager complained: %s\n", ++ sanei_usb_manager_strerror (result)); ++ if (result == USB_MANAGER_ERROR_ACCESS) ++ { ++ DBG (1, "Make sure you run as root or set appropriate " ++ "permissions\n"); ++ status = SANE_STATUS_ACCESS_DENIED; ++ } ++ else if (result == USB_MANAGER_ERROR_BUSY) ++ { ++ DBG (1, "Maybe the kernel scanner driver claims the " ++ "scanner's interface?\n"); ++ status = SANE_STATUS_DEVICE_BUSY; ++ } ++ ++ usb_manager_close (devices[devcount].usb_manager_handle); ++ return status; ++ } ++ ++ /* Loop through all of the configurations */ ++ for (c = 0; c < desc.bNumConfigurations; c++) ++ { ++ struct usb_manager_config_descriptor *config; ++ ++ result = usb_manager_get_config_descriptor (dev, c, &config); ++ if (result < 0) ++ { ++ DBG (1, ++ "sanei_usb_open: could not get config[%d] descriptor for device `%s' (err %d)\n", ++ c, devname, result); ++ continue; ++ } ++ ++ /* Loop through all of the interfaces */ ++ for (i = 0; i < config->bNumInterfaces; i++) ++ { ++ /* Loop through all of the alternate settings */ ++ for (a = 0; a < config->interface[i].num_altsetting; a++) ++ { ++ const struct usb_manager_interface_descriptor *interface; ++ ++ DBG (5, "sanei_usb_open: configuration nr: %d\n", c); ++ DBG (5, "sanei_usb_open: interface nr: %d\n", i); ++ DBG (5, "sanei_usb_open: alt_setting nr: %d\n", a); ++ ++ /* Start by interfaces found in sanei_usb_init */ ++ if (c == 0 && i != devices[devcount].interface_nr) ++ { ++ DBG (5, "sanei_usb_open: interface %d not detected as " ++ "a scanner by sanei_usb_init, ignoring.\n", i); ++ continue; ++ } ++ ++ interface = &config->interface[i].altsetting[a]; ++ ++ /* Now we look for usable endpoints */ ++ for (num = 0; num < interface->bNumEndpoints; num++) ++ { ++ const struct usb_manager_endpoint_descriptor *endpoint; ++ int direction, transfer_type, transfer_type_usb_manager; ++ ++ endpoint = &interface->endpoint[num]; ++ DBG (5, "sanei_usb_open: endpoint nr: %d\n", num); ++ ++ transfer_type_usb_manager = ++ endpoint->bmAttributes & USB_MANAGER_TRANSFER_TYPE_MASK; ++ direction = endpoint->bEndpointAddress & USB_MANAGER_ENDPOINT_DIR_MASK; ++ ++ // don't rely on USB_MANAGER_TRANSFER_TYPE_* mapping to ++ // USB_ENDPOINT_TYPE_* even though they'll most likely be ++ // the same ++ switch (transfer_type_usb_manager) ++ { ++ case USB_MANAGER_TRANSFER_TYPE_INTERRUPT: ++ transfer_type = USB_ENDPOINT_TYPE_INTERRUPT; ++ break; ++ case USB_MANAGER_TRANSFER_TYPE_BULK: ++ transfer_type = USB_ENDPOINT_TYPE_BULK; ++ break; ++ case USB_MANAGER_TRANSFER_TYPE_ISOCHRONOUS: ++ transfer_type = USB_MANAGER_TRANSFER_TYPE_ISOCHRONOUS; ++ break; ++ case USB_MANAGER_TRANSFER_TYPE_CONTROL: ++ transfer_type = USB_ENDPOINT_TYPE_CONTROL; ++ break; ++ ++ } ++ ++ sanei_usb_add_endpoint(&devices[devcount], ++ transfer_type, ++ endpoint->bEndpointAddress, ++ direction); ++ } ++ } ++ } ++ ++ usb_manager_free_config_descriptor (config); ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ ++ DBG (1, "sanei_usb_open: can't open device `%s': " ++ "libusb support missing\n", devname); ++ return SANE_STATUS_UNSUPPORTED; ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ ++ } ++ else if (devices[devcount].method == sanei_usb_method_scanner_driver) ++ { ++#ifdef FD_CLOEXEC ++ long int flag; ++#endif ++ /* Using kernel scanner driver */ ++ devices[devcount].fd = -1; ++#ifdef HAVE_RESMGR ++ devices[devcount].fd = rsm_open_device (devname, O_RDWR); ++#endif ++ if (devices[devcount].fd == -1) ++ devices[devcount].fd = open (devname, O_RDWR); ++ if (devices[devcount].fd < 0) ++ { ++ SANE_Status status = SANE_STATUS_INVAL; ++ ++ if (errno == EACCES) ++ status = SANE_STATUS_ACCESS_DENIED; ++ else if (errno == ENOENT) ++ { ++ DBG (5, "sanei_usb_open: open of `%s' failed: %s\n", ++ devname, strerror (errno)); ++ return status; ++ } ++ DBG (1, "sanei_usb_open: open of `%s' failed: %s\n", ++ devname, strerror (errno)); ++ return status; ++ } ++#ifdef FD_CLOEXEC ++ flag = fcntl (devices[devcount].fd, F_GETFD); + if (flag >= 0) + { + if (fcntl (devices[devcount].fd, F_SETFD, flag | FD_CLOEXEC) < 0) +@@ -3061,7 +3557,22 @@ sanei_usb_close (SANE_Int dn) + devices[dn].interface_nr); + libusb_close (devices[dn].lu_handle); + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ /* This call seems to be required by Linux xhci driver ++ * even though it should be a no-op. Without it, the ++ * host or driver does not reset it's data toggle bit. ++ * We intentionally ignore the return val */ ++ if (workaround) ++ { ++ sanei_usb_set_altinterface (dn, devices[dn].alt_setting); ++ } ++ ++ usb_manager_release_interface (devices[dn].usb_manager_handle, ++ devices[dn].interface_nr); ++ usb_manager_close (devices[dn].usb_manager_handle); ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + DBG (1, "sanei_usb_close: libusb support missing\n"); + #endif + devices[dn].open = SANE_FALSE; +@@ -3074,11 +3585,13 @@ sanei_usb_set_timeout (SANE_Int __sane_unused__ timeout) + if (testing_mode == sanei_usb_testing_mode_replay) + return; + +-#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) ++#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) + libusb_timeout = timeout; ++#elif defined(HAVE_USB_MANAGER) ++ usb_manager_timeout = timeout; + #else + DBG (1, "sanei_usb_set_timeout: libusb support missing\n"); +-#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB */ ++#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USB_MANAGER */ + } + + SANE_Status +@@ -3151,9 +3664,32 @@ sanei_usb_clear_halt (SANE_Int dn) + DBG (1, "sanei_usb_clear_halt: BULK_OUT ret=%d\n", ret); + return SANE_STATUS_INVAL; + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ int ret; ++ ++ /* This call seems to be required by Linux xhci driver ++ * even though it should be a no-op. Without it, the ++ * host or driver does not send the clear to the device. ++ * We intentionally ignore the return val */ ++ if (workaround) ++ { ++ sanei_usb_set_altinterface (dn, devices[dn].alt_setting); ++ } ++ ++ ret = usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_in_ep); ++ if (ret){ ++ DBG (1, "sanei_usb_clear_halt: BULK_IN ret=%d\n", ret); ++ return SANE_STATUS_INVAL; ++ } ++ ++ ret = usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_out_ep); ++ if (ret){ ++ DBG (1, "sanei_usb_clear_halt: BULK_OUT ret=%d\n", ret); ++ return SANE_STATUS_INVAL; ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + DBG (1, "sanei_usb_clear_halt: libusb support missing\n"); +-#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB */ ++#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USB_MANAGER */ + + return SANE_STATUS_GOOD; + } +@@ -3181,10 +3717,18 @@ sanei_usb_reset (SANE_Int __sane_unused__ dn) + DBG (1, "sanei_usb_reset: ret=%d\n", ret); + return SANE_STATUS_INVAL; + } ++#elif defined(HAVE_USB_MANAGER) ++ int ret; + +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++ ret = usb_manager_reset_device (devices[dn].usb_manager_handle); ++ if (ret){ ++ DBG (1, "sanei_usb_reset: ret=%d\n", ret); ++ return SANE_STATUS_INVAL; ++ } ++ ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + DBG (1, "sanei_usb_reset: libusb support missing\n"); +-#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB */ ++#endif /* HAVE_LIBUSB_LEGACY || HAVE_LIBUSB || HAVE_USB_MANAGER */ + + return SANE_STATUS_GOOD; + } +@@ -3428,7 +3972,36 @@ sanei_usb_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) + return SANE_STATUS_INVAL; + } + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ if (devices[dn].bulk_in_ep) ++ { ++ int ret, rsize; ++ ret = usb_manager_bulk_transfer (devices[dn].usb_manager_handle, ++ devices[dn].bulk_in_ep, buffer, ++ (int) *size, &rsize, ++ usb_manager_timeout); ++ ++ if (ret < 0) ++ { ++ DBG (1, "sanei_usb_read_bulk: read failed (still got %d bytes): %s\n", ++ rsize, sanei_usb_manager_strerror (ret)); ++ ++ read_size = -1; ++ } ++ else ++ { ++ read_size = rsize; ++ } ++ } ++ else ++ { ++ DBG (1, "sanei_usb_read_bulk: can't read without a bulk-in " ++ "endpoint\n"); ++ return SANE_STATUS_INVAL; ++ } ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + { + DBG (1, "sanei_usb_read_bulk: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; +@@ -3500,6 +4073,9 @@ sanei_usb_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) + #elif defined(HAVE_LIBUSB) + if (devices[dn].method == sanei_usb_method_libusb) + libusb_clear_halt (devices[dn].lu_handle, devices[dn].bulk_in_ep); ++#elif defined(HAVE_USB_MANAGER) ++ if (devices[dn].method == sanei_usb_method_usb_manager) ++ usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_in_ep); + #endif + return SANE_STATUS_IO_ERROR; + } +@@ -3763,12 +4339,40 @@ sanei_usb_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size) + return SANE_STATUS_INVAL; + } + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ if (devices[dn].bulk_out_ep) ++ { ++ int ret; ++ int trans_bytes; ++ ret = usb_manager_bulk_transfer (devices[dn].usb_manager_handle, ++ devices[dn].bulk_out_ep, ++ (unsigned char *) buffer, ++ (int) *size, &trans_bytes, ++ usb_manager_timeout); ++ if (ret < 0) ++ { ++ DBG (1, "sanei_usb_write_bulk: write failed: %s\n", ++ sanei_usb_manager_strerror (ret)); ++ ++ write_size = -1; ++ } ++ else ++ write_size = trans_bytes; ++ } ++ else ++ { ++ DBG (1, "sanei_usb_write_bulk: can't write without a bulk-out " ++ "endpoint\n"); ++ return SANE_STATUS_INVAL; ++ } ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + { + DBG (1, "sanei_usb_write_bulk: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + else if (devices[dn].method == sanei_usb_method_usbcalls) + { + #ifdef HAVE_USBCALLS +@@ -3836,6 +4440,9 @@ sanei_usb_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size) + #elif defined(HAVE_LIBUSB) + if (devices[dn].method == sanei_usb_method_libusb) + libusb_clear_halt (devices[dn].lu_handle, devices[dn].bulk_out_ep); ++#elif defined(HAVE_USB_MANAGER) ++ if (devices[dn].method == sanei_usb_method_usb_manager) ++ usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].bulk_out_ep); + #endif + return SANE_STATUS_IO_ERROR; + } +@@ -4103,12 +4710,28 @@ sanei_usb_control_msg (SANE_Int dn, SANE_Int rtype, SANE_Int req, + if ((rtype & 0x80) && debug_level > 10) + print_buffer (data, len); + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB*/ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ int result; ++ ++ result = usb_manager_control_transfer (devices[dn].usb_manager_handle, rtype, req, ++ value, index, data, len, ++ usb_manager_timeout); ++ if (result < 0) ++ { ++ DBG (1, "sanei_usb_control_msg: libusb complained: %s\n", ++ sanei_usb_manager_strerror (result)); ++ return SANE_STATUS_INVAL; ++ } ++ if ((rtype & 0x80) && debug_level > 10) ++ print_buffer (data, len); ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ + { + DBG (1, "sanei_usb_control_msg: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + else if (devices[dn].method == sanei_usb_method_usbcalls) + { + #ifdef HAVE_USBCALLS +@@ -4282,7 +4905,7 @@ SANE_Status + sanei_usb_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) + { + ssize_t read_size = 0; +-#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) ++#if defined(HAVE_LIBUSB_LEGACY) || defined(HAVE_LIBUSB) || defined(HAVE_USB_MANAGER) + SANE_Bool stalled = SANE_FALSE; + #endif + +@@ -4363,12 +4986,37 @@ sanei_usb_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) + return SANE_STATUS_INVAL; + } + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ if (devices[dn].int_in_ep) ++ { ++ int ret; ++ int trans_bytes; ++ ret = usb_manager_interrupt_transfer (devices[dn].usb_manager_handle, ++ devices[dn].int_in_ep, ++ buffer, (int) *size, ++ &trans_bytes, usb_manager_timeout); ++ ++ if (ret < 0) ++ read_size = -1; ++ else ++ read_size = trans_bytes; ++ ++ stalled = (ret == USB_MANAGER_ERROR_PIPE); ++ } ++ else ++ { ++ DBG (1, "sanei_usb_read_int: can't read without an int " ++ "endpoint\n"); ++ return SANE_STATUS_INVAL; ++ } ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ + { + DBG (1, "sanei_usb_read_int: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + else if (devices[dn].method == sanei_usb_method_usbcalls) + { + #ifdef HAVE_USBCALLS +@@ -4429,6 +5077,10 @@ sanei_usb_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) + if (devices[dn].method == sanei_usb_method_libusb) + if (stalled) + libusb_clear_halt (devices[dn].lu_handle, devices[dn].int_in_ep); ++#elif defined(HAVE_USB_MANAGER) ++ if (devices[dn].method == sanei_usb_method_usb_manager) ++ if (stalled) ++ usb_manager_clear_halt (devices[dn].usb_manager_handle, devices[dn].int_in_ep); + #endif + return SANE_STATUS_IO_ERROR; + } +@@ -4568,12 +5220,25 @@ sanei_usb_set_configuration (SANE_Int dn, SANE_Int configuration) + } + return SANE_STATUS_GOOD; + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ int result; ++ ++ result = usb_manager_set_configuration (devices[dn].usb_manager_handle, configuration); ++ if (result < 0) ++ { ++ DBG (1, "sanei_usb_set_configuration: libusb complained: %s\n", ++ sanei_usb_manager_strerror (result)); ++ return SANE_STATUS_INVAL; ++ } ++ return SANE_STATUS_GOOD; ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + { + DBG (1, "sanei_usb_set_configuration: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + else + { + DBG (1, +@@ -4641,12 +5306,25 @@ sanei_usb_claim_interface (SANE_Int dn, SANE_Int interface_number) + } + return SANE_STATUS_GOOD; + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ int result; ++ ++ result = usb_manager_claim_interface (devices[dn].usb_manager_handle, interface_number); ++ if (result < 0) ++ { ++ DBG (1, "sanei_usb_claim_interface: libusb complained: %s\n", ++ sanei_usb_manager_strerror (result)); ++ return SANE_STATUS_INVAL; ++ } ++ return SANE_STATUS_GOOD; ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + { + DBG (1, "sanei_usb_claim_interface: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ + else + { + DBG (1, "sanei_usb_claim_interface: access method %d not implemented\n", +@@ -4712,12 +5390,25 @@ sanei_usb_release_interface (SANE_Int dn, SANE_Int interface_number) + } + return SANE_STATUS_GOOD; + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ int result; ++ ++ result = usb_manager_release_interface (devices[dn].usb_manager_handle, interface_number); ++ if (result < 0) ++ { ++ DBG (1, "sanei_usb_release_interface: libusb complained: %s\n", ++ sanei_usb_manager_strerror (result)); ++ return SANE_STATUS_INVAL; ++ } ++ return SANE_STATUS_GOOD; ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + { + DBG (1, "sanei_usb_release_interface: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + else + { + DBG (1, +@@ -4783,12 +5474,26 @@ sanei_usb_set_altinterface (SANE_Int dn, SANE_Int alternate) + } + return SANE_STATUS_GOOD; + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ int result; ++ ++ result = usb_manager_set_interface_alt_setting (devices[dn].usb_manager_handle, ++ devices[dn].interface_nr, alternate); ++ if (result < 0) ++ { ++ DBG (1, "sanei_usb_set_altinterface: usb_manager complained: %s\n", ++ sanei_usb_manager_strerror (result)); ++ return SANE_STATUS_INVAL; ++ } ++ return SANE_STATUS_GOOD; ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ + { + DBG (1, "sanei_set_altinterface: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + else + { + DBG (1, +@@ -4949,12 +5654,36 @@ sanei_usb_get_descriptor( SANE_Int dn, + desc->dev_protocol = lu_desc.bDeviceProtocol; + desc->max_packet_size = lu_desc.bMaxPacketSize0; + } +-#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#elif defined(HAVE_USB_MANAGER) ++ { ++ struct usb_manager_device_descriptor usb_manager_desc; ++ int ret; ++ ++ ret = usb_manager_get_device_descriptor (devices[dn].usb_manager_device, &usb_manager_desc); ++ if (ret < 0) ++ { ++ DBG (1, ++ "sanei_usb_get_descriptor: libusb error: %s\n", ++ sanei_usb_manager_strerror (ret)); ++ ++ return SANE_STATUS_INVAL; ++ } ++ ++ desc->desc_type = usb_manager_desc.bDescriptorType; ++ desc->bcd_usb = usb_manager_desc.bcdUSB; ++ desc->bcd_dev = usb_manager_desc.bcdDevice; ++ desc->dev_class = usb_manager_desc.bDeviceClass; ++ ++ desc->dev_sub_class = usb_manager_desc.bDeviceSubClass; ++ desc->dev_protocol = usb_manager_desc.bDeviceProtocol; ++ desc->max_packet_size = usb_manager_desc.bMaxPacketSize0; ++ } ++#else /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER*/ + { + DBG (1, "sanei_usb_get_descriptor: libusb support missing\n"); + return SANE_STATUS_UNSUPPORTED; + } +-#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB */ ++#endif /* not HAVE_LIBUSB_LEGACY && not HAVE_LIBUSB && not HAVE_USB_MANAGER */ + + if (testing_mode == sanei_usb_testing_mode_record) + { +diff --git a/sanei/usb_manager.cpp b/sanei/usb_manager.cpp +new file mode 100644 +index 000000000..62d7931e1 +--- /dev/null ++++ b/sanei/usb_manager.cpp +@@ -0,0 +1,572 @@ ++/* ++ * Copyright (c) 2024 Huawei Device Co., Ltd. ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include ++#include ++#include "iusb_srv.h" ++#include "securec.h" ++#include "string.h" ++#include "cstring" ++#include "usb_srv_client.h" ++#include "usb_manager.h" ++#include "v1_0/iusb_interface.h" ++#include "hilog/log.h" ++ ++#define SANE_LOG_TAG "sanekit" ++#define SANE_HILOG_INFO(...) ((void)HiLogPrint(LOG_APP, LOG_INFO, 0, "sanekit", __VA_ARGS__)) ++#define SANE_HILOG_ERROR(...) ((void)HiLogPrint(LOG_APP, LOG_ERROR, 0, "sanekit", __VA_ARGS__)) ++#define SANE_HILOG_DEBUG(...) ((void)HiLogPrint(LOG_APP, LOG_DEBUG, 0, "sanekit", __VA_ARGS__)) ++#define SANE_HILOG_WARN(...) ((void)HiLogPrint(LOG_APP, LOG_WARN, 0, "sanekit", __VA_ARGS__)) ++ ++using namespace OHOS::USB; ++ ++#define DELETE_AND_NULLPTR(ptr) \ ++ if ((ptr) != nullptr) { \ ++ delete (ptr); \ ++ (ptr) = nullptr; \ ++ } ++ ++#define DELETE_ARRAY_AND_NULLPTR(ptr) \ ++ if ((ptr) != nullptr) { \ ++ delete[] (ptr); \ ++ (ptr) = nullptr; \ ++ } ++ ++std::vector g_deviceList; ++static ssize_t g_deviceCount = 0; ++static uint8_t g_interfaceNumber = 0; ++static usb_manager_config_descriptor* g_deviceConfig = nullptr; ++ ++struct usb_manager_device_handle { ++ UsbDevice device; ++ USBDevicePipe pipe; ++}; ++ ++struct usb_manager_device { ++ UsbDevice device; ++}; ++ ++static void MemoryFreeDeviceList(usb_manager_device **list) ++{ ++ if (list == nullptr) { ++ return; ++ } ++ for (ssize_t i = 0 ; i < g_deviceCount; i++) { ++ DELETE_AND_NULLPTR(list[i]); ++ } ++ DELETE_ARRAY_AND_NULLPTR(list); ++ g_deviceCount = 0; ++} ++ ++int usb_manager_init(usb_manager_context **ctx) ++{ ++ SANE_HILOG_INFO("%s: begin", __func__); ++ if (ctx == nullptr) { ++ SANE_HILOG_ERROR("%s: ctx is a nullptr.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ usb_manager_context *usbmanagerContext = new (std::nothrow) usb_manager_context(); ++ if (usbmanagerContext == nullptr) { ++ SANE_HILOG_ERROR("%s: Not enough memory.", __func__); ++ return USB_MANAGER_ERROR_NO_MEM; ++ } ++ *ctx = usbmanagerContext; ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++int usb_manager_exit(usb_manager_context *ctx) ++{ ++ SANE_HILOG_INFO("%s: begin", __func__); ++ if (ctx == nullptr) { ++ SANE_HILOG_ERROR("%s: ctx is a nullptr.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ DELETE_AND_NULLPTR(ctx); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++ssize_t usb_manager_get_device_list(usb_manager_context *ctx, usb_manager_device ***list) ++{ ++ SANE_HILOG_INFO("%s: begin", __func__); ++ if (ctx == nullptr || list == nullptr) { ++ SANE_HILOG_ERROR("%s: ctx or list is a nullptr.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ g_deviceList.clear(); ++ auto ret = UsbSrvClient::GetInstance().GetDevices(g_deviceList); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("%s: GetDevices exception.", __func__); ++ return USB_MANAGER_ERROR_IO; ++ } ++ g_deviceCount = static_cast(g_deviceList.size()); ++ SANE_HILOG_DEBUG("%s: deviceCount : %d", __func__, g_deviceCount); ++ if (g_deviceCount == 0) { ++ SANE_HILOG_DEBUG("%s: not found device.", __func__); ++ return USB_MANAGER_SUCCESS; ++ } ++ usb_manager_device** usbManagerDeviceList = new (std::nothrow) usb_manager_device* [g_deviceCount]; ++ if (usbManagerDeviceList == nullptr) { ++ SANE_HILOG_ERROR("%s: Not enough memory.", __func__); ++ return USB_MANAGER_ERROR_NO_MEM; ++ } ++ for (ssize_t i = 0; i < g_deviceCount; i++) { ++ usb_manager_device* usbDevice = new (std::nothrow) usb_manager_device(); ++ if (usbDevice == nullptr) { ++ MemoryFreeDeviceList(usbManagerDeviceList); ++ SANE_HILOG_ERROR("%s: Not enough memory.", __func__); ++ return USB_MANAGER_ERROR_NO_MEM; ++ } ++ usbDevice->device = g_deviceList[i]; ++ usbManagerDeviceList[i] = usbDevice; ++ } ++ *list = usbManagerDeviceList; ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return g_deviceCount; ++} ++ ++int usb_manager_get_bus_number(usb_manager_device *dev) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev == nullptr) { ++ SANE_HILOG_ERROR("%s: dev is a nullptr.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return dev->device.GetBusNum(); ++} ++ ++int usb_manager_get_device_address(usb_manager_device *dev) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev == nullptr) { ++ SANE_HILOG_ERROR("%s: dev is a nullptr.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return dev->device.GetDevAddr(); ++} ++ ++int usb_manager_get_device_descriptor(usb_manager_device *dev, usb_manager_device_descriptor *desc) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev == nullptr || desc == nullptr) { ++ SANE_HILOG_ERROR("%s: dev or desc is a nullptr.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ UsbDevice &device = dev->device; ++ desc->idVendor = static_cast(device.GetVendorId()); ++ desc->idProduct = static_cast(device.GetProductId()); ++ desc->bDeviceClass = static_cast(device.GetClass()); ++ desc->bNumConfigurations = static_cast(device.GetConfigCount()); ++ desc->bDeviceSubClass = static_cast(device.GetSubclass()); ++ desc->bDeviceProtocol = static_cast(device.GetProtocol()); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++int usb_manager_open(usb_manager_device *dev, usb_manager_device_handle **dev_handle) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev == nullptr || dev_handle == nullptr) { ++ SANE_HILOG_ERROR("%s: dev or dev_handle is a nullptr.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ auto &usbSrvClient = UsbSrvClient::GetInstance(); ++ USBDevicePipe pipe; ++ UsbDevice &device = dev->device; ++ auto ret = usbSrvClient.RequestRight(device.GetName()); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("request right failed ret=%{public}d", ret); ++ return USB_MANAGER_ERROR_ACCESS; ++ } ++ ret = usbSrvClient.OpenDevice(device, pipe); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("open device failed ret=%{public}d", ret); ++ return USB_MANAGER_ERROR_ACCESS; ++ } ++ auto handle = new (std::nothrow) usb_manager_device_handle(); ++ if (handle == nullptr) { ++ SANE_HILOG_ERROR("%s: Not enough memory.", __func__); ++ return USB_MANAGER_ERROR_NO_MEM; ++ } ++ handle->device = device; ++ handle->pipe = pipe; ++ *dev_handle = handle; ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++void usb_manager_close(usb_manager_device_handle *dev_handle) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev_handle == nullptr) { ++ SANE_HILOG_ERROR("%s: dev_handle is a nullptr", __func__); ++ return; ++ } ++ auto &usbSrvClient = UsbSrvClient::GetInstance(); ++ usbSrvClient.Close(dev_handle->pipe); ++ DELETE_AND_NULLPTR(dev_handle); ++ SANE_HILOG_INFO("%s: end", __func__); ++ return; ++} ++ ++int usb_manager_get_configuration(usb_manager_device_handle *dev, int *config) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev == nullptr || config == nullptr) { ++ SANE_HILOG_ERROR("%s: dev or config is a nullptr", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ UsbDevice &device = dev->device; ++ auto configCount = device.GetConfigCount(); ++ SANE_HILOG_DEBUG("%s: configCount = %d", __func__, configCount); ++ *config = configCount; ++ return USB_MANAGER_SUCCESS; ++} ++ ++struct UsbEndPointDes { ++ uint8_t bmAttributes; ++ uint8_t bEndpointAddress; ++}; ++ ++struct UsbInterfaceAltDes{ ++ uint8_t bInterfaceClass; ++ std::vector endpointDes; ++}; ++ ++struct UsbAltInterface { ++ std::vector altDes; ++}; ++ ++void InterfaceConvert(std::vector &usbInterfaces, std::vector &usbAlt) { ++ auto memCopyInter = [&](size_t &i, UsbAltInterface &altInter) { ++ UsbInterfaceAltDes des; ++ des.bInterfaceClass = static_cast(usbInterfaces[i].GetClass()); ++ std::vector &endPoints = usbInterfaces[i].GetEndpoints(); ++ for (size_t j = 0; j < endPoints.size(); j++) { ++ UsbEndPointDes pointDes; ++ pointDes.bmAttributes = static_cast(endPoints[j].GetAttributes()); ++ pointDes.bEndpointAddress = static_cast(endPoints[j].GetAddress()); ++ des.endpointDes.push_back(pointDes); ++ } ++ altInter.altDes.push_back(des); ++ }; ++ for (size_t i = 0; i < usbInterfaces.size(); i++) { ++ UsbInterface& inter = usbInterfaces[i]; ++ if (inter.GetAlternateSetting() == 0) { ++ UsbAltInterface altInter; ++ memCopyInter(i, altInter); ++ usbAlt.push_back(altInter); ++ } else { ++ int id = usbInterfaces[i].GetId(); ++ UsbAltInterface &altInter = usbAlt[id]; ++ memCopyInter(i, altInter); ++ } ++ } ++} ++ ++int usb_manager_get_config_descriptor(usb_manager_device *dev, uint8_t config_index, ++ usb_manager_config_descriptor **config) ++{ ++ SANE_HILOG_INFO("%s: begin", __func__); ++ if (dev == nullptr || config == nullptr) { ++ SANE_HILOG_ERROR("%s: dev or config is a nullptr", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ UsbDevice &device = dev->device; ++ std::vector &configs = device.GetConfigs(); ++ if (config_index >= configs.size()) { ++ SANE_HILOG_ERROR("%s: config_index(%u) is invalid.", __func__, config_index); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ USBConfig &usbConfig = configs[config_index]; ++ SANE_HILOG_DEBUG("%s: config[%u] = %s", __func__, config_index, usbConfig.getJsonString().c_str()); ++ usb_manager_config_descriptor* retConfig = new (std::nothrow) usb_manager_config_descriptor(); ++ if (retConfig == nullptr) { ++ SANE_HILOG_ERROR("%s: Not enough memory.", __func__); ++ return USB_MANAGER_ERROR_NO_MEM; ++ } ++ std::vector &usbInterfaces = usbConfig.GetInterfaces(); ++ std::vector usbAlt; ++ InterfaceConvert(usbInterfaces, usbAlt); ++ size_t bNumInterfaces = usbAlt.size(); ++ retConfig->bNumInterfaces = static_cast(bNumInterfaces); ++ retConfig->bConfigurationValue = static_cast(usbConfig.GetId()); ++ auto retInterface = new (std::nothrow) usb_manager_interface[bNumInterfaces]; ++ if (retInterface == nullptr) { ++ SANE_HILOG_ERROR("%s: Not enough memory.", __func__); ++ return USB_MANAGER_ERROR_NO_MEM; ++ } ++ for (int i = 0; i < bNumInterfaces; i++) { ++ size_t altSet = usbAlt[i].altDes.size(); ++ auto retAltsetting = new (std::nothrow) usb_manager_interface_descriptor[altSet]; ++ if (retAltsetting == nullptr) { ++ SANE_HILOG_ERROR("%s: Not enough memory.", __func__); ++ return USB_MANAGER_ERROR_NO_MEM; ++ } ++ for (size_t j = 0; j < altSet; j++) { ++ retAltsetting[j].bInterfaceClass = usbAlt[i].altDes[j].bInterfaceClass; ++ size_t endPointsNum = usbAlt[i].altDes[j].endpointDes.size(); ++ retAltsetting[j].bNumEndpoints = endPointsNum; ++ retAltsetting[j].endpoint = new usb_manager_endpoint_descriptor[endPointsNum]; ++ for (int k = 0 ; k < endPointsNum; k++) { ++ uint8_t bmAttr = usbAlt[i].altDes[j].endpointDes[k].bmAttributes; ++ uint8_t bEndpointAddress = usbAlt[i].altDes[j].endpointDes[k].bEndpointAddress; ++ retAltsetting[j].endpoint[k].bmAttributes = bmAttr; ++ retAltsetting[j].endpoint[k].bEndpointAddress = bEndpointAddress; ++ } ++ } ++ retInterface[i].altsetting = retAltsetting; ++ retInterface[i].num_altsetting = static_cast(altSet); ++ } ++ retConfig->interface = retInterface; ++ *config = retConfig; ++ g_deviceConfig = retConfig; ++ SANE_HILOG_INFO("%s: end", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++void usb_manager_free_config_descriptor(usb_manager_config_descriptor *config) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (config == nullptr) { ++ SANE_HILOG_ERROR("%s: config is a nullptr", __func__); ++ return; ++ } ++ usb_manager_interface *interface = config->interface; ++ // for each interface ++ for (uint8_t i = 0; i < config->bNumInterfaces; i++) { ++ usb_manager_interface *interfacei = interface + i; ++ if (interfacei == nullptr) { ++ break; ++ } ++ usb_manager_interface_descriptor *altsetting = interfacei->altsetting; ++ // for each altsetting interface ++ for (int j = 0; j < interfacei->num_altsetting; i++) { ++ usb_manager_interface_descriptor *altsettingj = altsetting + j; ++ if (altsettingj == nullptr) { ++ break; ++ } ++ DELETE_ARRAY_AND_NULLPTR(altsettingj->endpoint) ++ } ++ DELETE_ARRAY_AND_NULLPTR(interfacei->altsetting); ++ } ++ DELETE_ARRAY_AND_NULLPTR(interface); ++ DELETE_AND_NULLPTR(config); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return; ++} ++ ++void usb_manager_free_device_list(usb_manager_device **list, int unref_devices) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (list == nullptr) { ++ SANE_HILOG_ERROR("%s: list is a nullptr", __func__); ++ return; ++ } ++ MemoryFreeDeviceList(list); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++} ++ ++int usb_manager_set_configuration(usb_manager_device_handle *dev_handle, int configuration) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev_handle == nullptr) { ++ SANE_HILOG_ERROR("%s: dev_handle is a nullptr", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ UsbDevice &device = dev_handle->device; ++ USBDevicePipe pip; ++ pip.SetBusNum(device.GetBusNum()); ++ pip.SetDevAddr(device.GetDevAddr()); ++ USBConfig config; ++ config.SetId(configuration); ++ auto ret = UsbSrvClient::GetInstance().SetConfiguration(pip, config); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("SetConfiguration failed ret=%{public}d", ret); ++ return USB_MANAGER_ERROR_IO; ++ } ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++int usb_manager_claim_interface(usb_manager_device_handle *dev_handle, int interface_number) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev_handle == nullptr) { ++ SANE_HILOG_ERROR("%s: dev_handle is a nullptr", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ auto &usbSrvClient = UsbSrvClient::GetInstance(); ++ UsbInterface interface; ++ interface.SetId(interface_number); ++ auto ret = usbSrvClient.ClaimInterface(dev_handle->pipe, interface, true); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("ClaimInterface failed ret=%{public}d", ret); ++ return USB_MANAGER_ERROR_IO; ++ } ++ g_interfaceNumber = interface_number; ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++int usb_manager_release_interface(usb_manager_device_handle *dev_handle, int interface_number) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev_handle == nullptr) { ++ SANE_HILOG_ERROR("%s: dev_handle is a nullptr", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ auto &usbSrvClient = UsbSrvClient::GetInstance(); ++ USBDevicePipe &pipe = dev_handle->pipe; ++ SANE_HILOG_DEBUG("%s: interface_number : %d", __func__, interface_number); ++ UsbInterface interface; ++ interface.SetId(interface_number); ++ auto ret = usbSrvClient.ReleaseInterface(pipe, interface); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("ReleaseInterface failed ret=%{public}d", ret); ++ return USB_MANAGER_ERROR_IO; ++ } ++ g_interfaceNumber = 0; ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++int usb_manager_bulk_transfer(usb_manager_device_handle *dev_handle, unsigned char endpoint, ++ unsigned char *data, int length, int *transferred, unsigned int timeout) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev_handle == nullptr || data == nullptr || length == 0 || transferred == nullptr) { ++ SANE_HILOG_ERROR("%s: Invalid input parameter.", __func__); ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ USBDevicePipe &pipe = dev_handle->pipe; ++ USBEndpoint usbEndpoint; ++ usbEndpoint.SetInterfaceId(g_interfaceNumber); ++ usbEndpoint.SetAddr(endpoint); ++ auto &usbSrvClient = UsbSrvClient::GetInstance(); ++ if (endpoint & USB_MANAGER_ENDPOINT_IN) { ++ // read ++ std::vector bufferData(length); ++ auto ret = usbSrvClient.BulkTransfer(pipe, usbEndpoint, bufferData, timeout); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_INFO("%s: error", __func__); ++ return USB_MANAGER_ERROR_IO; ++ } ++ for (int i = 0; i < length; i++) { ++ data[i] = bufferData[i]; ++ } ++ } else { ++ // write ++ std::vector bufferData(length); ++ for (int i = 0; i < length; i++) { ++ bufferData[i] = data[i]; ++ } ++ auto ret = usbSrvClient.BulkTransfer(pipe, usbEndpoint, bufferData, timeout); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_INFO("%s: error", __func__); ++ return USB_MANAGER_ERROR_IO; ++ } ++ } ++ *transferred = length; ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++int usb_manager_control_transfer(usb_manager_device_handle *dev_handle, uint8_t request_type, ++ uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, ++ unsigned int timeout) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev_handle == nullptr || data == nullptr || wLength == 0) { ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ USBDevicePipe &pipe = dev_handle->pipe; ++ OHOS::HDI::Usb::V1_0::UsbCtrlTransfer ctrl; ++ ctrl.requestType = static_cast(request_type); ++ ctrl.requestCmd = static_cast(bRequest); ++ ctrl.value = static_cast(wValue); ++ ctrl.index = static_cast(wIndex); ++ ctrl.timeout = static_cast(timeout); ++ ++ auto &usbSrvClient = UsbSrvClient::GetInstance(); ++ std::vector bufferData; ++ for (uint16_t i = 0; i < wLength; i++) { ++ bufferData[i] = data[i]; ++ } ++ auto ret = usbSrvClient.ControlTransfer(pipe, ctrl, bufferData); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("ControlTransfer failed ret=%{public}d", ret); ++ return USB_MANAGER_ERROR_IO; ++ } ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++int usb_manager_set_interface_alt_setting(usb_manager_device_handle *dev_handle, int interface_number, ++ int alternate_setting) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ if (dev_handle == nullptr) { ++ return USB_MANAGER_ERROR_INVALID_PARAM; ++ } ++ auto &usbSrvClient = UsbSrvClient::GetInstance(); ++ USBDevicePipe pipe = dev_handle->pipe; ++ UsbInterface interface; ++ interface.SetId(interface_number); ++ interface.SetAlternateSetting(alternate_setting); ++ auto ret = usbSrvClient.SetInterface(pipe, interface); ++ if (ret != USB_MANAGER_SUCCESS) { ++ SANE_HILOG_ERROR("SetInterface failed ret=%{public}d", ret); ++ return USB_MANAGER_ERROR_IO; ++ } ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++// stub ++int usb_manager_interrupt_transfer(usb_manager_device_handle *dev_handle, unsigned char endpoint, ++ unsigned char *data, int length, int *actual_length, unsigned int timeout) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++// stub ++usb_manager_device * usb_manager_ref_device(usb_manager_device *dev) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return nullptr; ++} ++ ++// stub ++int usb_manager_clear_halt(usb_manager_device_handle *dev_handle, unsigned char endpoint) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} ++ ++// stub ++int usb_manager_reset_device(usb_manager_device_handle *dev_handle) ++{ ++ SANE_HILOG_INFO("%s: start", __func__); ++ SANE_HILOG_INFO("%s: end successful", __func__); ++ return USB_MANAGER_SUCCESS; ++} +\ No newline at end of file +-- +2.34.1 +