mirror of
https://github.com/RPCS3/hidapi.git
synced 2026-07-19 21:43:36 -04:00
Added the hidapi_enumerate() interface on Linux.
Added manufacturer and product strings to the hid_device struct.
This commit is contained in:
@@ -230,6 +230,8 @@ void HID_API_EXPORT hid_free_enumeration(struct hid_device *devs)
|
||||
struct hid_device *next = d->next;
|
||||
free(d->path);
|
||||
free(d->serial_number);
|
||||
free(d->manufacturer_string);
|
||||
free(d->product_string);
|
||||
free(d);
|
||||
d = next;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ extern "C" {
|
||||
unsigned short product_id;
|
||||
/** Serial Number */
|
||||
wchar_t *serial_number;
|
||||
/** Manufacturer String */
|
||||
wchar_t *manufacturer_string;
|
||||
/** Product string */
|
||||
wchar_t *product_string;
|
||||
|
||||
/** Pointer to the next device */
|
||||
struct hid_device *next;
|
||||
|
||||
+4
-1
@@ -39,7 +39,10 @@ int main(int argc, char* argv[])
|
||||
cur_dev = devs;
|
||||
while (cur_dev) {
|
||||
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
|
||||
printf("\n\n");
|
||||
printf("\n");
|
||||
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
|
||||
printf(" Product: %ls\n", cur_dev->product_string);
|
||||
printf("\n");
|
||||
cur_dev = cur_dev->next;
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
gcc -Wall -g -c hid.c -I ../hidapi
|
||||
gcc -Wall -g -c ../hidtest/hidtest.cpp -I ../hidapi
|
||||
g++ -Wall -g -o test hid.o hidtest.o /usr/lib/libudev.so.0.8.0
|
||||
g++ -Wall -g -o test hid.o hidtest.o -ludev
|
||||
+173
-67
@@ -16,15 +16,22 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "/usr/include/libudev.h"
|
||||
/* Unix */
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "libudev.h"
|
||||
|
||||
#include "hidapi.h"
|
||||
|
||||
struct Device {
|
||||
int valid;
|
||||
int device_handle;
|
||||
int blocking;
|
||||
int valid;
|
||||
int device_handle;
|
||||
int blocking;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,6 +44,24 @@ static void register_error(struct Device *device, const char *op)
|
||||
|
||||
}
|
||||
|
||||
/* Get an attribute value from a udev_device and return it as a whar_t
|
||||
string. The returned string must be freed with free() when done.*/
|
||||
static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)
|
||||
{
|
||||
const char *str;
|
||||
wchar_t *ret = NULL;
|
||||
str = udev_device_get_sysattr_value(dev, udev_name);
|
||||
if (str) {
|
||||
/* Convert the string from UTF-8 to wchar_t */
|
||||
size_t wlen = mbstowcs(NULL, str, 0);
|
||||
ret = calloc(wlen+1, sizeof(wchar_t));
|
||||
mbstowcs(ret, str, wlen+1);
|
||||
ret[wlen] = 0x0000;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct hid_device HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
|
||||
{
|
||||
struct udev *udev;
|
||||
@@ -46,12 +71,14 @@ struct hid_device HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsig
|
||||
|
||||
struct hid_device *root = NULL; // return object
|
||||
struct hid_device *cur_dev = NULL;
|
||||
|
||||
setlocale(LC_ALL,"");
|
||||
|
||||
/* Create the udev object */
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
printf("Can't create udev\n");
|
||||
exit(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create a list of the devices in the 'hidraw' subsystem. */
|
||||
@@ -59,46 +86,21 @@ struct hid_device HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsig
|
||||
udev_enumerate_add_match_subsystem(enumerate, "hidraw");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
/* For each item enumerated, print out its information.
|
||||
udev_list_entry_foreach is a macro which expands to
|
||||
a loop. The loop will be executed for each member in
|
||||
devices, setting dev_list_entry to a list entry
|
||||
which contains the device's path in /sys. */
|
||||
/* For each item, see if it matches the vid/pid, and if so
|
||||
create a udev_device record for it */
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
const char *path;
|
||||
const char *sysfs_path;
|
||||
const char *dev_path;
|
||||
const char *str;
|
||||
size_t len;
|
||||
struct hid_device *tmp;
|
||||
unsigned short dev_vid;
|
||||
unsigned short dev_pid;
|
||||
|
||||
/* Get the filename of the /sys entry for the device
|
||||
and create a udev_device object (dev) representing it */
|
||||
path = udev_list_entry_get_name(dev_list_entry);
|
||||
dev = udev_device_new_from_syspath(udev, path);
|
||||
|
||||
/* usb_device_get_devnode() returns the path to the device node
|
||||
itself in /dev. */
|
||||
printf("Device Node Path: %s\n", udev_device_get_devnode(dev));
|
||||
sysfs_path = udev_list_entry_get_name(dev_list_entry);
|
||||
dev = udev_device_new_from_syspath(udev, sysfs_path);
|
||||
dev_path = udev_device_get_devnode(dev);
|
||||
|
||||
tmp = malloc(sizeof(struct hid_device));
|
||||
if (cur_dev) {
|
||||
cur_dev->next = tmp;
|
||||
}
|
||||
else {
|
||||
root = tmp;
|
||||
}
|
||||
cur_dev = tmp;
|
||||
|
||||
cur_dev->next = NULL;
|
||||
str = udev_device_get_devnode(dev);
|
||||
if (str) {
|
||||
len = strlen(str);
|
||||
cur_dev->path = calloc(len+1, sizeof(char));
|
||||
strncpy(cur_dev->path, str, len+1);
|
||||
cur_dev->path[len] = '\0';
|
||||
}
|
||||
else
|
||||
cur_dev->path = NULL;
|
||||
|
||||
/* The device pointed to by dev contains information about
|
||||
the hidraw device. In order to get information about the
|
||||
USB device, get the parent device with the
|
||||
@@ -110,49 +112,121 @@ struct hid_device HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsig
|
||||
"usb",
|
||||
"usb_device");
|
||||
if (!dev) {
|
||||
printf("Unable to find parent usb device.");
|
||||
exit(1);
|
||||
/* Unable to find parent usb device. */
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Get the VID/PID of the device */
|
||||
str = udev_device_get_sysattr_value(dev,"idVendor");
|
||||
cur_dev->vendor_id = (str)? strtol(str, NULL, 16): 0x0;
|
||||
|
||||
dev_vid = (str)? strtol(str, NULL, 16): 0x0;
|
||||
str = udev_device_get_sysattr_value(dev, "idProduct");
|
||||
cur_dev->product_id = (str)? strtol(str, NULL, 16): 0x0;
|
||||
dev_pid = (str)? strtol(str, NULL, 16): 0x0;
|
||||
|
||||
/* Check the VID/PID against the arguments */
|
||||
if ((vendor_id == 0x0 && product_id == 0x0) ||
|
||||
(vendor_id == dev_vid && product_id == dev_pid)) {
|
||||
struct hid_device *tmp;
|
||||
size_t len;
|
||||
|
||||
/* From here, we can call get_sysattr_value() for each file
|
||||
in the device's /sys entry. The strings passed into these
|
||||
functions (idProduct, idVendor, serial, etc.) correspond
|
||||
directly to the files in the /sys directory which
|
||||
represents the USB device. Note that USB strings are
|
||||
Unicode, UCS2 encoded, but the strings returned from
|
||||
udev_device_get_sysattr_value() are UTF-8 encoded. */
|
||||
printf(" VID/PID: %s %s\n",
|
||||
udev_device_get_sysattr_value(dev,"idVendor"),
|
||||
udev_device_get_sysattr_value(dev, "idProduct"));
|
||||
printf(" %s\n %s\n",
|
||||
udev_device_get_sysattr_value(dev,"manufacturer"),
|
||||
udev_device_get_sysattr_value(dev,"product"));
|
||||
printf(" serial: %s\n",
|
||||
udev_device_get_sysattr_value(dev, "serial"));
|
||||
/* VID/PID match. Create the record. */
|
||||
tmp = malloc(sizeof(struct hid_device));
|
||||
if (cur_dev) {
|
||||
cur_dev->next = tmp;
|
||||
}
|
||||
else {
|
||||
root = tmp;
|
||||
}
|
||||
cur_dev = tmp;
|
||||
|
||||
/* Fill out the record */
|
||||
cur_dev->next = NULL;
|
||||
str = dev_path;
|
||||
if (str) {
|
||||
len = strlen(str);
|
||||
cur_dev->path = calloc(len+1, sizeof(char));
|
||||
strncpy(cur_dev->path, str, len+1);
|
||||
cur_dev->path[len] = '\0';
|
||||
}
|
||||
else
|
||||
cur_dev->path = NULL;
|
||||
|
||||
/* Serial Number */
|
||||
cur_dev->serial_number
|
||||
= copy_udev_string(dev, "serial");
|
||||
|
||||
/* Manufacturer and Product strings */
|
||||
cur_dev->manufacturer_string
|
||||
= copy_udev_string(dev, "manufacturer");
|
||||
cur_dev->product_string
|
||||
= copy_udev_string(dev, "product");
|
||||
|
||||
/* VID/PID */
|
||||
cur_dev->vendor_id = dev_vid;
|
||||
cur_dev->product_id = dev_pid;
|
||||
}
|
||||
else
|
||||
goto next;
|
||||
|
||||
next:
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
/* Free the enumerator object */
|
||||
/* Free the enumerator and udev objects. */
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
udev_unref(udev);
|
||||
|
||||
return root;
|
||||
|
||||
}
|
||||
|
||||
void HID_API_EXPORT hid_free_enumeration(struct hid_device *devs)
|
||||
{
|
||||
|
||||
struct hid_device *d = devs;
|
||||
while (d) {
|
||||
struct hid_device *next = d->next;
|
||||
free(d->path);
|
||||
free(d->serial_number);
|
||||
free(d->manufacturer_string);
|
||||
free(d->product_string);
|
||||
free(d);
|
||||
d = next;
|
||||
}
|
||||
}
|
||||
|
||||
int HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number)
|
||||
{
|
||||
struct hid_device *devs, *cur_dev;
|
||||
const char *path_to_open = NULL;
|
||||
int handle = -1;
|
||||
|
||||
devs = hid_enumerate(vendor_id, product_id);
|
||||
cur_dev = devs;
|
||||
while (cur_dev) {
|
||||
if (cur_dev->vendor_id == vendor_id &&
|
||||
cur_dev->product_id == product_id) {
|
||||
if (serial_number) {
|
||||
if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
|
||||
path_to_open = cur_dev->path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
path_to_open = cur_dev->path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur_dev = cur_dev->next;
|
||||
}
|
||||
|
||||
if (path_to_open) {
|
||||
/* Open the device */
|
||||
handle = hid_open_path(path_to_open);
|
||||
}
|
||||
|
||||
hid_free_enumeration(devs);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int HID_API_EXPORT hid_open_path(const char *path)
|
||||
{
|
||||
int i;
|
||||
int handle = -1;
|
||||
@@ -183,6 +257,9 @@ int HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id,
|
||||
return -1;
|
||||
}
|
||||
|
||||
// OPEN HERE //
|
||||
dev->device_handle = open(path, O_RDWR);
|
||||
|
||||
// If we have a good handle, return it.
|
||||
if (dev->device_handle > 0) {
|
||||
return handle;
|
||||
@@ -192,13 +269,14 @@ int HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id,
|
||||
dev->valid = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int HID_API_EXPORT hid_write(int device, const unsigned char *data, size_t length)
|
||||
{
|
||||
struct Device *dev = NULL;
|
||||
int bytes_written;
|
||||
int res;
|
||||
|
||||
// Get the handle
|
||||
if (device < 0 || device >= MAX_DEVICES)
|
||||
@@ -206,6 +284,8 @@ int HID_API_EXPORT hid_write(int device, const unsigned char *data, size_t lengt
|
||||
if (devices[device].valid == 0)
|
||||
return -1;
|
||||
dev = &devices[device];
|
||||
|
||||
bytes_written = write(dev->device_handle, data, length);
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
@@ -215,7 +295,6 @@ int HID_API_EXPORT hid_read(int device, unsigned char *data, size_t length)
|
||||
{
|
||||
struct Device *dev = NULL;
|
||||
int bytes_read;
|
||||
int res;
|
||||
|
||||
// Get the handle
|
||||
if (device < 0 || device >= MAX_DEVICES)
|
||||
@@ -224,11 +303,14 @@ int HID_API_EXPORT hid_read(int device, unsigned char *data, size_t length)
|
||||
return -1;
|
||||
dev = &devices[device];
|
||||
|
||||
bytes_read = read(dev->device_handle, data, length);
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
int HID_API_EXPORT hid_set_nonblocking(int device, int nonblock)
|
||||
{
|
||||
int flags, res;
|
||||
struct Device *dev = NULL;
|
||||
|
||||
// Get the handle
|
||||
@@ -238,8 +320,23 @@ int HID_API_EXPORT hid_set_nonblocking(int device, int nonblock)
|
||||
return -1;
|
||||
dev = &devices[device];
|
||||
|
||||
dev->blocking = !nonblock;
|
||||
return 0; /* Success */
|
||||
flags = fcntl(dev->device_handle, F_GETFL, 0);
|
||||
if (flags >= 0) {
|
||||
if (nonblock)
|
||||
res = fcntl(dev->device_handle, F_SETFL, flags | O_NONBLOCK);
|
||||
else
|
||||
res = fcntl(dev->device_handle, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (res < 0) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
dev->blocking = !nonblock;
|
||||
return 0; /* Success */
|
||||
}
|
||||
}
|
||||
|
||||
void HID_API_EXPORT hid_close(int device)
|
||||
@@ -253,6 +350,8 @@ void HID_API_EXPORT hid_close(int device)
|
||||
return;
|
||||
dev = &devices[device];
|
||||
|
||||
close(dev->device_handle);
|
||||
|
||||
dev->valid = 0;
|
||||
}
|
||||
|
||||
@@ -268,6 +367,7 @@ int HID_API_EXPORT_CALL hid_get_manufacturer_string(int device, wchar_t *string,
|
||||
return -1;
|
||||
dev = &devices[device];
|
||||
|
||||
// TODO:
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -284,6 +384,7 @@ int HID_API_EXPORT_CALL hid_get_product_string(int device, wchar_t *string, size
|
||||
return -1;
|
||||
dev = &devices[device];
|
||||
|
||||
// TODO:
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -300,6 +401,8 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(int device, wchar_t *string
|
||||
return -1;
|
||||
dev = &devices[device];
|
||||
|
||||
// TODO:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -315,6 +418,7 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(int device, int string_index, wch
|
||||
return -1;
|
||||
dev = &devices[device];
|
||||
|
||||
// TODO:
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -331,5 +435,7 @@ HID_API_EXPORT const char * HID_API_CALL hid_error(int device)
|
||||
return NULL;
|
||||
dev = &devices[device];
|
||||
|
||||
// TODO:
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user