mirror of https://github.com/encounter/SDL.git
hidapi/libusb: maintain in-memory cache of vendor/product strings
The get_usb_string call is rather expensive on some USB devices, so we cache the vendor/product strings for future lookups (e.g. when hid_enumerate is invoked again later). This way, we only need to ask libusb for strings for devices we haven't seen since before we started. Signed-off-by: Steven Noonan <steven@valvesoftware.com> Signed-off-by: Sam Lantinga <slouken@libsdl.org>
This commit is contained in:
parent
4535d65491
commit
17d8479d98
|
@ -440,6 +440,94 @@ err:
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct usb_string_cache_entry {
|
||||||
|
uint16_t vid;
|
||||||
|
uint16_t pid;
|
||||||
|
wchar_t *vendor;
|
||||||
|
wchar_t *product;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct usb_string_cache_entry *usb_string_cache = NULL;
|
||||||
|
static size_t usb_string_cache_size = 0;
|
||||||
|
static size_t usb_string_cache_insert_pos = 0;
|
||||||
|
|
||||||
|
static int usb_string_cache_grow()
|
||||||
|
{
|
||||||
|
struct usb_string_cache_entry *new_cache;
|
||||||
|
size_t allocSize;
|
||||||
|
size_t new_cache_size;
|
||||||
|
|
||||||
|
new_cache_size = usb_string_cache_size + 8;
|
||||||
|
allocSize = sizeof(struct usb_string_cache_entry) * new_cache_size;
|
||||||
|
new_cache = (struct usb_string_cache_entry *)realloc(usb_string_cache, allocSize);
|
||||||
|
if (!new_cache)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
usb_string_cache = new_cache;
|
||||||
|
usb_string_cache_size = new_cache_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_string_cache_destroy()
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < usb_string_cache_insert_pos; i++) {
|
||||||
|
free(usb_string_cache[i].vendor);
|
||||||
|
free(usb_string_cache[i].product);
|
||||||
|
}
|
||||||
|
free(usb_string_cache);
|
||||||
|
|
||||||
|
usb_string_cache = NULL;
|
||||||
|
usb_string_cache_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct usb_string_cache_entry *usb_string_cache_insert()
|
||||||
|
{
|
||||||
|
struct usb_string_cache_entry *new_entry = NULL;
|
||||||
|
if (usb_string_cache_insert_pos >= usb_string_cache_size) {
|
||||||
|
if (usb_string_cache_grow() < 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
new_entry = &usb_string_cache[usb_string_cache_insert_pos];
|
||||||
|
usb_string_cache_insert_pos++;
|
||||||
|
return new_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct usb_string_cache_entry *usb_string_cache_find(struct libusb_device_descriptor *desc, struct libusb_device_handle *handle)
|
||||||
|
{
|
||||||
|
struct usb_string_cache_entry *entry = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Search for existing string cache entry */
|
||||||
|
for (i = 0; i < usb_string_cache_insert_pos; i++) {
|
||||||
|
entry = &usb_string_cache[i];
|
||||||
|
if (entry->vid != desc->idVendor)
|
||||||
|
continue;
|
||||||
|
if (entry->pid != desc->idProduct)
|
||||||
|
continue;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found, create one. */
|
||||||
|
entry = usb_string_cache_insert();
|
||||||
|
if (!entry)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
entry->vid = desc->idVendor;
|
||||||
|
entry->pid = desc->idProduct;
|
||||||
|
if (desc->iManufacturer > 0)
|
||||||
|
entry->vendor = get_usb_string(handle, desc->iManufacturer);
|
||||||
|
else
|
||||||
|
entry->vendor = NULL;
|
||||||
|
if (desc->iProduct > 0)
|
||||||
|
entry->product = get_usb_string(handle, desc->iProduct);
|
||||||
|
else
|
||||||
|
entry->product = NULL;
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
static char *make_path(libusb_device *dev, int interface_number)
|
static char *make_path(libusb_device *dev, int interface_number)
|
||||||
{
|
{
|
||||||
char str[64];
|
char str[64];
|
||||||
|
@ -473,6 +561,8 @@ int HID_API_EXPORT hid_init(void)
|
||||||
|
|
||||||
int HID_API_EXPORT hid_exit(void)
|
int HID_API_EXPORT hid_exit(void)
|
||||||
{
|
{
|
||||||
|
usb_string_cache_destroy();
|
||||||
|
|
||||||
if (usb_context) {
|
if (usb_context) {
|
||||||
libusb_exit(usb_context);
|
libusb_exit(usb_context);
|
||||||
usb_context = NULL;
|
usb_context = NULL;
|
||||||
|
@ -617,6 +707,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||||
|
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
struct hid_device_info *tmp;
|
struct hid_device_info *tmp;
|
||||||
|
const struct usb_string_cache_entry *string_cache;
|
||||||
|
|
||||||
/* VID/PID match. Create the record. */
|
/* VID/PID match. Create the record. */
|
||||||
tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
|
tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
|
||||||
|
@ -638,12 +729,20 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||||
get_usb_string(handle, desc.iSerialNumber);
|
get_usb_string(handle, desc.iSerialNumber);
|
||||||
|
|
||||||
/* Manufacturer and Product strings */
|
/* Manufacturer and Product strings */
|
||||||
if (desc.iManufacturer > 0)
|
if (dev_vid && dev_pid) {
|
||||||
cur_dev->manufacturer_string =
|
string_cache = usb_string_cache_find(&desc, handle);
|
||||||
get_usb_string(handle, desc.iManufacturer);
|
if (string_cache) {
|
||||||
if (desc.iProduct > 0)
|
cur_dev->manufacturer_string = wcsdup(string_cache->vendor);
|
||||||
cur_dev->product_string =
|
cur_dev->product_string = wcsdup(string_cache->product);
|
||||||
get_usb_string(handle, desc.iProduct);
|
}
|
||||||
|
} else {
|
||||||
|
if (desc.iManufacturer > 0)
|
||||||
|
cur_dev->manufacturer_string =
|
||||||
|
get_usb_string(handle, desc.iManufacturer);
|
||||||
|
if (desc.iProduct > 0)
|
||||||
|
cur_dev->product_string =
|
||||||
|
get_usb_string(handle, desc.iProduct);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef INVASIVE_GET_USAGE
|
#ifdef INVASIVE_GET_USAGE
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue