4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
14 * Neither the name of the NXP Semiconductor nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
33 * Windows libusb don't support hotplug yet
34 * Will polling devices list every 100ms
54 using chrono::milliseconds
;
55 using chrono::operator ""ms
;
56 using chrono::seconds
;
57 using chrono::operator ""s
;
59 static atomic
<seconds
> g_wait_usb_timeout
{-1s
};
60 static atomic
<milliseconds
> g_usb_poll_period
{200ms
};
61 static atomic
<seconds
> g_wait_next_usb_timeout
{-1s
};
63 enum KnownDeviceState
{
69 static atomic
<KnownDeviceState
> g_known_device_state
{NoKnownDevice
};
76 if (libusb_init(nullptr) < 0)
77 throw runtime_error
{ "Call libusb_init failure" };
88 libusb_device
**list
= nullptr;
90 CAutoList(libusb_device
**list
)
96 CAutoList(CAutoList
&&other
)
98 this->list
= other
.list
;
99 this->m_rc
= other
.m_rc
;
100 other
.list
= nullptr;
105 m_rc
= libusb_get_device_list(nullptr, &list
);
107 set_last_err_string(std::string("libusb_get_device_list failed: ") +
108 libusb_strerror(static_cast<libusb_error
>(m_rc
)));
114 if (list
!= nullptr) {
115 libusb_free_device_list(list
, 1);
119 CAutoList
& operator=(CAutoList
&&other
)
121 this->list
= other
.list
;
122 this->m_rc
= other
.m_rc
;
123 other
.list
= nullptr;
127 CAutoList
& operator=(const CAutoList
&) = delete; // Prevent copy, allow move only
128 CAutoList(const CAutoList
&) = delete; // Prevent copy, allow move only
143 void push_back(string filter
)
145 lock_guard
<mutex
> guard
{lock
};
146 list
.emplace_back(std::move(filter
));
150 static struct: public filter
{
151 bool is_valid(const string
& path
)
153 lock_guard
<mutex
> guard
{lock
};
157 auto end
= list
.end();
158 auto pos
= find(list
.begin(), end
, path
);
164 static struct: public filter
{
165 bool is_valid(const string
& serial_no
)
167 lock_guard
<mutex
> guard
{lock
};
171 if (serial_no
.empty())
175 if (compare_str(serial_no
.substr(0, it
.length()), it
, true))
181 } g_filter_usbserial_no
;
185 using Clock
= chrono::steady_clock
;
186 Clock::time_point start
;
188 explicit Timer(Clock::time_point start
) : start
{start
} {}
189 Timer() : Timer
{Clock::now()} {}
191 bool is_elapsed(Clock::duration interval
) const
193 return (Clock::now() - start
) >= interval
;
196 void reset(Clock::time_point start
)
210 #define TRY_SUDO ",Try sudo uuu"
213 static string
get_device_path(libusb_device
*dev
)
217 int bus
= libusb_get_bus_number(dev
);
221 str
.format("%d:", bus
);
223 int ret
= libusb_get_port_numbers(dev
, path
, sizeof(path
));
228 s
.format("%d", path
[0]);
231 for (int j
= 1; j
< ret
; j
++)
233 s
.format("%d", path
[j
]);
239 #define SERIAL_NO_MAX 512
241 static string
get_device_serial_no(libusb_device
*dev
, struct libusb_device_descriptor
*desc
, ConfigItem
*item
)
244 struct libusb_device_handle
*dev_handle
= NULL
;
245 int sid
= desc
->iSerialNumber
;
249 const ROM_INFO
*info
= search_rom_info(item
);
250 sid
= info
->serial_idx
;
253 serial
.resize(SERIAL_NO_MAX
);
254 libusb_open(dev
, &dev_handle
);
255 if (sid
&& dev_handle
)
256 ret
= libusb_get_string_descriptor_ascii(dev_handle
, sid
, (unsigned char*)serial
.c_str(), SERIAL_NO_MAX
);
257 libusb_close(dev_handle
);
261 return str_to_upper(serial
);
264 static string
get_device_serial_no(libusb_device
*dev
)
268 struct libusb_device_descriptor desc
;
269 int r
= libusb_get_device_descriptor(dev
, &desc
);
271 set_last_err_string("failure get device descriptor");
275 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
277 return get_device_serial_no(dev
, &desc
, item
);
280 static int open_libusb(libusb_device
*dev
, void **usb_device_handle
)
288 /* work around windows open device failure 1/10
289 * sometime HID device detect need some time, refresh list
290 * to make sure HID driver installed.
292 * On linux, udev rules may need some time to kick in,
293 * so also retry on -EACCES.
298 if ((ret
= libusb_open(dev
, (libusb_device_handle
**)(usb_device_handle
))) < 0)
300 if ((ret
!= LIBUSB_ERROR_NOT_SUPPORTED
&& ret
!= LIBUSB_ERROR_ACCESS
)
303 set_last_err_string("Failure open usb device" TRY_SUDO
);
306 this_thread::sleep_for(200ms
);
318 Thread function. Didn't call this function directly.
319 Unbalance libusb_unref_device.
320 Before start thread, need call libusb_ref_device to dev is free
323 libusb_ref_device // avoid free at libusb_free_list if run_usb_cmd have not open device in time.
324 thread start run_usb_cmds;
327 static int run_usb_cmds(ConfigItem
*item
, libusb_device
*dev
, short bcddevice
)
331 nt
.type
= uuu_notify::NOTIFY_DEV_ATTACH
;
334 str
= get_device_path(dev
);
336 str
+= get_device_serial_no(dev
);
337 nt
.str
= (char*)str
.c_str();
341 ctx
.m_config_item
= item
;
342 ctx
.m_current_bcd
= bcddevice
;
344 if ((ret
= open_libusb(dev
, &(ctx
.m_dev
))))
346 nt
.type
= uuu_notify::NOTIFY_CMD_END
;
352 ret
= run_cmds(item
->m_protocol
.c_str(), &ctx
);
353 g_known_device_state
= KnownDeviceDone
;
355 nt
.type
= uuu_notify::NOTIFY_THREAD_EXIT
;
358 libusb_unref_device(dev
); //ref_device when start thread
363 static int usb_add(libusb_device
*dev
)
365 struct libusb_device_descriptor desc
;
366 int r
= libusb_get_device_descriptor(dev
, &desc
);
368 set_last_err_string("failure get device descriptor");
373 str
= get_device_path(dev
);
374 if (!g_filter_usbpath
.is_valid(str
))
377 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
381 string serial
= get_device_serial_no(dev
, &desc
, item
);
382 if (!g_filter_usbserial_no
.is_valid(serial
))
385 g_known_device_state
= KnownDeviceToDo
;
388 * start new thread, need increase dev ref number.
389 * otherwise polling thread, free_device_list free device if open device call after free_device_list.
391 libusb_ref_device(dev
);
393 std::thread(run_usb_cmds
, item
, dev
, desc
.bcdDevice
).detach();
398 static int usb_remove(libusb_device
* /*dev*/)
404 void compare_list(libusb_device
** old
, libusb_device
**nw
)
411 while ((dev
= nw
[i
++]) != nullptr)
418 while ((dev
= nw
[i
++]) != nullptr)
422 while ((p
= old
[j
++]) != nullptr)
432 while ((dev
= old
[i
++]) != nullptr)
436 while ((p
= nw
[j
++]) != nullptr)
446 static int check_usb_timeout(Timer
& usb_timer
)
448 auto known_device_state
= g_known_device_state
.load();
449 if (known_device_state
== KnownDeviceDone
)
451 g_known_device_state
= known_device_state
= WaitNextKnownDevice
;
455 auto usb_timeout
= g_wait_usb_timeout
.load();
456 if (usb_timeout
>= 0s
&& known_device_state
== NoKnownDevice
)
458 if (usb_timer
.is_elapsed(usb_timeout
))
460 set_last_err_string("Timeout: Wait for Known USB Device");
465 usb_timeout
= g_wait_next_usb_timeout
.load();
466 if (usb_timeout
>= 0s
&& g_known_device_state
== WaitNextKnownDevice
)
468 if (usb_timer
.is_elapsed(usb_timeout
))
470 set_last_err_string("Timeout: Wait for next USB Device");
478 int polling_usb(std::atomic
<int>& bexit
)
480 if (run_cmds("CFG:", nullptr))
485 CAutoList
oldlist(nullptr);
495 compare_list(oldlist
.list
, newlist
.list
);
497 std::swap(oldlist
, newlist
);
499 this_thread::sleep_for(g_usb_poll_period
.load());
501 if (check_usb_timeout(usb_timer
))
508 CmdUsbCtx::~CmdUsbCtx()
512 libusb_close((libusb_device_handle
*)m_dev
);
517 int CmdUsbCtx::look_for_match_device(const char *pro
)
519 if (run_cmds("CFG:", nullptr))
535 while ((dev
= l
.list
[i
++]) != nullptr)
537 struct libusb_device_descriptor desc
;
538 int r
= libusb_get_device_descriptor(dev
, &desc
);
540 set_last_err_string("failure get device descriptor");
543 string str
= get_device_path(dev
);
545 if (!g_filter_usbpath
.is_valid(str
))
548 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
550 string serial_no
= get_device_serial_no(dev
, &desc
, item
);
551 if (!g_filter_usbserial_no
.is_valid(serial_no
))
554 if (item
&& item
->m_protocol
== str_to_upper(pro
))
557 nt
.type
= uuu_notify::NOTIFY_DEV_ATTACH
;
558 m_config_item
= item
;
559 m_current_bcd
= desc
.bcdDevice
;
562 if ((ret
= open_libusb(dev
, &(m_dev
))))
565 nt
.str
= (char*)str
.c_str();
572 this_thread::sleep_for(200ms
);
575 nt
.type
= nt
.NOTIFY_WAIT_FOR
;
576 nt
.str
= (char*)"Wait for Known USB";
579 if (check_usb_timeout(usb_timer
))
586 int uuu_add_usbpath_filter(const char *path
)
588 g_filter_usbpath
.push_back(path
);
592 int uuu_add_usbserial_no_filter(const char *serial_no
)
594 g_filter_usbserial_no
.push_back(serial_no
);
598 int uuu_for_each_devices(uuu_ls_usb_devices fn
, void *p
)
608 while ((dev
= l
.list
[i
++]) != nullptr)
610 struct libusb_device_descriptor desc
;
611 int r
= libusb_get_device_descriptor(dev
, &desc
);
613 set_last_err_string("failure get device descriptor");
616 string str
= get_device_path(dev
);
618 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
621 string serial
= get_device_serial_no(dev
, &desc
, item
);
622 if (fn(str
.c_str(), item
->m_chip
.c_str(), item
->m_protocol
.c_str(), desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
, serial
.c_str(), p
))
624 set_last_err_string("call back return error");
633 int uuu_set_wait_timeout(int timeout_in_seconds
)
635 g_wait_usb_timeout
= seconds
{timeout_in_seconds
};
639 void uuu_set_poll_period(int period_in_milliseconds
)
641 g_usb_poll_period
= milliseconds
{period_in_milliseconds
};
644 int uuu_set_wait_next_timeout(int timeout_in_seconds
)
646 g_wait_next_usb_timeout
= seconds
{timeout_in_seconds
};