mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-29 11:06:18 +00:00
xrt: Add new prober interface and code
This commit is contained in:
parent
e2bd986bc5
commit
d97df04c11
|
@ -9,13 +9,141 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "xrt/xrt_config.h"
|
||||
#include "xrt/xrt_device.h"
|
||||
#include "os/os_hid.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Prober and device manager.
|
||||
*
|
||||
*/
|
||||
|
||||
struct xrt_prober;
|
||||
struct xrt_prober_device;
|
||||
|
||||
/*!
|
||||
* Entry for a single device.
|
||||
*
|
||||
* @ingroup xrt_iface
|
||||
*/
|
||||
struct xrt_prober_entry
|
||||
{
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
|
||||
int (*found)(struct xrt_prober *xp,
|
||||
struct xrt_prober_device **devices,
|
||||
size_t index,
|
||||
struct xrt_device **out_xdev);
|
||||
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Function for creating a auto prober.
|
||||
*
|
||||
* @ingroup xrt_iface
|
||||
*/
|
||||
typedef struct xrt_auto_prober *(*xrt_auto_prober_creator)();
|
||||
|
||||
/*!
|
||||
* Main root of all of the probing device.
|
||||
*
|
||||
* @ingroup xrt_iface
|
||||
*/
|
||||
struct xrt_prober_entry_lists
|
||||
{
|
||||
/*!
|
||||
* A a null terminated list of null terminated lists of
|
||||
* @ref xrt_prober_entry.
|
||||
*/
|
||||
struct xrt_prober_entry **entries;
|
||||
|
||||
/*!
|
||||
* A null terminated list of @ref xrt_auto_prober creation functions.
|
||||
*/
|
||||
xrt_auto_prober_creator *auto_probers;
|
||||
|
||||
/*!
|
||||
* Allows you to chain multiple prober entry lists.
|
||||
*/
|
||||
struct xrt_prober_entry_lists *next;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Bus type of a device.
|
||||
*/
|
||||
enum xrt_bus_type
|
||||
{
|
||||
XRT_BUS_TYPE_UNKNOWN,
|
||||
XRT_BUS_TYPE_USB,
|
||||
XRT_BUS_TYPE_BLUETOOTH,
|
||||
};
|
||||
|
||||
/*!
|
||||
* A probed device, may or may not be opened.
|
||||
*
|
||||
* @ingroup xrt_iface
|
||||
*/
|
||||
struct xrt_prober_device
|
||||
{
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
|
||||
enum xrt_bus_type bus;
|
||||
|
||||
bool opened;
|
||||
};
|
||||
|
||||
/*!
|
||||
* The main prober that probes and manages found but not opened HMD devices
|
||||
* that are connected to the system.
|
||||
*
|
||||
* @ingroup xrt_iface
|
||||
*/
|
||||
struct xrt_prober
|
||||
{
|
||||
int (*probe)(struct xrt_prober *xp);
|
||||
int (*dump)(struct xrt_prober *xp);
|
||||
int (*select)(struct xrt_prober *xp, struct xrt_device **out_xdev);
|
||||
int (*open_hid_interface)(struct xrt_prober *xp,
|
||||
struct xrt_prober_device *xpdev,
|
||||
int interface,
|
||||
struct os_hid_device **out_hid_dev);
|
||||
void (*destroy)(struct xrt_prober **xp);
|
||||
};
|
||||
|
||||
/*!
|
||||
* Call this function to create the @ref xrt_prober. This function is setup in
|
||||
* the the very small target wrapper.c for each binary.
|
||||
*
|
||||
* @ingroup xrt_iface
|
||||
*/
|
||||
int
|
||||
xrt_prober_create(struct xrt_prober **out_prober);
|
||||
|
||||
/*!
|
||||
* Used by the target binary to create the prober with a list of drivers.
|
||||
*
|
||||
* @ingroup xrt_iface
|
||||
*/
|
||||
int
|
||||
xrt_prober_create_with_lists(struct xrt_prober **out_prober,
|
||||
struct xrt_prober_entry_lists *list);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Auto prober.
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* A simple prober to probe for a HMD device connected to the system.
|
||||
*
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
add_subdirectory(oxr)
|
||||
add_subdirectory(prober)
|
||||
|
|
30
src/xrt/state_trackers/prober/CMakeLists.txt
Normal file
30
src/xrt/state_trackers/prober/CMakeLists.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Copyright 2019, Collabora, Ltd.
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../auxiliary
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../external
|
||||
)
|
||||
|
||||
set(PROBER_SOURCE_FILES
|
||||
p_auto_wrap.c
|
||||
p_documentation.h
|
||||
p_dump.c
|
||||
p_prober.c
|
||||
p_prober.h
|
||||
p_udev.c
|
||||
)
|
||||
|
||||
# Use OBJECT to not create a archive, since it just gets in the way.
|
||||
add_library(st_prober OBJECT ${PROBER_SOURCE_FILES})
|
||||
|
||||
target_include_directories(st_prober
|
||||
PRIVATE
|
||||
${LIBUSB_INCLUDES}
|
||||
${LIBUVC_INCLUDES}
|
||||
${FFMPEG_INCLUDES}
|
||||
${OPENCV_INCLUDES}
|
||||
)
|
||||
|
||||
set_property(TARGET st_prober PROPERTY POSITION_INDEPENDENT_CODE ON)
|
106
src/xrt/state_trackers/prober/p_auto_wrap.c
Normal file
106
src/xrt/state_trackers/prober/p_auto_wrap.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Export a auto prober interface.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup st_prober
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_compiler.h"
|
||||
#include "xrt/xrt_prober.h"
|
||||
#include "util/u_misc.h"
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Structs and helprs.
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Simple wrapper exposing the old interface.
|
||||
*
|
||||
* @ingroup st_prober
|
||||
*/
|
||||
struct prober_wrapper
|
||||
{
|
||||
struct xrt_auto_prober base;
|
||||
struct xrt_prober *xp;
|
||||
};
|
||||
|
||||
static inline struct prober_wrapper *
|
||||
prober_wrapper(struct xrt_auto_prober *xap)
|
||||
{
|
||||
return (struct prober_wrapper *)xap;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Member functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static struct xrt_device *
|
||||
auto_probe(struct xrt_auto_prober *xap)
|
||||
{
|
||||
struct prober_wrapper *pw = prober_wrapper(xap);
|
||||
struct xrt_device *xdev = NULL;
|
||||
int ret;
|
||||
|
||||
ret = pw->xp->probe(pw->xp);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = pw->xp->select(pw->xp, &xdev);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return xdev;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(struct xrt_auto_prober *xap)
|
||||
{
|
||||
struct prober_wrapper *pw = prober_wrapper(xap);
|
||||
|
||||
if (pw->xp != NULL) {
|
||||
pw->xp->destroy(&pw->xp);
|
||||
}
|
||||
|
||||
free(pw);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Exported function(s).
|
||||
*
|
||||
*/
|
||||
|
||||
struct xrt_auto_prober *
|
||||
xrt_auto_prober_create()
|
||||
{
|
||||
struct prober_wrapper *pw = U_TYPED_CALLOC(struct prober_wrapper);
|
||||
struct xrt_prober *xp = NULL;
|
||||
int ret;
|
||||
|
||||
if (pw == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = xrt_prober_create(&xp);
|
||||
if (ret < 0) {
|
||||
free(pw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pw->base.lelo_dallas_autoprobe = auto_probe;
|
||||
pw->base.destroy = destroy;
|
||||
pw->xp = xp;
|
||||
|
||||
return &pw->base;
|
||||
}
|
19
src/xrt/state_trackers/prober/p_documentation.h
Normal file
19
src/xrt/state_trackers/prober/p_documentation.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Documentation.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup st_prober
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
/*!
|
||||
* @defgroup st_prober Prober and device managment code
|
||||
*
|
||||
* Probing code.
|
||||
*
|
||||
* @ingroup xrt
|
||||
*/
|
136
src/xrt/state_trackers/prober/p_dump.c
Normal file
136
src/xrt/state_trackers/prober/p_dump.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Prober code to dump information.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup st_prober
|
||||
*/
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "p_prober.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
static int
|
||||
print_ports(char* tmp, size_t size, uint8_t* ports, int num)
|
||||
{
|
||||
switch (num) {
|
||||
case 1: {
|
||||
snprintf(tmp, size, "%i", ports[0]);
|
||||
return 1;
|
||||
}
|
||||
case 2: {
|
||||
snprintf(tmp, size, "%i.%i", ports[0], ports[1]);
|
||||
return 1;
|
||||
}
|
||||
case 3: {
|
||||
snprintf(tmp, size, "%i.%i.%i", ports[0], ports[1], ports[2]);
|
||||
return 1;
|
||||
}
|
||||
case 4: {
|
||||
snprintf(tmp, size, "%i.%i.%i.%i", ports[0], ports[1], ports[2],
|
||||
ports[3]);
|
||||
return 1;
|
||||
}
|
||||
case 5: {
|
||||
snprintf(tmp, size, "%i.%i.%i.%i.%i", ports[0], ports[1],
|
||||
ports[2], ports[3], ports[4]);
|
||||
return 1;
|
||||
}
|
||||
case 6: {
|
||||
snprintf(tmp, size, "%i.%i.%i.%i.%i.%i", ports[0], ports[1],
|
||||
ports[2], ports[3], ports[4], ports[5]);
|
||||
return 1;
|
||||
}
|
||||
case 7: {
|
||||
snprintf(tmp, size, "%i.%i.%i.%i.%i.%i.%i", ports[0], ports[1],
|
||||
ports[2], ports[3], ports[4], ports[5], ports[6]);
|
||||
return 1;
|
||||
}
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* "Exported" functions.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
p_dump_device(struct prober* p, struct prober_device* pdev, int id)
|
||||
{
|
||||
if (pdev->usb.bus != 0 && pdev->usb.addr == 0 &&
|
||||
pdev->base.vendor_id != 0 && pdev->base.product_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\t% 3i: 0x%04x:0x%04x\n", id, pdev->base.vendor_id,
|
||||
pdev->base.product_id);
|
||||
printf("\t\tptr: %p\n", (void*)pdev);
|
||||
|
||||
if (pdev->usb.bus != 0 || pdev->usb.addr != 0) {
|
||||
printf("\t\tusb.bus: %i\n", pdev->usb.bus);
|
||||
printf("\t\tusb.addr: %i\n", pdev->usb.addr);
|
||||
}
|
||||
|
||||
if (pdev->bluetooth.id != 0) {
|
||||
printf("\t\tbluetooth.id: %012" PRIx64 "\n",
|
||||
pdev->bluetooth.id);
|
||||
}
|
||||
|
||||
libusb_device* usb_dev = pdev->usb.dev;
|
||||
if (usb_dev != NULL) {
|
||||
uint8_t ports[8];
|
||||
char tmp[1024];
|
||||
|
||||
printf("\t\tlibusb: %p\n", (void*)usb_dev);
|
||||
|
||||
int num =
|
||||
libusb_get_port_numbers(usb_dev, ports, ARRAY_SIZE(ports));
|
||||
|
||||
if (print_ports(tmp, ARRAY_SIZE(tmp), ports, num)) {
|
||||
printf("\t\tport%s %s\n", num > 1 ? "s:" : ": ",
|
||||
tmp);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < pdev->num_hidraws; j++) {
|
||||
struct prober_hidraw* hidraw = &pdev->hidraws[j];
|
||||
|
||||
printf("\t\tinterface: %u\n", (int)hidraw->interface);
|
||||
printf("\t\tpath: '%s'\n", hidraw->path);
|
||||
}
|
||||
|
||||
#ifdef XRT_HAVE_LIBUVC
|
||||
uvc_device_t* uvc_dev = pdev->uvc.dev;
|
||||
if (uvc_dev != NULL) {
|
||||
struct uvc_device_descriptor* desc;
|
||||
|
||||
printf("\t\tlibuvc: %p\n", (void*)uvc_dev);
|
||||
|
||||
uvc_get_device_descriptor(uvc_dev, &desc);
|
||||
|
||||
if (desc->product != NULL) {
|
||||
|
||||
printf("\t\tproduct: '%s'\n", desc->product);
|
||||
}
|
||||
if (desc->manufacturer != NULL) {
|
||||
|
||||
printf("\t\tmanufacturer: '%s'\n", desc->manufacturer);
|
||||
}
|
||||
if (desc->serialNumber != NULL) {
|
||||
|
||||
printf("\t\tserial: '%s'\n", desc->serialNumber);
|
||||
}
|
||||
|
||||
uvc_free_device_descriptor(desc);
|
||||
desc = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
584
src/xrt/state_trackers/prober/p_prober.c
Normal file
584
src/xrt/state_trackers/prober/p_prober.c
Normal file
|
@ -0,0 +1,584 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Main prober code.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup st_prober
|
||||
*/
|
||||
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_misc.h"
|
||||
#include "p_prober.h"
|
||||
|
||||
#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
|
||||
add_device(struct prober* p, struct prober_device** out_dev);
|
||||
|
||||
static int
|
||||
initialize(struct prober* p, struct xrt_prober_entry_lists* lists);
|
||||
|
||||
static void
|
||||
teardown_devices(struct prober* p);
|
||||
|
||||
static void
|
||||
teardown(struct prober* p);
|
||||
|
||||
static int
|
||||
probe(struct xrt_prober* xp);
|
||||
|
||||
static int
|
||||
dump(struct xrt_prober* xp);
|
||||
|
||||
static int
|
||||
select_device(struct xrt_prober* xp, struct xrt_device** out_xdev);
|
||||
|
||||
static int
|
||||
open_hid_interface(struct xrt_prober* xp,
|
||||
struct xrt_prober_device* xpdev,
|
||||
int interface,
|
||||
struct os_hid_device** out_hid_dev);
|
||||
|
||||
static void
|
||||
destroy(struct xrt_prober** xp);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* "Exported" functions.
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
xrt_prober_create_with_lists(struct xrt_prober** out_xp,
|
||||
struct xrt_prober_entry_lists* lists)
|
||||
{
|
||||
struct prober* p = U_TYPED_CALLOC(struct prober);
|
||||
|
||||
int ret = initialize(p, lists);
|
||||
if (ret != 0) {
|
||||
free(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*out_xp = &p->base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
p_dev_get_usb_dev(struct prober* p,
|
||||
uint16_t bus,
|
||||
uint16_t addr,
|
||||
uint16_t vendor_id,
|
||||
uint16_t product_id,
|
||||
struct prober_device** out_pdev)
|
||||
{
|
||||
struct prober_device* pdev;
|
||||
|
||||
for (size_t i = 0; i < p->num_devices; i++) {
|
||||
struct prober_device* pdev = &p->devices[i];
|
||||
|
||||
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
|
||||
p_dev_get_bluetooth_dev(struct prober* p,
|
||||
uint64_t id,
|
||||
uint16_t vendor_id,
|
||||
uint16_t product_id,
|
||||
struct prober_device** out_pdev)
|
||||
{
|
||||
struct prober_device* pdev;
|
||||
|
||||
for (size_t i = 0; i < p->num_devices; i++) {
|
||||
struct prober_device* pdev = &p->devices[i];
|
||||
|
||||
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.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
add_device(struct prober* p, struct prober_device** out_dev)
|
||||
{
|
||||
size_t new_size = (p->num_devices + 1) * sizeof(struct prober_device);
|
||||
p->devices = realloc(p->devices, new_size);
|
||||
|
||||
struct prober_device* dev = &p->devices[p->num_devices++];
|
||||
memset(dev, 0, sizeof(struct prober_device));
|
||||
|
||||
*out_dev = dev;
|
||||
}
|
||||
|
||||
static void
|
||||
add_usb_entry(struct prober* p, struct xrt_prober_entry* entry)
|
||||
{
|
||||
size_t new_size =
|
||||
(p->num_entries + 1) * sizeof(struct xrt_prober_entry_usb*);
|
||||
p->entries = realloc(p->entries, new_size);
|
||||
p->entries[p->num_entries++] = entry;
|
||||
}
|
||||
|
||||
static int
|
||||
collect_entries(struct prober* p)
|
||||
{
|
||||
struct xrt_prober_entry_lists* lists = p->lists;
|
||||
while (lists) {
|
||||
for (size_t j = 0; lists->entries != NULL && lists->entries[j];
|
||||
j++) {
|
||||
struct xrt_prober_entry* entry = lists->entries[j];
|
||||
for (size_t k = 0; entry[k].found != NULL; k++) {
|
||||
add_usb_entry(p, &entry[k]);
|
||||
}
|
||||
}
|
||||
|
||||
lists = lists->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
initialize(struct prober* p, struct xrt_prober_entry_lists* lists)
|
||||
{
|
||||
p->base.probe = probe;
|
||||
p->base.dump = dump;
|
||||
p->base.select = select_device;
|
||||
p->base.open_hid_interface = open_hid_interface;
|
||||
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();
|
||||
|
||||
int ret;
|
||||
|
||||
ret = collect_entries(p);
|
||||
if (ret != 0) {
|
||||
teardown(p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = libusb_init(&p->usb.ctx);
|
||||
if (ret != 0) {
|
||||
teardown(p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef XRT_HAVE_LIBUVC
|
||||
ret = uvc_init(&p->uvc.ctx, p->usb.ctx);
|
||||
if (ret != 0) {
|
||||
teardown(p);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < MAX_AUTO_PROBERS && lists->auto_probers[i]; i++) {
|
||||
p->auto_probers[i] = lists->auto_probers[i]();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
teardown_devices(struct prober* p)
|
||||
{
|
||||
// for (size_t i; i)
|
||||
// Need to free all devices.
|
||||
for (size_t i = 0; i < p->num_devices; i++) {
|
||||
struct prober_device* pdev = &p->devices[i];
|
||||
|
||||
for (size_t j = 0; j < pdev->num_hidraws; j++) {
|
||||
struct prober_hidraw* hidraw = &pdev->hidraws[j];
|
||||
free((char*)hidraw->path);
|
||||
hidraw->path = NULL;
|
||||
}
|
||||
|
||||
if (pdev->hidraws != NULL) {
|
||||
free(pdev->hidraws);
|
||||
pdev->hidraws = NULL;
|
||||
pdev->num_hidraws = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->devices != NULL) {
|
||||
free(p->devices);
|
||||
p->devices = NULL;
|
||||
p->num_devices = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
teardown(struct prober* p)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// Free all libuvc resources.
|
||||
if (p->uvc.list != NULL) {
|
||||
uvc_free_device_list(p->uvc.list, 1);
|
||||
p->uvc.list = NULL;
|
||||
}
|
||||
|
||||
if (p->uvc.ctx != NULL) {
|
||||
uvc_exit(p->uvc.ctx);
|
||||
p->uvc.ctx = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Free all libusb resources.
|
||||
if (p->usb.list != NULL) {
|
||||
libusb_free_device_list(p->usb.list, 1);
|
||||
p->usb.list = NULL;
|
||||
}
|
||||
|
||||
if (p->usb.ctx != NULL) {
|
||||
libusb_exit(p->usb.ctx);
|
||||
p->usb.ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
p_libusb_probe(struct prober* p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// Free old list first.
|
||||
if (p->usb.list != NULL) {
|
||||
libusb_free_device_list(p->usb.list, 1);
|
||||
p->usb.list = NULL;
|
||||
}
|
||||
|
||||
// Probe for USB devices.
|
||||
p->usb.count = libusb_get_device_list(p->usb.ctx, &p->usb.list);
|
||||
if (p->usb.count < 0) {
|
||||
P_ERROR(p, "\tFailed to enumerate usb devices\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ssize_t i = 0; i < p->usb.count; i++) {
|
||||
libusb_device* device = p->usb.list[i];
|
||||
struct libusb_device_descriptor desc;
|
||||
struct prober_device* pdev = NULL;
|
||||
|
||||
libusb_get_device_descriptor(device, &desc);
|
||||
uint8_t bus = libusb_get_bus_number(device);
|
||||
uint8_t addr = libusb_get_device_address(device);
|
||||
uint16_t vendor = desc.idVendor;
|
||||
uint16_t product = desc.idProduct;
|
||||
|
||||
ret = p_dev_get_usb_dev(p, bus, addr, vendor, product, &pdev);
|
||||
|
||||
P_SPEW(p,
|
||||
"libusb\n"
|
||||
"\t\tptr: %p (%i)\n"
|
||||
"\t\tvendor_id: %04x\n"
|
||||
"\t\tproduct_id: %04x\n"
|
||||
"\t\tbus: %i\n"
|
||||
"\t\taddr: %i",
|
||||
(void*)pdev, ret, vendor, product, bus, addr);
|
||||
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "p_dev_get_usb_device failed!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attach the libusb device to it.
|
||||
pdev->usb.dev = device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
p_libuvc_probe(struct prober* p)
|
||||
{
|
||||
#ifdef XRT_HAVE_LIBUVC
|
||||
int ret;
|
||||
|
||||
// Free old list first.
|
||||
if (p->uvc.list != NULL) {
|
||||
uvc_free_device_list(p->uvc.list, 1);
|
||||
p->uvc.list = NULL;
|
||||
}
|
||||
|
||||
ret = uvc_get_device_list(p->uvc.ctx, &p->uvc.list);
|
||||
if (ret < 0) {
|
||||
P_ERROR(p, "\tFailed to enumerate uvc devices\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Count the number of UVC devices.
|
||||
while (p->uvc.list != NULL && p->uvc.list[p->uvc.count] != NULL) {
|
||||
p->uvc.count++;
|
||||
}
|
||||
|
||||
for (ssize_t k = 0; k < p->uvc.count; k++) {
|
||||
uvc_device_t* device = p->uvc.list[k];
|
||||
struct uvc_device_descriptor* desc;
|
||||
struct prober_device* pdev = NULL;
|
||||
|
||||
uvc_get_device_descriptor(device, &desc);
|
||||
uint8_t bus = uvc_get_bus_number(device);
|
||||
uint8_t addr = uvc_get_device_address(device);
|
||||
uint16_t vendor = desc->idVendor;
|
||||
uint16_t product = desc->idProduct;
|
||||
uvc_free_device_descriptor(desc);
|
||||
|
||||
ret = p_dev_get_usb_dev(p, bus, addr, vendor, product, &pdev);
|
||||
|
||||
P_SPEW(p,
|
||||
"libuvc\n"
|
||||
"\t\tptr: %p (%i)\n"
|
||||
"\t\tvendor_id: %04x\n"
|
||||
"\t\tproduct_id: %04x\n"
|
||||
"\t\tbus: %i\n"
|
||||
"\t\taddr: %i",
|
||||
(void*)pdev, ret, vendor, product, bus, addr);
|
||||
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "p_dev_get_usb_device failed!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attach the libuvc device to it.
|
||||
pdev->uvc.dev = p->uvc.list[k];
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Member functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
probe(struct xrt_prober* xp)
|
||||
{
|
||||
struct prober* p = (struct prober*)xp;
|
||||
XRT_MAYBE_UNUSED int ret = 0;
|
||||
|
||||
// Free old list first.
|
||||
teardown_devices(p);
|
||||
|
||||
ret = p_libusb_probe(p);
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "Failed to enumerate libusb devices\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = p_libuvc_probe(p);
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "Failed to enumerate libuvc devices\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = p_udev_probe(p);
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "Failed to enumerate udev devices\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dump(struct xrt_prober* xp)
|
||||
{
|
||||
struct prober* p = (struct prober*)xp;
|
||||
XRT_MAYBE_UNUSED ssize_t k = 0;
|
||||
XRT_MAYBE_UNUSED size_t j = 0;
|
||||
|
||||
for (size_t i = 0; i < p->num_devices; i++) {
|
||||
struct prober_device* pdev = &p->devices[i];
|
||||
p_dump_device(p, pdev, (int)i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
select_device(struct xrt_prober* xp, struct xrt_device** out_xdev)
|
||||
{
|
||||
struct xrt_device* xdev = NULL;
|
||||
struct prober* p = (struct prober*)xp;
|
||||
|
||||
// Build a list of all current probed devices.
|
||||
struct xrt_prober_device** dev_list =
|
||||
U_TYPED_ARRAY_CALLOC(struct xrt_prober_device*, p->num_devices);
|
||||
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++) {
|
||||
struct prober_device* pdev = &p->devices[i];
|
||||
|
||||
for (size_t k = 0; k < p->num_entries; k++) {
|
||||
struct xrt_prober_entry* entry = p->entries[k];
|
||||
if (pdev->base.vendor_id != entry->vendor_id ||
|
||||
pdev->base.product_id != entry->product_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entry->found(xp, dev_list, i, &xdev);
|
||||
|
||||
if (xdev != NULL) {
|
||||
free(dev_list);
|
||||
*out_xdev = xdev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free the temporary list.
|
||||
free(dev_list);
|
||||
|
||||
for (int i = 0; i < MAX_AUTO_PROBERS && p->auto_probers[i]; i++) {
|
||||
struct xrt_device* ret =
|
||||
p->auto_probers[i]->lelo_dallas_autoprobe(
|
||||
p->auto_probers[i]);
|
||||
if (ret) {
|
||||
*out_xdev = ret;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
open_hid_interface(struct xrt_prober* xp,
|
||||
struct xrt_prober_device* xpdev,
|
||||
int interface,
|
||||
struct os_hid_device** out_hid_dev)
|
||||
{
|
||||
struct prober_device* pdev = (struct prober_device*)xpdev;
|
||||
int ret;
|
||||
|
||||
for (size_t j = 0; j < pdev->num_hidraws; j++) {
|
||||
struct prober_hidraw* hidraw = &pdev->hidraws[j];
|
||||
|
||||
if (hidraw->interface != interface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = os_hid_open_hidraw(hidraw->path, out_hid_dev);
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "Failed to open device!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
P_ERROR(p,
|
||||
"Could not find the requested "
|
||||
"hid interface (%i) on the device!",
|
||||
interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(struct xrt_prober** xp)
|
||||
{
|
||||
struct prober* p = (struct prober*)*xp;
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
teardown(p);
|
||||
free(p);
|
||||
|
||||
*xp = NULL;
|
||||
}
|
179
src/xrt/state_trackers/prober/p_prober.h
Normal file
179
src/xrt/state_trackers/prober/p_prober.h
Normal file
|
@ -0,0 +1,179 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Main prober code.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup st_prober
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xrt/xrt_compiler.h"
|
||||
#include "xrt/xrt_prober.h"
|
||||
|
||||
#ifdef XRT_HAVE_LIBUSB
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#endif
|
||||
|
||||
#ifdef XRT_HAVE_LIBUVC
|
||||
#include <libuvc/libuvc.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Struct and defines
|
||||
*
|
||||
*/
|
||||
|
||||
#define P_SPEW(p, ...) \
|
||||
do { \
|
||||
if (p->print_spew) { \
|
||||
fprintf(stderr, "%s - ", __func__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define P_DEBUG(p, ...) \
|
||||
do { \
|
||||
if (p->print_debug) { \
|
||||
fprintf(stderr, "%s - ", __func__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define P_ERROR(p, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "%s - ", __func__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (false)
|
||||
|
||||
#define MAX_AUTO_PROBERS 8
|
||||
|
||||
|
||||
/*!
|
||||
* A hidraw interface that a @ref prober_device exposes.
|
||||
*/
|
||||
struct prober_hidraw
|
||||
{
|
||||
ssize_t interface;
|
||||
const char* path;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A prober device.
|
||||
*/
|
||||
struct prober_device
|
||||
{
|
||||
struct xrt_prober_device base;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t bus;
|
||||
uint16_t addr;
|
||||
|
||||
#ifdef XRT_HAVE_LIBUSB
|
||||
libusb_device* dev;
|
||||
#endif
|
||||
} usb;
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t id;
|
||||
} bluetooth;
|
||||
|
||||
#ifdef XRT_HAVE_LIBUVC
|
||||
struct
|
||||
{
|
||||
uvc_device_t* dev;
|
||||
} uvc;
|
||||
#endif
|
||||
|
||||
#ifdef XRT_OS_LINUX
|
||||
struct
|
||||
{
|
||||
const char** paths;
|
||||
} v4l;
|
||||
#endif
|
||||
|
||||
size_t num_hidraws;
|
||||
struct prober_hidraw* hidraws;
|
||||
};
|
||||
|
||||
struct prober
|
||||
{
|
||||
struct xrt_prober base;
|
||||
|
||||
struct xrt_prober_entry_lists* lists;
|
||||
|
||||
struct
|
||||
{
|
||||
libusb_context* ctx;
|
||||
libusb_device** list;
|
||||
ssize_t count;
|
||||
} usb;
|
||||
|
||||
#ifdef XRT_HAVE_LIBUVC
|
||||
struct
|
||||
{
|
||||
uvc_context_t* ctx;
|
||||
uvc_device_t** list;
|
||||
ssize_t count;
|
||||
} uvc;
|
||||
#endif
|
||||
|
||||
struct xrt_auto_prober* auto_probers[MAX_AUTO_PROBERS];
|
||||
|
||||
size_t num_devices;
|
||||
struct prober_device* devices;
|
||||
|
||||
size_t num_entries;
|
||||
struct xrt_prober_entry** entries;
|
||||
|
||||
bool print_debug;
|
||||
bool print_spew;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Functions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Dump the given device to stdout.
|
||||
*/
|
||||
void
|
||||
p_dump_device(struct prober* p, struct prober_device* pdev, int id);
|
||||
|
||||
/*!
|
||||
* Get or create a @ref prober_device from the device.
|
||||
*/
|
||||
int
|
||||
p_dev_get_usb_dev(struct prober* p,
|
||||
uint16_t bus,
|
||||
uint16_t addr,
|
||||
uint16_t vendor_id,
|
||||
uint16_t product_id,
|
||||
struct prober_device** out_pdev);
|
||||
|
||||
/*!
|
||||
* Get or create a @ref prober_device from the device.
|
||||
*/
|
||||
int
|
||||
p_dev_get_bluetooth_dev(struct prober* p,
|
||||
uint64_t id,
|
||||
uint16_t vendor_id,
|
||||
uint16_t product_id,
|
||||
struct prober_device** out_pdev);
|
||||
|
||||
|
||||
#ifdef XRT_HAVE_LIBUDEV
|
||||
int
|
||||
p_udev_probe(struct prober* p);
|
||||
#endif
|
345
src/xrt/state_trackers/prober/p_udev.c
Normal file
345
src/xrt/state_trackers/prober/p_udev.c
Normal file
|
@ -0,0 +1,345 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Prober code interfacing to libudev.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup st_prober
|
||||
*/
|
||||
|
||||
#ifdef XRT_HAVE_LIBUDEV
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "p_prober.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libudev.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/hidraw.h>
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Defines
|
||||
*
|
||||
*/
|
||||
|
||||
#define HIDRAW_BUS_USB 3
|
||||
#define HIDRAW_BUS_BLUETOOTH 5
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Pre-declare functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
p_udev_add_interface(struct prober_device* pdev,
|
||||
uint32_t interface,
|
||||
const char* path);
|
||||
|
||||
static int
|
||||
p_udev_get_interface_number(struct udev_device* raw_dev,
|
||||
uint16_t* interface_number);
|
||||
|
||||
static int
|
||||
p_udev_get_and_parse_uevent(struct udev_device* raw_dev,
|
||||
uint32_t* out_bus_type,
|
||||
uint16_t* out_vendor_id,
|
||||
uint16_t* out_product_id,
|
||||
uint64_t* out_bluetooth_serial);
|
||||
|
||||
static int
|
||||
p_udev_get_usb_address(struct udev_device* raw_dev,
|
||||
uint32_t bus_type,
|
||||
uint16_t* usb_bus,
|
||||
uint16_t* usb_addr);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* "Exported" functions.
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
p_udev_probe(struct prober* p)
|
||||
{
|
||||
struct prober_device* pdev;
|
||||
struct udev* udev;
|
||||
struct udev_enumerate* enumerate;
|
||||
struct udev_list_entry *devices, *dev_list_entry;
|
||||
struct udev_device* raw_dev = NULL;
|
||||
uint16_t vendor_id, product_id, interface;
|
||||
uint16_t usb_bus = 0;
|
||||
uint16_t usb_addr = 0;
|
||||
uint32_t bus_type;
|
||||
uint64_t bluetooth_id;
|
||||
int ret;
|
||||
|
||||
const char* sysfs_path;
|
||||
const char* dev_path;
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
P_ERROR(p, "Can't create udev\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
udev_enumerate_add_match_subsystem(enumerate, "hidraw");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
|
||||
udev_list_entry_foreach(dev_list_entry, devices)
|
||||
{
|
||||
// Where in the sysfs is.
|
||||
sysfs_path = udev_list_entry_get_name(dev_list_entry);
|
||||
// Raw sysfs node.
|
||||
raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
|
||||
// The thing we will open.
|
||||
dev_path = udev_device_get_devnode(raw_dev);
|
||||
|
||||
// Bus type, vendor_id and product_id.
|
||||
ret = p_udev_get_and_parse_uevent(
|
||||
raw_dev, &bus_type, &vendor_id, &product_id, &bluetooth_id);
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "Failed to get uevent info from device");
|
||||
goto next;
|
||||
}
|
||||
|
||||
// HID interface.
|
||||
ret = p_udev_get_interface_number(raw_dev, &interface);
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "Failed to get interface number.");
|
||||
goto next;
|
||||
}
|
||||
|
||||
// Get USB bus and address to de-dublicate devices.
|
||||
ret = p_udev_get_usb_address(raw_dev, bus_type, &usb_bus,
|
||||
&usb_addr);
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "Failed to get USB bus and addr.");
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (bus_type == HIDRAW_BUS_BLUETOOTH) {
|
||||
ret = p_dev_get_bluetooth_dev(
|
||||
p, bluetooth_id, vendor_id, product_id, &pdev);
|
||||
} else if (bus_type == HIDRAW_BUS_USB) {
|
||||
ret = p_dev_get_usb_dev(p, usb_bus, usb_addr, vendor_id,
|
||||
product_id, &pdev);
|
||||
} else {
|
||||
// Right now only support USB & Bluetooth devices.
|
||||
P_ERROR(p,
|
||||
"Ignoring none USB or Bluetooth hidraw device "
|
||||
"'%u'.",
|
||||
bus_type);
|
||||
goto next;
|
||||
}
|
||||
|
||||
P_SPEW(p,
|
||||
"hidraw\n"
|
||||
"\t\tptr: %p (%i)\n"
|
||||
"\t\tsysfs_path: '%s'\n"
|
||||
"\t\tdev_path: '%s'\n"
|
||||
"\t\tbus_type: %i\n"
|
||||
"\t\tvender_id: %04x\n"
|
||||
"\t\tproduct_id: %04x\n"
|
||||
"\t\tinterface: %i\n"
|
||||
"\t\tusb_bus: %i\n"
|
||||
"\t\tusb_addr: %i\n"
|
||||
"\t\tbluetooth_id: %012" PRIx64,
|
||||
(void*)pdev, ret, sysfs_path, dev_path, bus_type,
|
||||
vendor_id, product_id, interface, usb_bus, usb_addr,
|
||||
bluetooth_id);
|
||||
|
||||
if (ret != 0) {
|
||||
P_ERROR(p, "p_dev_get_usb_device failed!");
|
||||
goto next;
|
||||
}
|
||||
|
||||
// Add this interface to the usb device.
|
||||
p_udev_add_interface(pdev, interface, dev_path);
|
||||
|
||||
next:
|
||||
udev_device_unref(raw_dev);
|
||||
}
|
||||
|
||||
enumerate = udev_enumerate_unref(enumerate);
|
||||
udev = udev_unref(udev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Internal functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
p_udev_add_interface(struct prober_device* pdev,
|
||||
uint32_t interface,
|
||||
const char* path)
|
||||
{
|
||||
size_t new_size =
|
||||
(pdev->num_hidraws + 1) * sizeof(struct prober_hidraw);
|
||||
pdev->hidraws = realloc(pdev->hidraws, new_size);
|
||||
|
||||
struct prober_hidraw* hidraw = &pdev->hidraws[pdev->num_hidraws++];
|
||||
memset(hidraw, 0, sizeof(struct prober_hidraw));
|
||||
|
||||
hidraw->interface = interface;
|
||||
hidraw->path = strdup(path);
|
||||
}
|
||||
|
||||
static int
|
||||
p_udev_get_usb_address(struct udev_device* raw_dev,
|
||||
uint32_t bus_type,
|
||||
uint16_t* usb_bus,
|
||||
uint16_t* usb_addr)
|
||||
{
|
||||
struct udev_device* usb_dev;
|
||||
const char* bus_str;
|
||||
const char* addr_str;
|
||||
|
||||
|
||||
if (bus_type != HIDRAW_BUS_USB) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the first USB device parent.
|
||||
// No we should not unref intf_dev, valgrind agrees.
|
||||
usb_dev = udev_device_get_parent_with_subsystem_devtype(raw_dev, "usb",
|
||||
"usb_device");
|
||||
if (usb_dev == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus_str = udev_device_get_sysattr_value(usb_dev, "busnum");
|
||||
if (bus_str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_str = udev_device_get_sysattr_value(usb_dev, "devnum");
|
||||
if (addr_str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*usb_bus = (int)strtol(bus_str, NULL, 16);
|
||||
*usb_addr = (int)strtol(addr_str, NULL, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
p_udev_get_interface_number(struct udev_device* raw_dev, uint16_t* interface)
|
||||
{
|
||||
struct udev_device* intf_dev;
|
||||
const char* str;
|
||||
|
||||
// Make udev find the handle to the interface node.
|
||||
// No we should not unref intf_dev, valgrind agrees.
|
||||
intf_dev = udev_device_get_parent_with_subsystem_devtype(
|
||||
raw_dev, "usb", "usb_interface");
|
||||
if (intf_dev == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");
|
||||
if (str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*interface = (uint16_t)strtol(str, NULL, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
p_udev_get_and_parse_uevent(struct udev_device* raw_dev,
|
||||
uint32_t* out_bus_type,
|
||||
uint16_t* out_vendor_id,
|
||||
uint16_t* out_product_id,
|
||||
uint64_t* out_bluetooth_serial)
|
||||
{
|
||||
struct udev_device* hid_dev;
|
||||
char* serial_utf8 = NULL;
|
||||
uint64_t bluetooth_serial = 0;
|
||||
uint16_t vendor_id = 0, product_id = 0;
|
||||
uint32_t bus_type;
|
||||
const char* uevent;
|
||||
char* saveptr;
|
||||
char* line;
|
||||
char* tmp;
|
||||
int ret;
|
||||
bool ok;
|
||||
|
||||
// Dig through and find the regular hid node.
|
||||
hid_dev =
|
||||
udev_device_get_parent_with_subsystem_devtype(raw_dev, "hid", NULL);
|
||||
if (hid_dev == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uevent = udev_device_get_sysattr_value(hid_dev, "uevent");
|
||||
if (uevent == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = strdup(uevent);
|
||||
if (tmp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
line = strtok_r(tmp, "\n", &saveptr);
|
||||
while (line != NULL) {
|
||||
if (strncmp(line, "HID_ID=", 7) == 0) {
|
||||
ret = sscanf(line + 7, "%x:%hx:%hx", &bus_type,
|
||||
&vendor_id, &product_id);
|
||||
if (ret == 3) {
|
||||
ok = true;
|
||||
}
|
||||
} else if (strncmp(line, "HID_NAME=", 9) == 0) {
|
||||
// printf("\t\tprocuct_name: '%s'\n", line + 9);
|
||||
} else if (strncmp(line, "HID_UNIQ=", 9) == 0) {
|
||||
serial_utf8 = &line[9];
|
||||
// printf("\t\tserial: '%s'\n", line + 9);
|
||||
}
|
||||
|
||||
line = strtok_r(NULL, "\n", &saveptr);
|
||||
}
|
||||
|
||||
if (ok && bus_type == HIDRAW_BUS_BLUETOOTH && serial_utf8 != NULL) {
|
||||
union {
|
||||
uint8_t arr[8];
|
||||
uint64_t v;
|
||||
} extract = {0};
|
||||
|
||||
ret = sscanf(serial_utf8, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&extract.arr[5], &extract.arr[4], &extract.arr[3],
|
||||
&extract.arr[2], &extract.arr[1], &extract.arr[0]);
|
||||
if (ret == 6) {
|
||||
bluetooth_serial = extract.v;
|
||||
}
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
|
||||
if (ok) {
|
||||
*out_bus_type = bus_type;
|
||||
*out_vendor_id = vendor_id;
|
||||
*out_product_id = product_id;
|
||||
*out_bluetooth_serial = bluetooth_serial;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -5,4 +5,5 @@
|
|||
# This is where we collect all of the pieces from the different parts of
|
||||
# the source tree and build a complete driver or integration part.
|
||||
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(openxr)
|
||||
|
|
16
src/xrt/targets/common/CMakeLists.txt
Normal file
16
src/xrt/targets/common/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Copyright 2019, Collabora, Ltd.
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../auxiliary
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../drivers
|
||||
)
|
||||
|
||||
set(SOURCE_FILES
|
||||
target_lists.c
|
||||
)
|
||||
|
||||
add_library(target_lists OBJECT ${SOURCE_FILES})
|
||||
|
||||
set_property(TARGET target_lists PROPERTY POSITION_INDEPENDENT_CODE ON)
|
53
src/xrt/targets/common/target_lists.c
Normal file
53
src/xrt/targets/common/target_lists.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Common things to pull into a target.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
*/
|
||||
|
||||
#include "target_lists.h"
|
||||
|
||||
#ifdef XRT_BUILD_HDK
|
||||
#include "hdk/hdk_interface.h"
|
||||
#endif
|
||||
|
||||
#ifdef XRT_BUILD_OHMD
|
||||
#include "ohmd/oh_interface.h"
|
||||
#endif
|
||||
|
||||
#ifdef XRT_BUILD_PSVR
|
||||
#include "psvr/psvr_interface.h"
|
||||
#endif
|
||||
|
||||
|
||||
struct xrt_prober_entry target_entry_list[] = {
|
||||
{0x0000, 0x0000, NULL, NULL}, // Terminate
|
||||
};
|
||||
|
||||
struct xrt_prober_entry *target_entry_lists[] = {
|
||||
target_entry_list,
|
||||
NULL, // Terminate
|
||||
};
|
||||
|
||||
xrt_auto_prober_creator target_auto_list[] = {
|
||||
#ifdef XRT_BUILD_HDK
|
||||
hdk_create_auto_prober,
|
||||
#endif
|
||||
|
||||
#ifdef XRT_BUILD_PSVR
|
||||
psvr_create_auto_prober,
|
||||
#endif
|
||||
|
||||
#ifdef XRT_BUILD_OHMD
|
||||
// OpenHMD last as we want to override it with native drivers.
|
||||
oh_create_auto_prober,
|
||||
#endif
|
||||
NULL, // Terminate
|
||||
};
|
||||
|
||||
struct xrt_prober_entry_lists target_lists = {
|
||||
target_entry_lists,
|
||||
target_auto_list,
|
||||
NULL,
|
||||
};
|
16
src/xrt/targets/common/target_lists.h
Normal file
16
src/xrt/targets/common/target_lists.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Common things to pull into a target.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xrt/xrt_prober.h"
|
||||
|
||||
extern struct xrt_prober_entry target_entry_list[];
|
||||
extern struct xrt_prober_entry *target_entry_lists[];
|
||||
extern xrt_auto_prober_creator target_auto_list[];
|
||||
extern struct xrt_prober_entry_lists target_lists;
|
Loading…
Reference in a new issue