2019-04-30 13:33:34 +00:00
|
|
|
// Copyright 2019, Collabora, Ltd.
|
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Main prober code.
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
|
|
* @ingroup st_prober
|
|
|
|
*/
|
|
|
|
|
2019-08-31 11:49:32 +00:00
|
|
|
#include "util/u_var.h"
|
2019-04-30 13:33:34 +00:00
|
|
|
#include "util/u_misc.h"
|
2019-08-31 11:49:32 +00:00
|
|
|
#include "util/u_debug.h"
|
2019-04-30 13:33:34 +00:00
|
|
|
#include "p_prober.h"
|
|
|
|
|
2019-11-10 01:36:34 +00:00
|
|
|
#ifdef XRT_HAVE_V4L2
|
2019-09-02 12:25:52 +00:00
|
|
|
#include "v4l2/v4l2_interface.h"
|
|
|
|
#endif
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Pre-declare functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
DEBUG_GET_ONCE_BOOL_OPTION(prober_spew, "PROBER_PRINT_SPEW", false)
|
|
|
|
DEBUG_GET_ONCE_BOOL_OPTION(prober_debug, "PROBER_PRINT_DEBUG", false)
|
|
|
|
|
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
add_device(struct prober *p, struct prober_device **out_dev);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
initialize(struct prober *p, struct xrt_prober_entry_lists *lists);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
teardown_devices(struct prober *p);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
teardown(struct prober *p);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
probe(struct xrt_prober *xp);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
dump(struct xrt_prober *xp);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
select_device(struct xrt_prober *xp,
|
|
|
|
struct xrt_device **xdevs,
|
2019-05-31 16:55:19 +00:00
|
|
|
size_t num_xdevs);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
open_hid_interface(struct xrt_prober *xp,
|
|
|
|
struct xrt_prober_device *xpdev,
|
2019-04-30 13:33:34 +00:00
|
|
|
int interface,
|
2019-09-29 10:44:00 +00:00
|
|
|
struct os_hid_device **out_hid_dev);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
2019-09-02 12:25:52 +00:00
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
open_video_device(struct xrt_prober *xp,
|
|
|
|
struct xrt_prober_device *xpdev,
|
|
|
|
struct xrt_frame_context *xfctx,
|
|
|
|
struct xrt_fs **out_xfs);
|
2019-09-02 12:25:52 +00:00
|
|
|
|
2019-06-28 13:02:10 +00:00
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
list_video_devices(struct xrt_prober *xp,
|
2019-06-28 13:02:10 +00:00
|
|
|
xrt_prober_list_video_cb cb,
|
2019-09-29 10:44:00 +00:00
|
|
|
void *ptr);
|
2019-06-21 17:33:41 +00:00
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
get_string_descriptor(struct xrt_prober *xp,
|
|
|
|
struct xrt_prober_device *xpdev,
|
2019-06-21 17:33:41 +00:00
|
|
|
enum xrt_prober_string which_string,
|
2019-09-29 10:44:00 +00:00
|
|
|
unsigned char *buffer,
|
2019-06-21 17:33:41 +00:00
|
|
|
int length);
|
2019-06-28 13:02:10 +00:00
|
|
|
|
2019-10-05 09:22:26 +00:00
|
|
|
static bool
|
|
|
|
can_open(struct xrt_prober *xp, struct xrt_prober_device *xpdev);
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
destroy(struct xrt_prober **xp);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* "Exported" functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2019-09-29 10:44:00 +00:00
|
|
|
xrt_prober_create_with_lists(struct xrt_prober **out_prober,
|
|
|
|
struct xrt_prober_entry_lists *lists)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober *p = U_TYPED_CALLOC(struct prober);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
int ret = initialize(p, lists);
|
|
|
|
if (ret != 0) {
|
|
|
|
free(p);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-08-16 22:01:18 +00:00
|
|
|
*out_prober = &p->base;
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-05 13:54:17 +00:00
|
|
|
#define ENUM_TO_STR(r) \
|
|
|
|
case r: return #r
|
|
|
|
|
|
|
|
const char *
|
|
|
|
xrt_prober_string_to_string(enum xrt_prober_string t)
|
|
|
|
{
|
|
|
|
switch (t) {
|
|
|
|
ENUM_TO_STR(XRT_PROBER_STRING_MANUFACTURER);
|
|
|
|
ENUM_TO_STR(XRT_PROBER_STRING_PRODUCT);
|
|
|
|
ENUM_TO_STR(XRT_PROBER_STRING_SERIAL_NUMBER);
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
xrt_bus_type_to_string(enum xrt_bus_type t)
|
|
|
|
{
|
|
|
|
switch (t) {
|
|
|
|
ENUM_TO_STR(XRT_BUS_TYPE_UNKNOWN);
|
|
|
|
ENUM_TO_STR(XRT_BUS_TYPE_USB);
|
|
|
|
ENUM_TO_STR(XRT_BUS_TYPE_BLUETOOTH);
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
xrt_prober_match_string(struct xrt_prober *xp,
|
|
|
|
struct xrt_prober_device *dev,
|
|
|
|
enum xrt_prober_string type,
|
|
|
|
const char *to_match)
|
|
|
|
{
|
|
|
|
unsigned char s[256] = {0};
|
|
|
|
int len = xrt_prober_get_string_descriptor(xp, dev, type, s, sizeof(s));
|
|
|
|
if (len == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return 0 == strncmp(to_match, (const char *)s, sizeof(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
int
|
2019-09-29 10:44:00 +00:00
|
|
|
p_dev_get_usb_dev(struct prober *p,
|
2019-04-30 13:33:34 +00:00
|
|
|
uint16_t bus,
|
|
|
|
uint16_t addr,
|
|
|
|
uint16_t vendor_id,
|
|
|
|
uint16_t product_id,
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device **out_pdev)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev;
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < p->num_devices; i++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = &p->devices[i];
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
if (pdev->base.bus != XRT_BUS_TYPE_USB ||
|
|
|
|
pdev->usb.bus != bus || pdev->usb.addr != addr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdev->base.vendor_id != vendor_id ||
|
|
|
|
pdev->base.product_id != product_id) {
|
|
|
|
P_ERROR(p,
|
|
|
|
"USB device with same address but different "
|
|
|
|
"vendor and product found!\n"
|
|
|
|
"\tvendor: %04x %04x\n"
|
|
|
|
"\tproduct: %04x %04x",
|
|
|
|
pdev->base.vendor_id, vendor_id,
|
|
|
|
pdev->base.product_id, product_id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_pdev = pdev;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_device(p, &pdev);
|
|
|
|
pdev->base.vendor_id = vendor_id;
|
|
|
|
pdev->base.product_id = product_id;
|
|
|
|
pdev->base.bus = XRT_BUS_TYPE_USB;
|
|
|
|
pdev->usb.bus = bus;
|
|
|
|
pdev->usb.addr = addr;
|
|
|
|
*out_pdev = pdev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-09-29 10:44:00 +00:00
|
|
|
p_dev_get_bluetooth_dev(struct prober *p,
|
2019-04-30 13:33:34 +00:00
|
|
|
uint64_t id,
|
|
|
|
uint16_t vendor_id,
|
|
|
|
uint16_t product_id,
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device **out_pdev)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev;
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < p->num_devices; i++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = &p->devices[i];
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
if (pdev->base.bus != XRT_BUS_TYPE_BLUETOOTH ||
|
|
|
|
pdev->bluetooth.id != id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdev->base.vendor_id != vendor_id ||
|
|
|
|
pdev->base.product_id != product_id) {
|
|
|
|
P_ERROR(p,
|
|
|
|
"Bluetooth device with same address but "
|
|
|
|
"different vendor and product found!\n"
|
|
|
|
"\tvendor: %04x %04x\n"
|
|
|
|
"\tproduct: %04x %04x",
|
|
|
|
pdev->base.vendor_id, vendor_id,
|
|
|
|
pdev->base.product_id, product_id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_pdev = pdev;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_device(p, &pdev);
|
|
|
|
pdev->base.vendor_id = vendor_id;
|
|
|
|
pdev->base.product_id = product_id;
|
|
|
|
pdev->base.bus = XRT_BUS_TYPE_BLUETOOTH;
|
|
|
|
pdev->bluetooth.id = id;
|
|
|
|
|
|
|
|
*out_pdev = pdev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Internal functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-09-02 12:25:59 +00:00
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
fill_out_product(struct prober *p, struct prober_device *pdev)
|
2019-09-02 12:25:59 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
const char *bus =
|
2019-09-02 12:25:59 +00:00
|
|
|
pdev->base.bus == XRT_BUS_TYPE_BLUETOOTH ? "bluetooth" : "usb";
|
|
|
|
|
2019-09-29 10:44:00 +00:00
|
|
|
char *str = NULL;
|
2019-09-02 12:25:59 +00:00
|
|
|
int ret = 0;
|
|
|
|
do {
|
|
|
|
ret = snprintf(str, ret, "Unknown %s device: %04x:%04x", bus,
|
|
|
|
pdev->base.vendor_id, pdev->base.product_id);
|
|
|
|
if (ret <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (str == NULL) {
|
|
|
|
str = U_CALLOC_WITH_CAST(char, ret + 1);
|
|
|
|
} else {
|
|
|
|
pdev->usb.product = str;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
add_device(struct prober *p, struct prober_device **out_dev)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
|
|
|
size_t new_size = (p->num_devices + 1) * sizeof(struct prober_device);
|
|
|
|
p->devices = realloc(p->devices, new_size);
|
|
|
|
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *dev = &p->devices[p->num_devices++];
|
2019-06-18 19:03:53 +00:00
|
|
|
U_ZERO(dev);
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
*out_dev = dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
add_usb_entry(struct prober *p, struct xrt_prober_entry *entry)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-12-02 23:20:44 +00:00
|
|
|
U_ARRAY_REALLOC_OR_FREE(p->entries, struct xrt_prober_entry *,
|
|
|
|
(p->num_entries + 1));
|
2019-04-30 13:33:34 +00:00
|
|
|
p->entries[p->num_entries++] = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
collect_entries(struct prober *p)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_prober_entry_lists *lists = p->lists;
|
2019-04-30 13:33:34 +00:00
|
|
|
while (lists) {
|
|
|
|
for (size_t j = 0; lists->entries != NULL && lists->entries[j];
|
|
|
|
j++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_prober_entry *entry = lists->entries[j];
|
2019-04-30 13:33:34 +00:00
|
|
|
for (size_t k = 0; entry[k].found != NULL; k++) {
|
|
|
|
add_usb_entry(p, &entry[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lists = lists->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
initialize(struct prober *p, struct xrt_prober_entry_lists *lists)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
|
|
|
p->base.probe = probe;
|
|
|
|
p->base.dump = dump;
|
|
|
|
p->base.select = select_device;
|
|
|
|
p->base.open_hid_interface = open_hid_interface;
|
2019-09-02 12:25:52 +00:00
|
|
|
p->base.open_video_device = open_video_device;
|
2019-06-28 13:02:10 +00:00
|
|
|
p->base.list_video_devices = list_video_devices;
|
2019-06-21 17:33:41 +00:00
|
|
|
p->base.get_string_descriptor = get_string_descriptor;
|
2019-10-05 09:22:26 +00:00
|
|
|
p->base.can_open = can_open;
|
2019-04-30 13:33:34 +00:00
|
|
|
p->base.destroy = destroy;
|
|
|
|
p->lists = lists;
|
|
|
|
p->print_spew = debug_get_bool_option_prober_spew();
|
|
|
|
p->print_debug = debug_get_bool_option_prober_debug();
|
|
|
|
|
2019-09-29 10:44:00 +00:00
|
|
|
u_var_add_root((void *)p, "Prober", true);
|
|
|
|
u_var_add_bool((void *)p, &p->print_debug, "Debug");
|
|
|
|
u_var_add_bool((void *)p, &p->print_spew, "Spew");
|
2019-08-31 11:49:32 +00:00
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = collect_entries(p);
|
|
|
|
if (ret != 0) {
|
|
|
|
teardown(p);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-06-20 13:51:34 +00:00
|
|
|
#ifdef XRT_HAVE_LIBUSB
|
|
|
|
ret = p_libusb_init(p);
|
2019-04-30 13:33:34 +00:00
|
|
|
if (ret != 0) {
|
|
|
|
teardown(p);
|
|
|
|
return -1;
|
|
|
|
}
|
2019-06-20 13:51:34 +00:00
|
|
|
#endif
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
#ifdef XRT_HAVE_LIBUVC
|
2019-06-20 14:14:09 +00:00
|
|
|
ret = p_libuvc_init(p);
|
2019-04-30 13:33:34 +00:00
|
|
|
if (ret != 0) {
|
|
|
|
teardown(p);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-09-21 18:08:26 +00:00
|
|
|
ret = p_tracking_init(p);
|
|
|
|
if (ret != 0) {
|
|
|
|
teardown(p);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
for (int i = 0; i < MAX_AUTO_PROBERS && lists->auto_probers[i]; i++) {
|
|
|
|
p->auto_probers[i] = lists->auto_probers[i]();
|
|
|
|
}
|
2019-06-20 13:51:34 +00:00
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
teardown_devices(struct prober *p)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
|
|
|
// Need to free all devices.
|
|
|
|
for (size_t i = 0; i < p->num_devices; i++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = &p->devices[i];
|
2019-04-30 13:33:34 +00:00
|
|
|
|
2019-06-20 14:14:53 +00:00
|
|
|
#ifdef XRT_OS_LINUX
|
2019-06-26 14:10:32 +00:00
|
|
|
if (pdev->usb.product != NULL) {
|
2019-09-29 10:44:00 +00:00
|
|
|
free((char *)pdev->usb.product);
|
2019-06-26 14:10:32 +00:00
|
|
|
pdev->usb.product = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdev->usb.path != NULL) {
|
2019-09-29 10:44:00 +00:00
|
|
|
free((char *)pdev->usb.path);
|
2019-06-26 14:10:32 +00:00
|
|
|
pdev->usb.path = NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-20 17:27:21 +00:00
|
|
|
for (size_t j = 0; j < pdev->num_v4ls; j++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_v4l *v4l = &pdev->v4ls[j];
|
|
|
|
free((char *)v4l->path);
|
2019-06-20 17:27:21 +00:00
|
|
|
v4l->path = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdev->v4ls != NULL) {
|
|
|
|
free(pdev->v4ls);
|
|
|
|
pdev->v4ls = NULL;
|
|
|
|
pdev->num_v4ls = 0;
|
|
|
|
}
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
for (size_t j = 0; j < pdev->num_hidraws; j++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_hidraw *hidraw = &pdev->hidraws[j];
|
|
|
|
free((char *)hidraw->path);
|
2019-04-30 13:33:34 +00:00
|
|
|
hidraw->path = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdev->hidraws != NULL) {
|
|
|
|
free(pdev->hidraws);
|
|
|
|
pdev->hidraws = NULL;
|
|
|
|
pdev->num_hidraws = 0;
|
|
|
|
}
|
2019-06-20 14:14:53 +00:00
|
|
|
#endif
|
2019-04-30 13:33:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (p->devices != NULL) {
|
|
|
|
free(p->devices);
|
|
|
|
p->devices = NULL;
|
|
|
|
p->num_devices = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
teardown(struct prober *p)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-08-31 11:49:32 +00:00
|
|
|
// First remove the variable tracking.
|
2019-09-29 10:44:00 +00:00
|
|
|
u_var_remove_root((void *)p);
|
2019-08-31 11:49:32 +00:00
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
// Clean up all auto_probers.
|
|
|
|
for (int i = 0; i < MAX_AUTO_PROBERS && p->auto_probers[i]; i++) {
|
|
|
|
p->auto_probers[i]->destroy(p->auto_probers[i]);
|
|
|
|
p->auto_probers[i] = NULL;
|
|
|
|
}
|
|
|
|
|
2019-09-21 18:08:26 +00:00
|
|
|
// Need to turn off tracking early.
|
|
|
|
p_tracking_teardown(p);
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
// Need to free all entries.
|
|
|
|
if (p->entries != NULL) {
|
|
|
|
free(p->entries);
|
|
|
|
p->entries = NULL;
|
|
|
|
p->num_entries = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
teardown_devices(p);
|
|
|
|
|
|
|
|
#ifdef XRT_HAVE_LIBUVC
|
2019-06-20 14:14:09 +00:00
|
|
|
p_libuvc_teardown(p);
|
2019-04-30 13:33:34 +00:00
|
|
|
#endif
|
|
|
|
|
2019-06-20 13:51:34 +00:00
|
|
|
#ifdef XRT_HAVE_LIBUSB
|
|
|
|
p_libusb_teardown(p);
|
|
|
|
#endif
|
2019-04-30 13:33:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Member functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
probe(struct xrt_prober *xp)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober *p = (struct prober *)xp;
|
2019-04-30 13:33:34 +00:00
|
|
|
XRT_MAYBE_UNUSED int ret = 0;
|
|
|
|
|
|
|
|
// Free old list first.
|
|
|
|
teardown_devices(p);
|
|
|
|
|
2019-06-26 14:10:32 +00:00
|
|
|
#ifdef XRT_HAVE_LIBUDEV
|
|
|
|
ret = p_udev_probe(p);
|
|
|
|
if (ret != 0) {
|
|
|
|
P_ERROR(p, "Failed to enumerate udev devices\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-06-20 13:51:34 +00:00
|
|
|
#ifdef XRT_HAVE_LIBUSB
|
2019-04-30 13:33:34 +00:00
|
|
|
ret = p_libusb_probe(p);
|
|
|
|
if (ret != 0) {
|
|
|
|
P_ERROR(p, "Failed to enumerate libusb devices\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-06-20 13:51:34 +00:00
|
|
|
#endif
|
2019-04-30 13:33:34 +00:00
|
|
|
|
2019-06-20 14:14:09 +00:00
|
|
|
#ifdef XRT_HAVE_LIBUVC
|
2019-04-30 13:33:34 +00:00
|
|
|
ret = p_libuvc_probe(p);
|
|
|
|
if (ret != 0) {
|
|
|
|
P_ERROR(p, "Failed to enumerate libuvc devices\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-06-20 17:02:28 +00:00
|
|
|
#endif
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
dump(struct xrt_prober *xp)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober *p = (struct prober *)xp;
|
2019-04-30 13:33:34 +00:00
|
|
|
XRT_MAYBE_UNUSED ssize_t k = 0;
|
|
|
|
XRT_MAYBE_UNUSED size_t j = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < p->num_devices; i++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = &p->devices[i];
|
2019-04-30 13:33:34 +00:00
|
|
|
p_dump_device(p, pdev, (int)i);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-31 16:55:19 +00:00
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
handle_found_device(struct prober *p,
|
|
|
|
struct xrt_device **xdevs,
|
2019-05-31 16:55:19 +00:00
|
|
|
size_t num_xdevs,
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_device *xdev)
|
2019-05-31 16:55:19 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
P_DEBUG(p, "Found '%s' %p", xdev->str, (void *)xdev);
|
2019-05-31 16:55:19 +00:00
|
|
|
|
|
|
|
// For controllers we put them after the first found HMD.
|
|
|
|
if (xdev->hmd == NULL) {
|
|
|
|
for (size_t i = 1; i < num_xdevs; i++) {
|
|
|
|
if (xdevs[i] == NULL) {
|
|
|
|
xdevs[i] = xdev;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
P_ERROR(p, "Too many controller devices closing '%s'",
|
2019-09-04 11:43:57 +00:00
|
|
|
xdev->str);
|
2019-05-31 16:55:19 +00:00
|
|
|
xdev->destroy(xdev);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not found a HMD before, add it first in the list.
|
|
|
|
if (xdevs[0] == NULL) {
|
|
|
|
xdevs[0] = xdev;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-09-04 11:43:57 +00:00
|
|
|
P_ERROR(p, "Found more then one, HMD closing '%s'", xdev->str);
|
2019-05-31 16:55:19 +00:00
|
|
|
xdev->destroy(xdev);
|
|
|
|
}
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
select_device(struct xrt_prober *xp,
|
|
|
|
struct xrt_device **xdevs,
|
2019-05-31 16:55:19 +00:00
|
|
|
size_t num_xdevs)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober *p = (struct prober *)xp;
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
// Build a list of all current probed devices.
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_prober_device **dev_list =
|
|
|
|
U_TYPED_ARRAY_CALLOC(struct xrt_prober_device *, p->num_devices);
|
2019-04-30 13:33:34 +00:00
|
|
|
for (size_t i = 0; i < p->num_devices; i++) {
|
|
|
|
dev_list[i] = &p->devices[i].base;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loop over all devices and entries that might match them.
|
|
|
|
for (size_t i = 0; i < p->num_devices; i++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = &p->devices[i];
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
for (size_t k = 0; k < p->num_entries; k++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_prober_entry *entry = p->entries[k];
|
2019-04-30 13:33:34 +00:00
|
|
|
if (pdev->base.vendor_id != entry->vendor_id ||
|
|
|
|
pdev->base.product_id != entry->product_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_device
|
|
|
|
*new_xdevs[XRT_MAX_DEVICES_PER_PROBE] = {NULL};
|
2019-10-02 10:33:17 +00:00
|
|
|
int num_found = entry->found(
|
|
|
|
xp, dev_list, p->num_devices, i, &(new_xdevs[0]));
|
2019-04-30 13:33:34 +00:00
|
|
|
|
2019-06-21 23:01:27 +00:00
|
|
|
if (num_found <= 0) {
|
2019-05-31 16:55:19 +00:00
|
|
|
continue;
|
2019-04-30 13:33:34 +00:00
|
|
|
}
|
2019-06-21 23:01:27 +00:00
|
|
|
for (int created_idx = 0; created_idx < num_found;
|
|
|
|
++created_idx) {
|
|
|
|
if (new_xdevs[created_idx] == NULL) {
|
|
|
|
P_DEBUG(
|
|
|
|
p,
|
|
|
|
"Leaving device creation loop "
|
|
|
|
"early: found function reported %i "
|
|
|
|
"created, but only %i non-null",
|
|
|
|
num_found, created_idx);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
handle_found_device(p, xdevs, num_xdevs,
|
|
|
|
new_xdevs[created_idx]);
|
|
|
|
}
|
2019-04-30 13:33:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free the temporary list.
|
|
|
|
free(dev_list);
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_AUTO_PROBERS && p->auto_probers[i]; i++) {
|
2019-11-01 15:16:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have found a HMD stop checking the auto probers. This
|
|
|
|
* is mostly to stop OpenHMD and Monado fighting over devices.
|
|
|
|
*/
|
|
|
|
if (xdevs[0] != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_device *xdev =
|
2019-04-30 13:33:34 +00:00
|
|
|
p->auto_probers[i]->lelo_dallas_autoprobe(
|
2019-09-09 10:34:43 +00:00
|
|
|
p->auto_probers[i], xp);
|
2019-05-31 16:55:19 +00:00
|
|
|
if (xdev == NULL) {
|
|
|
|
continue;
|
2019-04-30 13:33:34 +00:00
|
|
|
}
|
2019-05-31 16:55:19 +00:00
|
|
|
|
|
|
|
handle_found_device(p, xdevs, num_xdevs, xdev);
|
2019-04-30 13:33:34 +00:00
|
|
|
}
|
|
|
|
|
2019-05-31 16:55:19 +00:00
|
|
|
|
|
|
|
if (xdevs[0] != NULL) {
|
2019-09-04 11:43:57 +00:00
|
|
|
P_DEBUG(p, "Found HMD! '%s'", xdevs[0]->str);
|
2019-05-31 16:55:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
P_DEBUG(p, "Didn't find any HMD devices");
|
|
|
|
|
|
|
|
// Destroy all other found devices.
|
|
|
|
for (size_t i = 1; i < num_xdevs; i++) {
|
|
|
|
if (xdevs[i] == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-09-04 11:43:57 +00:00
|
|
|
P_DEBUG(p, "Destroying '%s'", xdevs[i]->str);
|
2019-05-31 16:55:19 +00:00
|
|
|
xdevs[i]->destroy(xdevs[i]);
|
|
|
|
xdevs[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2019-04-30 13:33:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
open_hid_interface(struct xrt_prober *xp,
|
|
|
|
struct xrt_prober_device *xpdev,
|
2019-04-30 13:33:34 +00:00
|
|
|
int interface,
|
2019-09-29 10:44:00 +00:00
|
|
|
struct os_hid_device **out_hid_dev)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = (struct prober_device *)xpdev;
|
2019-04-30 13:33:34 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (size_t j = 0; j < pdev->num_hidraws; j++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_hidraw *hidraw = &pdev->hidraws[j];
|
2019-04-30 13:33:34 +00:00
|
|
|
|
|
|
|
if (hidraw->interface != interface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = os_hid_open_hidraw(hidraw->path, out_hid_dev);
|
|
|
|
if (ret != 0) {
|
2019-10-04 09:27:49 +00:00
|
|
|
P_ERROR(p, "Failed to open device '%s' got '%i'",
|
|
|
|
hidraw->path, ret);
|
2019-04-30 13:33:34 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
P_ERROR(p,
|
|
|
|
"Could not find the requested "
|
|
|
|
"hid interface (%i) on the device!",
|
|
|
|
interface);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-09-02 12:25:52 +00:00
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
open_video_device(struct xrt_prober *xp,
|
|
|
|
struct xrt_prober_device *xpdev,
|
|
|
|
struct xrt_frame_context *xfctx,
|
|
|
|
struct xrt_fs **out_xfs)
|
2019-09-02 12:25:52 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = (struct prober_device *)xpdev;
|
2019-09-02 12:25:52 +00:00
|
|
|
|
2019-11-10 01:36:34 +00:00
|
|
|
#if defined(XRT_HAVE_V4L2)
|
2019-09-02 12:25:52 +00:00
|
|
|
if (pdev->num_v4ls == 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-09-29 10:44:00 +00:00
|
|
|
struct xrt_fs *xfs = v4l2_fs_create(xfctx, pdev->v4ls[0].path);
|
2019-09-02 12:25:52 +00:00
|
|
|
if (xfs == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_xfs = xfs;
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
(void)pdev;
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:02:10 +00:00
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
list_video_devices(struct xrt_prober *xp,
|
2019-06-28 13:02:10 +00:00
|
|
|
xrt_prober_list_video_cb cb,
|
2019-09-29 10:44:00 +00:00
|
|
|
void *ptr)
|
2019-06-28 13:02:10 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober *p = (struct prober *)xp;
|
2019-06-28 13:02:10 +00:00
|
|
|
|
|
|
|
// Loop over all devices and find video devices.
|
|
|
|
for (size_t i = 0; i < p->num_devices; i++) {
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober_device *pdev = &p->devices[i];
|
2019-06-28 13:02:10 +00:00
|
|
|
|
|
|
|
bool has = false;
|
|
|
|
#ifdef XRT_HAVE_LIBUVC
|
|
|
|
has |= pdev->uvc.dev != NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef XRT_OS_LINUX
|
|
|
|
has |= pdev->num_v4ls > 0;
|
|
|
|
#endif
|
|
|
|
if (!has) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-09-02 12:25:59 +00:00
|
|
|
if (pdev->usb.product == NULL) {
|
|
|
|
fill_out_product(p, pdev);
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:02:10 +00:00
|
|
|
cb(xp, &pdev->base, pdev->usb.product, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-21 17:33:41 +00:00
|
|
|
static int
|
2019-09-29 10:44:00 +00:00
|
|
|
get_string_descriptor(struct xrt_prober *xp,
|
|
|
|
struct xrt_prober_device *xpdev,
|
2019-06-21 17:33:41 +00:00
|
|
|
enum xrt_prober_string which_string,
|
2019-09-29 10:44:00 +00:00
|
|
|
unsigned char *buffer,
|
2019-06-21 17:33:41 +00:00
|
|
|
int length)
|
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober *p = (struct prober *)xp;
|
|
|
|
struct prober_device *pdev = (struct prober_device *)xpdev;
|
2019-06-21 17:33:41 +00:00
|
|
|
int ret;
|
|
|
|
#ifdef XRT_HAVE_LIBUSB
|
|
|
|
if (pdev->usb.dev != NULL) {
|
|
|
|
ret = p_libusb_get_string_descriptor(p, pdev, which_string,
|
|
|
|
buffer, length);
|
|
|
|
if (ret >= 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//! @todo add more backends
|
|
|
|
//! @todo make this unicode (utf-16)? utf-8 would be better...
|
|
|
|
return 0;
|
|
|
|
}
|
2019-09-02 12:25:59 +00:00
|
|
|
|
2019-10-05 09:22:26 +00:00
|
|
|
static bool
|
|
|
|
can_open(struct xrt_prober *xp, struct xrt_prober_device *xpdev)
|
|
|
|
{
|
|
|
|
struct prober *p = (struct prober *)xp;
|
|
|
|
struct prober_device *pdev = (struct prober_device *)xpdev;
|
|
|
|
#ifdef XRT_HAVE_LIBUSB
|
|
|
|
if (pdev->usb.dev != NULL) {
|
|
|
|
return p_libusb_can_open(p, pdev);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//! @todo add more backends
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-30 13:33:34 +00:00
|
|
|
static void
|
2019-09-29 10:44:00 +00:00
|
|
|
destroy(struct xrt_prober **xp)
|
2019-04-30 13:33:34 +00:00
|
|
|
{
|
2019-09-29 10:44:00 +00:00
|
|
|
struct prober *p = (struct prober *)*xp;
|
2019-04-30 13:33:34 +00:00
|
|
|
if (p == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
teardown(p);
|
|
|
|
free(p);
|
|
|
|
|
|
|
|
*xp = NULL;
|
|
|
|
}
|