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
52 using chrono::milliseconds
;
53 using chrono::operator ""ms
;
54 using chrono::seconds
;
55 using chrono::operator ""s
;
57 static atomic
<seconds
> g_wait_usb_timeout
{-1s
};
58 static atomic
<milliseconds
> g_usb_poll_period
{200ms
};
59 static atomic
<seconds
> g_wait_next_usb_timeout
{-1s
};
61 enum KnownDeviceState
{
67 static atomic
<KnownDeviceState
> g_known_device_state
{NoKnownDevice
};
74 if (libusb_init(nullptr) < 0)
75 throw runtime_error
{ "Call libusb_init failure" };
86 libusb_device
**list
= nullptr;
88 CAutoList(libusb_device
**list
)
94 CAutoList(CAutoList
&&other
)
96 this->list
= other
.list
;
97 this->m_rc
= other
.m_rc
;
103 m_rc
= libusb_get_device_list(nullptr, &list
);
105 set_last_err_string(std::string("libusb_get_device_list failed: ") +
106 libusb_strerror(static_cast<libusb_error
>(m_rc
)));
112 if (list
!= nullptr) {
113 libusb_free_device_list(list
, 1);
117 CAutoList
& operator=(CAutoList
&&other
)
119 this->list
= other
.list
;
120 this->m_rc
= other
.m_rc
;
121 other
.list
= nullptr;
125 CAutoList
& operator=(const CAutoList
&) = delete; // Prevent copy, allow move only
126 CAutoList(const CAutoList
&) = delete; // Prevent copy, allow move only
141 void push_back(string filter
)
143 lock_guard
<mutex
> guard
{lock
};
144 list
.emplace_back(std::move(filter
));
147 bool is_valid(const string
& path
)
149 lock_guard
<mutex
> guard
{lock
};
153 auto end
= list
.end();
154 auto pos
= find(list
.begin(), end
, path
);
161 using Clock
= chrono::steady_clock
;
162 Clock::time_point start
;
164 explicit Timer(Clock::time_point start
) : start
{start
} {}
165 Timer() : Timer
{Clock::now()} {}
167 bool is_elapsed(Clock::duration interval
) const
169 return (Clock::now() - start
) >= interval
;
172 void reset(Clock::time_point start
)
186 #define TRY_SUDO ",Try sudo uuu"
189 static string
get_device_path(libusb_device
*dev
)
193 int bus
= libusb_get_bus_number(dev
);
197 str
.format("%d:", bus
);
199 int ret
= libusb_get_port_numbers(dev
, path
, sizeof(path
));
204 s
.format("%d", path
[0]);
207 for (int j
= 1; j
< ret
; j
++)
209 s
.format("%d", path
[j
]);
215 static int open_libusb(libusb_device
*dev
, void **usb_device_handle
)
226 /* work around windows open device failure 1/10
227 * sometime HID device detect need some time, refresh list
228 * to make sure HID driver installed.
233 if ((ret
= libusb_open(dev
, (libusb_device_handle
**)(usb_device_handle
))) < 0)
235 if ((ret
!= LIBUSB_ERROR_NOT_SUPPORTED
) || (retry
== 0))
237 set_last_err_string("Failure open usb device" TRY_SUDO
);
240 this_thread::sleep_for(200ms
);
252 Thread function. Didn't call this function directly.
253 Unbalance libusb_unref_device.
254 Before start thread, need call libusb_ref_device to dev is free
257 libusb_ref_device // avoid free at libusb_free_list if run_usb_cmd have not open device in time.
258 thread start run_usb_cmds;
261 static int run_usb_cmds(ConfigItem
*item
, libusb_device
*dev
, short bcddevice
)
265 nt
.type
= uuu_notify::NOTIFY_DEV_ATTACH
;
268 str
= get_device_path(dev
);
269 nt
.str
= (char*)str
.c_str();
273 ctx
.m_config_item
= item
;
274 ctx
.m_current_bcd
= bcddevice
;
276 if ((ret
= open_libusb(dev
, &(ctx
.m_dev
))))
278 nt
.type
= uuu_notify::NOTIFY_CMD_END
;
284 ret
= run_cmds(item
->m_protocol
.c_str(), &ctx
);
285 g_known_device_state
= KnownDeviceDone
;
287 nt
.type
= uuu_notify::NOTIFY_THREAD_EXIT
;
290 libusb_unref_device(dev
); //ref_device when start thread
295 static int usb_add(libusb_device
*dev
)
297 struct libusb_device_descriptor desc
;
298 int r
= libusb_get_device_descriptor(dev
, &desc
);
300 set_last_err_string("failure get device descriptor");
305 str
= get_device_path(dev
);
306 if (!g_filter_usbpath
.is_valid(str
))
309 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
313 g_known_device_state
= KnownDeviceToDo
;
316 * start new thread, need increase dev ref number.
317 * otherwise polling thread, free_device_list free device if open device call after free_device_list.
319 libusb_ref_device(dev
);
321 std::thread(run_usb_cmds
, item
, dev
, desc
.bcdDevice
).detach();
326 static int usb_remove(libusb_device
* /*dev*/)
332 void compare_list(libusb_device
** old
, libusb_device
**nw
)
339 while ((dev
= nw
[i
++]) != nullptr)
346 while ((dev
= nw
[i
++]) != nullptr)
350 while ((p
= old
[j
++]) != nullptr)
360 while ((dev
= old
[i
++]) != nullptr)
364 while ((p
= nw
[j
++]) != nullptr)
374 static int check_usb_timeout(Timer
& usb_timer
)
376 auto known_device_state
= g_known_device_state
.load();
377 if (known_device_state
== KnownDeviceDone
)
379 g_known_device_state
= known_device_state
= WaitNextKnownDevice
;
383 auto usb_timeout
= g_wait_usb_timeout
.load();
384 if (usb_timeout
>= 0s
&& known_device_state
== NoKnownDevice
)
386 if (usb_timer
.is_elapsed(usb_timeout
))
388 set_last_err_string("Timeout: Wait for Known USB Device");
393 usb_timeout
= g_wait_next_usb_timeout
.load();
394 if (usb_timeout
>= 0s
&& g_known_device_state
== WaitNextKnownDevice
)
396 if (usb_timer
.is_elapsed(usb_timeout
))
398 set_last_err_string("Timeout: Wait for next USB Device");
406 int polling_usb(std::atomic
<int>& bexit
)
408 if (run_cmds("CFG:", nullptr))
413 CAutoList
oldlist(nullptr);
423 compare_list(oldlist
.list
, newlist
.list
);
425 std::swap(oldlist
, newlist
);
427 this_thread::sleep_for(g_usb_poll_period
.load());
429 if (check_usb_timeout(usb_timer
))
436 CmdUsbCtx::~CmdUsbCtx()
440 libusb_close((libusb_device_handle
*)m_dev
);
445 int CmdUsbCtx::look_for_match_device(const char *pro
)
447 if (run_cmds("CFG:", nullptr))
463 while ((dev
= l
.list
[i
++]) != nullptr)
465 struct libusb_device_descriptor desc
;
466 int r
= libusb_get_device_descriptor(dev
, &desc
);
468 set_last_err_string("failure get device descriptor");
471 string str
= get_device_path(dev
);
473 if (!g_filter_usbpath
.is_valid(str
))
476 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
477 if (item
&& item
->m_protocol
== str_to_upper(pro
))
480 nt
.type
= uuu_notify::NOTIFY_DEV_ATTACH
;
481 m_config_item
= item
;
482 m_current_bcd
= desc
.bcdDevice
;
485 if ((ret
= open_libusb(dev
, &(m_dev
))))
488 nt
.str
= (char*)str
.c_str();
495 this_thread::sleep_for(200ms
);
498 nt
.type
= nt
.NOTIFY_WAIT_FOR
;
499 nt
.str
= (char*)"Wait for Known USB";
502 check_usb_timeout(usb_timer
);
508 int uuu_add_usbpath_filter(const char *path
)
510 g_filter_usbpath
.push_back(path
);
514 int uuu_for_each_devices(uuu_ls_usb_devices fn
, void *p
)
524 while ((dev
= l
.list
[i
++]) != nullptr)
526 struct libusb_device_descriptor desc
;
527 int r
= libusb_get_device_descriptor(dev
, &desc
);
529 set_last_err_string("failure get device descriptor");
532 string str
= get_device_path(dev
);
534 ConfigItem
*item
= get_config()->find(desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
);
537 if (fn(str
.c_str(), item
->m_chip
.c_str(), item
->m_protocol
.c_str(), desc
.idVendor
, desc
.idProduct
, desc
.bcdDevice
, p
))
539 set_last_err_string("call back return error");
548 int uuu_set_wait_timeout(int timeout_in_seconds
)
550 g_wait_usb_timeout
= seconds
{timeout_in_seconds
};
554 void uuu_set_poll_period(int period_in_milliseconds
)
556 g_usb_poll_period
= milliseconds
{period_in_milliseconds
};
559 int uuu_set_wait_next_timeout(int timeout_in_seconds
)
561 g_wait_next_usb_timeout
= seconds
{timeout_in_seconds
};