#include "usb_manager.h" #include "../wrapper/hg_log.h" #include #define IF_CLASS(code, cls) \ if(code == cls) \ return #cls; #if defined(WIN32) || defined(_WIN64) #include "scanner_manager.h" #else void memset(void* buf, unsigned char fill, int len) { unsigned char* data = (unsigned char*)buf; while (len-- > 0) *data++ = fill; } #endif usb_manager* usb_manager::inst_ = NULL; uint8_t usb_manager::uninit_uint8 = 0x0ff; usb_manager::usb_manager() : run_(true) , usb_cb_handle_(NULL) , usb_cb_(&usb_manager::usb_event_handle), usb_cb_param_(NULL) , context_(NULL), status_(SCANNER_ERR_OK) , born_(std::chrono::system_clock::now()) { int ret = libusb_init(&context_); // libusb_set_log_cb(context_, &usb_manager::usb_log_callback, LIBUSB_LOG_CB_CONTEXT); // LIBUSB_API_VERSION >= 0x01000107 VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "usb_manager(%s) libusb_init(%s) = %s, context = %s\n", hg_log::format_ptr(this).c_str(), hg_log::format_ptr(&context_).c_str(), libusb_error_name(ret), hg_log::format_ptr(context_).c_str()); if (ret) status_ = SCANNER_ERR_USB_INIT_FAILED; wait_pnp_.set_debug_info("Waiting PNP"); if (!usb_notify_thread_.get()) { run_ = true; usb_notify_thread_.reset(new std::thread(&usb_manager::thread_notify_usb_event, this)); } } usb_manager::~usb_manager() { run_ = false; wait_pnp_.notify(); libusb_context* ctx = nullptr; #if defined(WIN32) || defined(_WIN64) ctx = context_; libusb_quit(ctx); #endif if(usb_cb_handle_) libusb_hotplug_deregister_callback(ctx, usb_cb_handle_); if (usb_monitor_thread_.get() && usb_monitor_thread_->joinable()) { usb_monitor_thread_->join(); usb_monitor_thread_.reset(); } if (usb_notify_thread_.get() && usb_notify_thread_->joinable()) { usb_notify_thread_->join(); usb_notify_thread_.reset(); } libusb_exit(context_); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "usb_manager(%s) destroying and free context(%s)\n", hg_log::format_ptr(this).c_str(), hg_log::format_ptr(context_).c_str()); } int LIBUSB_CALL usb_manager::usb_pnp_callback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* monitor) { usb_manager* obj = (usb_manager*)monitor; // if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) //libusb_ref_device(device); // keep the object until handle it //else if(event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) // libusb_unref_device(device); return obj->on_usb_pnp_event(ctx, device, event); } void usb_manager::usb_event_handle(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry, void* user) // usb_ver_h.usb_ver_l { } void usb_manager::usb_log_callback(libusb_context* ctx, libusb_log_level level, const char* str) { // used when LIBUSB_API_VERSION >= 0x01000107 if (level == LIBUSB_LOG_LEVEL_NONE || LIBUSB_LOG_LEVEL_INFO || LIBUSB_LOG_LEVEL_DEBUG) { LOG_INFO(LOG_LEVEL_DEBUG_INFO, str); } else { LOG_INFO(LOG_LEVEL_FATAL, str); } } int usb_manager::register_usb_pnp(void) { libusb_context* ctx = nullptr; #if defined(WIN32) || defined(_WIN64) ctx = context_; #endif int ret = libusb_hotplug_register_callback(ctx, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), (libusb_hotplug_flag)LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,//LIBUSB_HOTPLUG_MATCH_ANY LIBUSB_HOTPLUG_MATCH_ANY,//LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, &usb_manager::usb_pnp_callback, this, &usb_cb_handle_); if (ret != LIBUSB_SUCCESS) { LOG_INFO(LOG_LEVEL_FATAL, (std::string("regist usbhotplug callback error msg: ") + libusb_error_name(ret) + "\n").c_str()); usb_cb_handle_ = NULL; status_ = SCANNER_ERR_USB_REGISTER_PNP_FAILED; } else status_ = SCANNER_ERR_OK; return ret; } void usb_manager::init_notify_thread() { if(!usb_monitor_thread_.get()) { usb_monitor_thread_.reset(new std::thread(&usb_manager::thread_trigger_usb_event, this)); } } void usb_manager::fake_usb_pnp(std::vector& devices) { libusb_device** devs = NULL; libusb_get_device_list(context_, &devs); if (devs) { std::vector current; // handle arrived ... for (int ind = 0; devs[ind]; ++ind) { std::vector::iterator it = std::find(devices.begin(), devices.end(), devs[ind]); if (it == devices.end()) { current.push_back(devs[ind]); on_usb_pnp_event(context_, devs[ind], LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED); } } // handle left ... for (int ind = 0; ind < devices.size(); ++ind) { std::vector::iterator it = std::find(current.begin(), current.end(), devices[ind]); if (it == current.end()) { on_usb_pnp_event(context_, devices[ind], LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT); } } devices = current; libusb_free_device_list(devs, 0); } } void usb_manager::thread_notify_usb_event() { while (run_) { if (!wait_pnp_.wait()) continue; if (!run_) break; int delay = 50; // milliseconds ... while (pnp_events_.Size() && run_) { PNPDEV pd = pnp_events_.Take(); bool retry = false; if (pd.event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { unsigned ms = std::chrono::duration_cast(std::chrono::system_clock::now() - pd.happen_time).count(); if (ms < delay) { this_thread::sleep_for(chrono::milliseconds(delay)); } } libusb_ref_device(pd.dev); // for re-enter the queue pnp_events_ notify_usb_event(pd, &retry); if (retry) { if (std::chrono::duration_cast(std::chrono::system_clock::now() - pd.happen_time).count() <= 5000) pnp_events_.Put(pd, sizeof(pd)); else retry = false; if(pnp_events_.Size() == 1) this_thread::sleep_for(chrono::milliseconds(1000)); else this_thread::sleep_for(chrono::milliseconds(delay)); } if (!retry) libusb_unref_device(pd.dev); } } } void usb_manager::notify_usb_event(PNPDEV& pd, bool* retry) { usb_event ev = USB_EVENT_NULL; usb_dev ud; bool re_try = false; std::string evstr(""); usb_manager::get_device_info(pd.dev, &ud); ud.contex = pd.ctx; if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == pd.event) { ev = USB_EVENT_DEVICE_ARRIVED; evstr = "USB_EVENT_DEVICE_ARRIVED"; } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == pd.event) { ev = USB_EVENT_DEVICE_LEFT; evstr = "USB_EVENT_DEVICE_LEFT"; } else { char buf[20]; sprintf(buf, "0x%x", pd.event); evstr = buf; } VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "USB%u.%x of pid:vid(%x:%x) event(%s) received.\n" , HIBYTE(ud.ver), LOBYTE(ud.ver) / 0x10, ud.pid, ud.vid, evstr.c_str()); if (ev != USB_EVENT_NULL) { if (!retry) retry = &re_try; usb_cb_(ev, pd.dev, ud.vid, ud.pid, HIBYTE(ud.ver), LOBYTE(ud.ver) / 0x10, retry, usb_cb_param_); } libusb_unref_device(pd.dev); // response for libusb_ref_device in usb_manager::usb_pnp_callback } void usb_manager::thread_trigger_usb_event() { if (!usb_cb_handle_) { // we try manually find device here int times = 10, elapse_max = 60 * 2, elapse = elapse_max; std::vector devices; while (run_) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // simulate PNP events ... fake_usb_pnp(devices); // retry register pnp ... if (--elapse == 0 && --times > 0) { elapse_max *= 2; elapse = elapse_max; if (register_usb_pnp() == LIBUSB_SUCCESS) { // ^_^ devices.clear(); LOG_INFO(LOG_LEVEL_DEBUG_INFO, "register_usb_pnp success ^_^\n"); break; } } } } while(run_) { timeval tm={1,0}; int ret=libusb_handle_events_timeout(context_, &tm); if(ret < 0) LOG_INFO(LOG_LEVEL_FATAL, (std::string("libusb_handle_events_timeout error ") + libusb_error_name(ret) + "\n").c_str()); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int usb_manager::on_usb_pnp_event(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event) { PNPDEV pd; unsigned ms = std::chrono::duration_cast(std::chrono::system_clock::now() - born_).count(); libusb_ref_device(device); pd.ctx = ctx; pd.dev = device; pd.event = event; pd.happen_time = std::chrono::system_clock::now(); if (ms > 1000) { pnp_events_.Put(pd, sizeof(pd)); wait_pnp_.notify(); } else { bool retry = false; libusb_ref_device(device); notify_usb_event(pd, &retry); if(retry) pnp_events_.Put(pd, sizeof(pd)); else libusb_unref_device(device); } return 0; } usb_manager* usb_manager::instance(void) { if (usb_manager::inst_ == NULL) usb_manager::inst_ = new usb_manager(); return usb_manager::inst_; } void usb_manager::clear(void) { if (usb_manager::inst_) { delete usb_manager::inst_; usb_manager::inst_ = NULL; } } int usb_manager::usb_error_2_hg_err(int usb_err) { if (usb_err == LIBUSB_ERROR_TIMEOUT) return SCANNER_ERR_TIMEOUT; else if (usb_err == LIBUSB_ERROR_PIPE) return SCANNER_ERR_IO; else if (usb_err == LIBUSB_ERROR_NO_DEVICE) return SCANNER_ERR_DEVICE_NOT_FOUND; else if (usb_err == LIBUSB_ERROR_BUSY) return SCANNER_ERR_DEVICE_BUSY; else if (usb_err == LIBUSB_ERROR_INVALID_PARAM) return SCANNER_ERR_INVALID_PARAMETER; else if (usb_err == LIBUSB_ERROR_OVERFLOW) return SCANNER_ERR_OUT_OF_RANGE; else if (usb_err == LIBUSB_ERROR_NO_MEM) return SCANNER_ERR_INSUFFICIENT_MEMORY; else if (usb_err == LIBUSB_ERROR_ACCESS) return SCANNER_ERR_ACCESS_DENIED; else if (usb_err < 0) return (scanner_err)usb_err; else return SCANNER_ERR_OK; } void usb_manager::init_endpoint(USBENDP* uep) { uep->in.port = uep->out.port = usb_manager::uninit_uint8; uep->in.iface = uep->out.iface = usb_manager::uninit_uint8; uep->in.iconf = uep->out.iconf = usb_manager::uninit_uint8; uep->in.claimed = uep->out.claimed = 0; uep->in.max_packet = uep->out.max_packet = 0; } std::string usb_manager::device_class(libusb_class_code code) { IF_CLASS(code, LIBUSB_CLASS_PER_INTERFACE); IF_CLASS(code, LIBUSB_CLASS_AUDIO); IF_CLASS(code, LIBUSB_CLASS_COMM); IF_CLASS(code, LIBUSB_CLASS_HID); IF_CLASS(code, LIBUSB_CLASS_PHYSICAL); IF_CLASS(code, LIBUSB_CLASS_IMAGE); IF_CLASS(code, LIBUSB_CLASS_PRINTER); IF_CLASS(code, LIBUSB_CLASS_MASS_STORAGE); IF_CLASS(code, LIBUSB_CLASS_HUB); IF_CLASS(code, LIBUSB_CLASS_DATA); IF_CLASS(code, LIBUSB_CLASS_SMART_CARD); IF_CLASS(code, LIBUSB_CLASS_CONTENT_SECURITY); IF_CLASS(code, LIBUSB_CLASS_VIDEO); IF_CLASS(code, LIBUSB_CLASS_PERSONAL_HEALTHCARE); IF_CLASS(code, LIBUSB_CLASS_DIAGNOSTIC_DEVICE); IF_CLASS(code, LIBUSB_CLASS_WIRELESS); //IF_CLASS(code, LIBUSB_CLASS_MISCELLANEOUS); IF_CLASS(code, LIBUSB_CLASS_APPLICATION); IF_CLASS(code, LIBUSB_CLASS_VENDOR_SPEC); char buf[40]; sprintf(buf, "unknown class: %d", code); return buf; } std::string usb_manager::endpoint_type(libusb_transfer_type type) { IF_CLASS(type, LIBUSB_TRANSFER_TYPE_CONTROL); IF_CLASS(type, LIBUSB_TRANSFER_TYPE_ISOCHRONOUS); IF_CLASS(type, LIBUSB_TRANSFER_TYPE_BULK); IF_CLASS(type, LIBUSB_TRANSFER_TYPE_INTERRUPT); IF_CLASS(type, LIBUSB_TRANSFER_TYPE_BULK_STREAM); char buf[40]; sprintf(buf, "unknown type: %d", type); return buf; } bool usb_manager::get_device_info(libusb_device* device, usb_dev* devinfo) { libusb_device_descriptor descriptor; int ret = libusb_get_device_descriptor(device, &descriptor); if (ret != LIBUSB_SUCCESS) return false; devinfo->device = device; devinfo->ver = descriptor.bcdUSB; devinfo->vid = descriptor.idVendor; devinfo->pid = descriptor.idProduct; devinfo->addr = 0; // libusb_get_device_address(device); - initialize at open return true; } void usb_manager::enum_endpoints(libusb_device* device, USBTRANSENDP* endp) { libusb_device_descriptor desc; libusb_config_descriptor *conf = NULL; std::string dev(hg_log::format_ptr(device)); int ret = libusb_get_device_descriptor(device, &desc); bool found_ep = false; if (ret != 0) { LOG_INFO(LOG_LEVEL_WARNING, (std::string("Get device descriptor of device(") + dev + ") failed.\n").c_str()); return; } if (endp) { usb_manager::init_endpoint(&endp->bulk); usb_manager::init_endpoint(&endp->bulk_stream); usb_manager::init_endpoint(&endp->control); usb_manager::init_endpoint(&endp->interrupt); usb_manager::init_endpoint(&endp->isochronous); } else VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " +Device(%s) has %u configurations ...\n", dev.c_str(), desc.bNumConfigurations); for (int i = 0; i < (int)desc.bNumConfigurations; ++i) { ret = libusb_get_config_descriptor(device, i, &conf); if (ret != 0) { if (!endp) VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " Get %d configuration failed.\n", i + 1); continue; } if (!endp) VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Configuration %d has %d interfaces\n", i + 1, conf->bNumInterfaces); for (int j = 0; j < conf->bNumInterfaces; ++j) { if (!endp) VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Interface %d has %d alt-settings\n", j + 1, conf->interface[j].num_altsetting); for (int k = 0; k < conf->interface[j].num_altsetting; ++k) { if (!endp) VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, " Setting %d: %d - %s has %d endpoints\n", k + 1, conf->interface[j].altsetting[k].bInterfaceNumber , usb_manager::device_class((libusb_class_code)conf->interface[j].altsetting[k].bInterfaceClass).c_str() , conf->interface[j].altsetting[k].bNumEndpoints); for (int l = 0; l < conf->interface[j].altsetting[k].bNumEndpoints; ++l) { if (endp) { USBENDP* ep = NULL; if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_CONTROL) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of control\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); ep = &endp->control; } else if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of isochronous\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); ep = &endp->isochronous; } if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of bulk\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); ep = &endp->bulk; } if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of interrupt\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); ep = &endp->interrupt; } if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK_STREAM) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of bulk-stream\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); ep = &endp->bulk_stream; } if (ep) { USBSIMPLEX* s = NULL; if (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & LIBUSB_ENDPOINT_IN) s = &ep->in;// = (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & 3) | LIBUSB_ENDPOINT_IN; else s = &ep->out; // = (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & 3) | LIBUSB_ENDPOINT_OUT; // NOTE: 这里应该尽量将输入输出端口统一到同一个接口上来,目前未做,只取第一? if (s->port == usb_manager::uninit_uint8) { s->port = conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & (LIBUSB_ENDPOINT_IN | LIBUSB_ENDPOINT_OUT | 3); s->iconf = conf->bConfigurationValue; s->iface = j; s->claimed = 0; s->max_packet = conf->interface[j].altsetting[k].endpoint[l].wMaxPacketSize; VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, " Endpoint address = 0x%02x, origin = 0x%02x, max packet: 0x%x\n", s->port, conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress , s->max_packet); } found_ep = true; } } else VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, " Endpoint %d(%s) address: %x, Max packet: 0x%x bytes\n", l + 1 , usb_manager::endpoint_type((libusb_transfer_type)conf->interface[j].altsetting[k].endpoint[l].bmAttributes).c_str() , conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress , conf->interface[j].altsetting[k].endpoint[l].wMaxPacketSize); } } } libusb_free_config_descriptor(conf); } if (endp && !found_ep) VLOG_MINI_2(LOG_LEVEL_FATAL, "No endpoint has been found on device (VID: %x, PID: %x)\n", desc.idVendor, desc.idProduct); } int usb_manager::register_hotplug(usb_event_handler cb, void* user) { if (cb) usb_cb_ = cb; else usb_cb_ = &usb_manager::usb_event_handle; usb_cb_param_ = user; int ret = register_usb_pnp(); if (ret != LIBUSB_SUCCESS) { // then we find devices manually, and need not return failure here } init_notify_thread(); return SCANNER_ERR_OK; } int usb_manager::open(libusb_device* device, usb_io** usbio, std::string* msg) { if (!usbio) return SCANNER_ERR_INVALID_PARAMETER; usb_dev dev; usb_io* usb = NULL; if (!get_device_info(device, &dev)) return SCANNER_ERR_DEVICE_NOT_FOUND; dev.contex = context_; usb = new usb_io(dev); if (!usb->is_ready()) { int err = usb->last_error(); if (msg) *msg = usb->init_error_msg(); usb->release(); VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Open %04x:%04x failed: %s\n", dev.vid, dev.pid, hg_scanner_err_name(err)); return err; } *usbio = dynamic_cast(usb); return SCANNER_ERR_OK; } int usb_manager::last_status(void) { return status_; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // usb_io //#define USE_OLD_USB #ifdef USE_OLD_USB #include "libusbex.h" std::shared_ptr usb_; #endif usb_io::usb_io(const usb_dev& dev) : ref_(1), handle_(NULL), dev_info_(dev), to_(1000), last_err_(SCANNER_ERR_NOT_START), ref_device_(nullptr) , singleton_(nullptr) { #ifdef USE_OLD_USB std::list> all = Libusb_List::find_vid_pid(0x3072, 0x239); if (all.size()) { usb_ = *all.begin(); usb_->open(); handle_ = (libusb_device_handle*)1; } #else clear_endpoints(); open(); #endif } usb_io::~usb_io() { close(); } bool usb_io::make_singleton(void) { unsigned long long key = dev_info_.vid; key <<= 16; key |= dev_info_.pid; key <<= 16; if (dev_info_.addr == 0) dev_info_.addr = libusb_get_device_address(dev_info_.device); key |= dev_info_.addr; if (singleton_) singleton_->release(); singleton_ = new shared_memory(key); if (singleton_->is_first()) { return true; } std::string str(singleton_->read()); singleton_->release(); singleton_ = nullptr; last_err_ = SCANNER_ERR_OPENED_BY_OTHER_PROCESS; std::string tips(from_default_language("\350\256\276\345\244\207\345\267\262\347\273\217\350\242\253\350\277\233\347\250\213 '%s' \345\215\240\347\224\250")); size_t pos = tips.find("%s"); if (pos != std::string::npos) tips.replace(pos, 2, str); str = std::move(tips); init_err_msg_ = str; VLOG_MINI_1(LOG_LEVEL_FATAL, "Open failed: %s\n", str.c_str()); return false; } void usb_io::clear_endpoints(void) { usb_manager::init_endpoint(&endpoints_.bulk); usb_manager::init_endpoint(&endpoints_.bulk_stream); usb_manager::init_endpoint(&endpoints_.control); usb_manager::init_endpoint(&endpoints_.interrupt); usb_manager::init_endpoint(&endpoints_.isochronous); } bool usb_io::claim_interterface(usb_manager::USBSIMPLEX* spl) { int ret = libusb_claim_interface(handle_, spl->iface); if (ret == LIBUSB_SUCCESS) { spl->claimed = true; return true; } VLOG_MINI_2(LOG_LEVEL_FATAL, "libusb_claim_interface(%d) = %s, now try some actions ...\n", spl->iface, libusb_error_name(ret)); ret = libusb_kernel_driver_active(handle_, spl->iface); if (ret == 1) { ret = libusb_detach_kernel_driver(handle_, spl->iface); VLOG_MINI_2(LOG_LEVEL_FATAL, " libusb_detach_kernel_driver(%d) = %s\n", spl->iface, libusb_error_name(ret)); } else if (ret == LIBUSB_ERROR_NO_DEVICE) { last_err_ = SCANNER_ERR_DEVICE_NOT_FOUND; VLOG_MINI_1(LOG_LEVEL_FATAL, " device(%s) maybe left when libusb_kernel_driver_active.\n", hg_log::format_ptr(dev_info_.device).c_str()); return false; } else { VLOG_MINI_2(LOG_LEVEL_FATAL, " libusb_kernel_driver_active(%d) = %d\n", spl->iface, ret); } ret = libusb_clear_halt(handle_, spl->port); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_clear_halt(%x) = %s\n", spl->port, libusb_error_name(ret)); ret = libusb_release_interface(handle_, spl->iface); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_release_interface(%u) = %s\n", spl->iface, libusb_error_name(ret)); ret = libusb_set_configuration(handle_, spl->iconf); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_set_configuration(%u) = %s\n", spl->iconf, libusb_error_name(ret)); //ret = libusb_reset_device(handle_); //VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " libusb_reset_device = %s\n", libusb_error_name(ret)); //if (ret == LIBUSB_ERROR_NOT_FOUND) //{ // last_err_ = usb_manager::usb_error_2_hg_err(ret); // VLOG_MINI_1(LOG_LEVEL_FATAL, "device(%s) maybe left when libusb_reset_device.\n", hg_log::format_ptr(dev_info_.device).c_str()); // // return false; //} std::this_thread::sleep_for(std::chrono::milliseconds(100)); ret = libusb_claim_interface(handle_, spl->iface); if (ret == LIBUSB_SUCCESS) { spl->claimed = true; VLOG_MINI_2(LOG_LEVEL_FATAL, "second libusb_claim_interface(%d) = %s\n", spl->iface, libusb_error_name(ret)); return true; } VLOG_MINI_2(LOG_LEVEL_FATAL, "second try libusb_claim_interface(%d) = %s\n", spl->iface, libusb_error_name(ret)); last_err_ = SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED; return false; } int usb_io::claim_interfaces(bool claim) { usb_manager::USBENDP* eps[] = { &endpoints_.control, &endpoints_.isochronous, &endpoints_.bulk, &endpoints_.interrupt, &endpoints_.bulk_stream }; std::vector claimed; if (claim) { for (size_t i = 0; i < _countof(eps); ++i) { if (eps[i]->in.port != usb_manager::uninit_uint8 && std::find(claimed.begin(), claimed.end(), eps[i]->in.iface) == claimed.end()) { if (!claim_interterface(&eps[i]->in)) break; claimed.push_back(eps[i]->in.iface); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "claimed %s interface %d\n", usb_manager::endpoint_type((libusb_transfer_type)i).c_str(), eps[i]->in.iface); } if (eps[i]->out.port != usb_manager::uninit_uint8 && eps[i]->out.iface != eps[i]->in.iface && std::find(claimed.begin(), claimed.end(), eps[i]->out.iface) == claimed.end()) { if (!claim_interterface(&eps[i]->out)) break; claimed.push_back(eps[i]->out.iface); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "claimed %s interface %d\n", usb_manager::endpoint_type((libusb_transfer_type)i).c_str(), eps[i]->out.iface); } } } else { for (size_t i = 0; i < _countof(eps); ++i) { if (eps[i]->in.claimed) libusb_release_interface(handle_, eps[i]->in.iface); if (eps[i]->out.claimed) libusb_release_interface(handle_, eps[i]->out.iface); } last_err_ = SCANNER_ERR_OK; } return last_err_; } void usb_io::init_after_open(void) { last_err_ = SCANNER_ERR_OK; libusb_set_auto_detach_kernel_driver(handle_, 1); usb_manager::enum_endpoints(dev_info_.device, &endpoints_); if (claim_interfaces(true) != SCANNER_ERR_OK) { int err = last_err_; close(); last_err_ = err; } else { char str[128] = { 0 }, *ver = nullptr; libusb_device_descriptor dd = { 0 }; libusb_get_device_descriptor(dev_info_.device, &dd); libusb_get_string_descriptor_ascii(handle_, dd.iProduct, (unsigned char*)str, _countof(str) - 1); VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "Device Product: '%s'\n", str); ver = strstr(str, "(V"); if (ver) { ver_ = (int)atof(ver + 2); } else { ver_ = 1; } } } void usb_io::open(void) { if (!make_singleton()) return; if (ref_device_) libusb_unref_device(ref_device_); ref_device_ = libusb_ref_device(dev_info_.device); int ret = libusb_open(dev_info_.device, &handle_); VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "call libusb_open(%s, %s) = %s\n", hg_log::format_ptr(dev_info_.device).c_str() , hg_log::format_ptr(handle_).c_str(), libusb_error_name(ret)); if (ret == LIBUSB_SUCCESS) { init_after_open(); } else { handle_ = libusb_open_device_with_vid_pid(dev_info_.contex, dev_info_.vid, dev_info_.pid); if (handle_) { init_after_open(); return; } last_err_ = usb_manager::usb_error_2_hg_err(ret); VLOG_MINI_4(LOG_LEVEL_FATAL, "Open USB%u.%u-%s failed: %s\n", HIBYTE(dev_info_.ver), LOBYTE(dev_info_.ver) / 0x10, hg_log::format_ptr(dev_info_.device).c_str(), libusb_error_name(ret)); init_err_msg_ = hg_scanner_err_description(last_err_); handle_ = NULL; } } bool usb_io::on_io_error(scanner_err err, usb_manager::USBSIMPLEX* endp) { if (err == SCANNER_ERR_OK) return true; if (err == SCANNER_ERR_TIMEOUT) { //因为在发送img参数出现timeout,暂时禁? // //LOG_INFO(LOG_LEVEL_DEBUG_INFO, "Operation timeout\n"); // libusb_clear_halt(handle_, endp->port); // return libusb_reset_device(handle_) == LIBUSB_SUCCESS; return true; } return true; } int usb_io::add_ref(void) { return ++ref_; // InterlockedIncreament in linux ? } int usb_io::release(void) { int ref = --ref_; // InterlockedDecreament in linux ? if (ref == 0) delete this; return ref; } int usb_io::control_io(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, void* buf, int* len) { #ifdef USE_OLD_USB return usb_->control_msg(type, req, val, ind, *len, buf); #endif if (!handle_) return last_err_; //if (endpoints_.control.in == usb_manager::uninit_uint8) // return SCANNER_ERR_DEVICE_NOT_SUPPORT; if (!len) return SCANNER_ERR_INVALID_PARAMETER; int ret = libusb_control_transfer(handle_, type, req, val, ind, (unsigned char*)buf, *len, to_); if (ret > 0) { *len = ret; last_err_ = SCANNER_ERR_OK; } else { //if (on_io_error((scanner_err)usb_manager::usb_error_2_hg_err(ret), &endpoints_.control.in)) //{ // ret = libusb_control_transfer(handle_, type, req, val, ind, (unsigned char*)buf, *len, to_); // if (ret > 0) // { // *len = ret; // last_err_ = SCANNER_ERR_OK; // return last_err_; // } // else // *len = 0; //} //else *len = 0; VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "libusb_control_transfer(%x, %x, %d, %d) = %s\n", type, req, val, ind, libusb_error_name(ret)); last_err_ = usb_manager::usb_error_2_hg_err(ret); } return last_err_; } int usb_io::read_bulk(void* buf, int* len) { #ifdef USE_OLD_USB *len = usb_->read_bulk(buf, *len); return SCANNER_ERR_OK; #endif if (!handle_) return last_err_; if(endpoints_.bulk.in.port == usb_manager::uninit_uint8) return SCANNER_ERR_DEVICE_NOT_SUPPORT; if (!len) return SCANNER_ERR_INVALID_PARAMETER; //if (*len < endpoints_.bulk.in.max_packet) // avoid transferring overflows ... //{ // *len = endpoints_.bulk.in.max_packet; // // return SCANNER_ERR_INSUFFICIENT_MEMORY; //} // libusb_clear_halt(handle_,endpoints_.bulk.in.port); int total = 0, err = libusb_bulk_transfer(handle_, endpoints_.bulk.in.port, (unsigned char*)buf, *len, &total, to_); if (err) { VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "read_bulk(%x, %d/%d) = %s\n", endpoints_.bulk.in.port, total, *len, libusb_error_name(err)); if (err == LIBUSB_ERROR_TIMEOUT && *len == total) { int old = to_; if(to_ < 10 * 1000) to_ *= 1.5f; //err = LIBUSB_SUCCESS; VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Read full length, we consider it as success, and increament timeout from %d to %d\n", old, to_); } } *len = total; last_err_ = usb_manager::usb_error_2_hg_err(err); return last_err_; } int usb_io::write_bulk(void* buf, int* len) { #ifdef USE_OLD_USB * len = usb_->write_bulk(buf, *len); return SCANNER_ERR_OK; #endif if (!handle_) return last_err_; if (endpoints_.bulk.out.port == usb_manager::uninit_uint8) return SCANNER_ERR_DEVICE_NOT_SUPPORT; if (!len) return SCANNER_ERR_INVALID_PARAMETER; unsigned char* data = (unsigned char*)buf; int total = 0, t = 0, err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.bulk.out.port, data, *len, &t, to_)); //VLOG_MINI_6(LOG_LEVEL_DEBUG_INFO, "First write port %x bulk %d/%d = %s(timeout = %d, packet size = %x)\n", endpoints_.bulk.out.port, t, *len, hg_scanner_err_name((scanner_err)err).c_str(), to_, endpoints_.bulk.out.max_packet); // printf("First write port %x bulk %d/%d = %s(timeout = %d, packet size = %x)\n", endpoints_.bulk.out.port, t, *len, hg_scanner_err_name((scanner_err)err).c_str(), to_, endpoints_.bulk.out.max_packet); if (!on_io_error((scanner_err)err, &endpoints_.bulk.out)) { *len = t; return err; } total += t; while (total < *len && (err == SCANNER_ERR_TIMEOUT || err == SCANNER_ERR_DEVICE_BUSY)) { if (!t) break; data += t; t = 0; err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.bulk.out.port, data, *len - total, &t, to_)); total += t; } //VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Last write bulk %d/%d = %s\n", total, *len, hg_scanner_err_name((scanner_err)err).c_str()); *len = total; last_err_ = err; return last_err_; } int usb_io::read_interrupt(void* buf, int* len) { #ifdef USE_OLD_USB * len = usb_->read_int(buf, *len); return SCANNER_ERR_OK; #endif if (!handle_) return last_err_; if (endpoints_.interrupt.in.port == usb_manager::uninit_uint8) return SCANNER_ERR_DEVICE_NOT_SUPPORT; if (!len) return SCANNER_ERR_INVALID_PARAMETER; if (*len < endpoints_.interrupt.in.max_packet) // avoid transferring overflows ... { *len = endpoints_.interrupt.in.max_packet; return SCANNER_ERR_INSUFFICIENT_MEMORY; } int io = 0; last_err_ = usb_manager::usb_error_2_hg_err(libusb_interrupt_transfer(handle_, endpoints_.interrupt.in.port, (unsigned char*)buf, *len, &io, to_)); *len = io; return last_err_; } int usb_io::write_interrupt(void* buf, int* len) { if (!handle_) return last_err_; if (endpoints_.interrupt.out.port == usb_manager::uninit_uint8) return SCANNER_ERR_DEVICE_NOT_SUPPORT; if (!len) return SCANNER_ERR_INVALID_PARAMETER; unsigned char* data = (unsigned char*)buf; int total = 0, t = 0, err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.interrupt.out.port, data, *len, &t, to_)); total += t; while (total < *len && (err == SCANNER_ERR_TIMEOUT || err == SCANNER_ERR_DEVICE_BUSY)) { data += t; t = 0; err = usb_manager::usb_error_2_hg_err(libusb_interrupt_transfer(handle_, endpoints_.interrupt.out.port, data, *len - total, &t, to_)); total += t; } *len = total; last_err_ = err; return last_err_; } int usb_io::read_isochronous(void* buf, int* len) { if (!handle_) return last_err_; return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int usb_io::write_isochronous(void* buf, int* len) { if (!handle_) return last_err_; return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int usb_io::read_bulk_stream(void* buf, int* len) { if (!handle_) return last_err_; return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int usb_io::write_bulk_stream(void* buf, int* len) { if (!handle_) return last_err_; return SCANNER_ERR_DEVICE_NOT_SUPPORT; } int usb_io::reset(void) { if (!handle_) return SCANNER_ERR_NOT_OPEN; return usb_manager::usb_error_2_hg_err(libusb_reset_device(handle_)); } int usb_io::reopen(void) { close(); open(); return last_err_; } int usb_io::close(void) { #ifdef USE_OLD_USB usb_.reset(); return SCANNER_ERR_OK; #endif if (singleton_) singleton_->release(); singleton_ = nullptr; if (handle_) { claim_interfaces(false); libusb_close(handle_); handle_ = nullptr; } clear_endpoints(); if (ref_device_) { libusb_unref_device(ref_device_); ref_device_ = nullptr; } return SCANNER_ERR_OK; } libusb_device* usb_io::get_usb_device(void) { return dev_info_.device; } int usb_io::get_vid(void) { return dev_info_.vid; } int usb_io::get_pid(void) { return dev_info_.pid; } int usb_io::get_ver(void) { return ver_; } void usb_io::on_disconnected(void) { close(); last_err_ = SCANNER_ERR_DEVICE_NOT_FOUND; } std::string usb_io::init_error_msg(void) { return init_err_msg_; } bool usb_io::is_ready(void) { return handle_ != NULL; } int usb_io::last_error(void) { return last_err_; } int usb_io::get_bulk_packet_size(int* bytes) { if (!bytes) return SCANNER_ERR_INVALID_PARAMETER; if (endpoints_.bulk.in.port == usb_manager::uninit_uint8 && endpoints_.bulk.out.port == usb_manager::uninit_uint8) return SCANNER_ERR_DEVICE_NOT_SUPPORT; *bytes = endpoints_.bulk.in.max_packet; return SCANNER_ERR_OK; } int usb_io::get_interrupt_packet_size(int* bytes) { if (!bytes) return SCANNER_ERR_INVALID_PARAMETER; if (endpoints_.interrupt.in.port == usb_manager::uninit_uint8 && endpoints_.interrupt.out.port == usb_manager::uninit_uint8) return SCANNER_ERR_DEVICE_NOT_SUPPORT; *bytes = endpoints_.interrupt.in.max_packet; return SCANNER_ERR_OK; } unsigned int usb_io::set_timeout(unsigned int to) { unsigned int old = to_; to_ = to; #if defined(WIN32) || defined(_WIN64) if (handle_) { libusb_set_timeout(handle_, to_); } #endif return old; } unsigned int usb_io::get_timeout(void) { return to_; }