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
);
251 sid
= info
->serial_idx
;
254 serial
.resize(SERIAL_NO_MAX
);
255 libusb_open(dev
, &dev_handle
);
256 if (sid
&& dev_handle
)
257 ret
= libusb_get_string_descriptor_ascii(dev_handle
, sid
, (unsigned char*)serial
.c_str(), SERIAL_NO_MAX
);
258 libusb_close(dev_handle
);
262 return str_to_upper(serial
);
265 static string
get_device_serial_no(libusb_device
*dev
)
269 struct libusb_device_descriptor desc
;
270 int r
= libusb_get_device_descriptor(dev
, &desc
);
272 set_last_err_string("failure get device descriptor");
276 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
278 return get_device_serial_no(dev
, &desc
, item
);
281 static int open_libusb(libusb_device
*dev
, void **usb_device_handle
)
289 /* work around windows open device failure 1/10
290 * sometime HID device detect need some time, refresh list
291 * to make sure HID driver installed.
293 * On linux, udev rules may need some time to kick in,
294 * so also retry on -EACCES.
299 if ((ret
= libusb_open(dev
, (libusb_device_handle
**)(usb_device_handle
))) < 0)
301 if ((ret
!= LIBUSB_ERROR_NOT_SUPPORTED
&& ret
!= LIBUSB_ERROR_ACCESS
)
304 set_last_err_string("Failure open usb device" TRY_SUDO
);
307 this_thread::sleep_for(200ms
);
319 Thread function. Didn't call this function directly.
320 Unbalance libusb_unref_device.
321 Before start thread, need call libusb_ref_device to dev is free
324 libusb_ref_device // avoid free at libusb_free_list if run_usb_cmd have not open device in time.
325 thread start run_usb_cmds;
328 static int run_usb_cmds(ConfigItem
*item
, libusb_device
*dev
, short bcddevice
)
332 nt
.type
= uuu_notify::NOTIFY_DEV_ATTACH
;
335 str
= get_device_path(dev
);
337 str
+= get_device_serial_no(dev
);
338 nt
.str
= (char*)str
.c_str();
342 ctx
.m_config_item
= item
;
343 ctx
.m_current_bcd
= bcddevice
;
345 if ((ret
= open_libusb(dev
, &(ctx
.m_dev
))))
347 nt
.type
= uuu_notify::NOTIFY_CMD_END
;
353 ret
= run_cmds(item
->m_protocol
.c_str(), &ctx
);
354 g_known_device_state
= KnownDeviceDone
;
356 nt
.type
= uuu_notify::NOTIFY_THREAD_EXIT
;
359 libusb_unref_device(dev
); //ref_device when start thread
364 static int usb_add(libusb_device
*dev
)
366 struct libusb_device_descriptor desc
;
367 int r
= libusb_get_device_descriptor(dev
, &desc
);
369 set_last_err_string("failure get device descriptor");
374 str
= get_device_path(dev
);
375 if (!g_filter_usbpath
.is_valid(str
))
378 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
382 string serial
= get_device_serial_no(dev
, &desc
, item
);
383 if (!g_filter_usbserial_no
.is_valid(serial
))
386 g_known_device_state
= KnownDeviceToDo
;
389 * start new thread, need increase dev ref number.
390 * otherwise polling thread, free_device_list free device if open device call after free_device_list.
392 libusb_ref_device(dev
);
394 std::thread(run_usb_cmds
, item
, dev
, desc
.bcdDevice
).detach();
399 static int usb_remove(libusb_device
* /*dev*/)
405 void compare_list(libusb_device
** old
, libusb_device
**nw
)
412 while ((dev
= nw
[i
++]) != nullptr)
419 while ((dev
= nw
[i
++]) != nullptr)
423 while ((p
= old
[j
++]) != nullptr)
433 while ((dev
= old
[i
++]) != nullptr)
437 while ((p
= nw
[j
++]) != nullptr)
447 static int check_usb_timeout(Timer
& usb_timer
)
449 auto known_device_state
= g_known_device_state
.load();
450 if (known_device_state
== KnownDeviceDone
)
452 g_known_device_state
= known_device_state
= WaitNextKnownDevice
;
456 auto usb_timeout
= g_wait_usb_timeout
.load();
457 if (usb_timeout
>= 0s
&& known_device_state
== NoKnownDevice
)
459 if (usb_timer
.is_elapsed(usb_timeout
))
461 set_last_err_string("Timeout: Wait for Known USB Device");
466 usb_timeout
= g_wait_next_usb_timeout
.load();
467 if (usb_timeout
>= 0s
&& g_known_device_state
== WaitNextKnownDevice
)
469 if (usb_timer
.is_elapsed(usb_timeout
))
471 set_last_err_string("Timeout: Wait for next USB Device");
479 int polling_usb(std::atomic
<int>& bexit
)
481 if (run_cmds("CFG:", nullptr))
486 CAutoList
oldlist(nullptr);
496 compare_list(oldlist
.list
, newlist
.list
);
498 std::swap(oldlist
, newlist
);
500 this_thread::sleep_for(g_usb_poll_period
.load());
502 if (check_usb_timeout(usb_timer
))
509 CmdUsbCtx::~CmdUsbCtx()
513 libusb_close((libusb_device_handle
*)m_dev
);
518 int CmdUsbCtx::look_for_match_device(const char *pro
)
520 if (run_cmds("CFG:", nullptr))
536 while ((dev
= l
.list
[i
++]) != nullptr)
538 struct libusb_device_descriptor desc
;
539 int r
= libusb_get_device_descriptor(dev
, &desc
);
541 set_last_err_string("failure get device descriptor");
544 string str
= get_device_path(dev
);
546 if (!g_filter_usbpath
.is_valid(str
))
549 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
551 string serial_no
= get_device_serial_no(dev
, &desc
, item
);
552 if (!g_filter_usbserial_no
.is_valid(serial_no
))
555 if (item
&& item
->m_protocol
== str_to_upper(pro
))
558 nt
.type
= uuu_notify::NOTIFY_DEV_ATTACH
;
559 m_config_item
= item
;
560 m_current_bcd
= desc
.bcdDevice
;
563 if ((ret
= open_libusb(dev
, &(m_dev
))))
566 nt
.str
= (char*)str
.c_str();
573 this_thread::sleep_for(200ms
);
576 nt
.type
= nt
.NOTIFY_WAIT_FOR
;
577 nt
.str
= (char*)"Wait for Known USB";
580 if (check_usb_timeout(usb_timer
))
587 int uuu_add_usbpath_filter(const char *path
)
589 g_filter_usbpath
.push_back(path
);
593 int uuu_add_usbserial_no_filter(const char *serial_no
)
595 g_filter_usbserial_no
.push_back(serial_no
);
599 int uuu_for_each_devices(uuu_ls_usb_devices fn
, void *p
)
609 while ((dev
= l
.list
[i
++]) != nullptr)
611 struct libusb_device_descriptor desc
;
612 int r
= libusb_get_device_descriptor(dev
, &desc
);
614 set_last_err_string("failure get device descriptor");
617 string str
= get_device_path(dev
);
619 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
622 string serial
= get_device_serial_no(dev
, &desc
, item
);
623 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
))
625 set_last_err_string("call back return error");
634 int uuu_set_wait_timeout(int timeout_in_seconds
)
636 g_wait_usb_timeout
= seconds
{timeout_in_seconds
};
640 void uuu_set_poll_period(int period_in_milliseconds
)
642 g_usb_poll_period
= milliseconds
{period_in_milliseconds
};
645 int uuu_set_wait_next_timeout(int timeout_in_seconds
)
647 g_wait_next_usb_timeout
= seconds
{timeout_in_seconds
};