diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c index b786f6fa4..23d628ef4 100644 --- a/src/core/linux/SDL_udev.c +++ b/src/core/linux/SDL_udev.c @@ -19,7 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ -/* +/* * To list the properties of a device, try something like: * udevadm info -a -n snd/hwC0D0 (for a sound card) * udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc) @@ -115,23 +115,23 @@ int SDL_UDEV_Init(void) { int retval = 0; - + if (_this == NULL) { _this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this)); if(_this == NULL) { return SDL_OutOfMemory(); } - + retval = SDL_UDEV_LoadLibrary(); if (retval < 0) { SDL_UDEV_Quit(); return retval; } - - /* Set up udev monitoring + + /* Set up udev monitoring * Listen for input devices (mouse, keyboard, joystick, etc) and sound devices */ - + _this->udev = _this->syms.udev_new(); if (_this->udev == NULL) { SDL_UDEV_Quit(); @@ -143,18 +143,18 @@ SDL_UDEV_Init(void) SDL_UDEV_Quit(); return SDL_SetError("udev_monitor_new_from_netlink() failed"); } - + _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL); _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL); _this->syms.udev_monitor_enable_receiving(_this->udev_mon); - + /* Do an initial scan of existing devices */ SDL_UDEV_Scan(); } - + _this->ref_count += 1; - + return retval; } @@ -162,15 +162,15 @@ void SDL_UDEV_Quit(void) { SDL_UDEV_CallbackList *item; - + if (_this == NULL) { return; } - + _this->ref_count -= 1; - + if (_this->ref_count < 1) { - + if (_this->udev_mon != NULL) { _this->syms.udev_monitor_unref(_this->udev_mon); _this->udev_mon = NULL; @@ -179,14 +179,14 @@ SDL_UDEV_Quit(void) _this->syms.udev_unref(_this->udev); _this->udev = NULL; } - + /* Remove existing devices */ while (_this->first != NULL) { item = _this->first; _this->first = _this->first->next; SDL_free(item); } - + SDL_UDEV_UnloadLibrary(); SDL_free(_this); _this = NULL; @@ -198,22 +198,22 @@ SDL_UDEV_Scan(void) { struct udev_enumerate *enumerate = NULL; struct udev_list_entry *devs = NULL; - struct udev_list_entry *item = NULL; - + struct udev_list_entry *item = NULL; + if (_this == NULL) { return; } - + enumerate = _this->syms.udev_enumerate_new(_this->udev); if (enumerate == NULL) { SDL_UDEV_Quit(); SDL_SetError("udev_enumerate_new() failed"); return; } - + _this->syms.udev_enumerate_add_match_subsystem(enumerate, "input"); _this->syms.udev_enumerate_add_match_subsystem(enumerate, "sound"); - + _this->syms.udev_enumerate_scan_devices(enumerate); devs = _this->syms.udev_enumerate_get_list_entry(enumerate); for (item = devs; item; item = _this->syms.udev_list_entry_get_next(item)) { @@ -228,6 +228,62 @@ SDL_UDEV_Scan(void) _this->syms.udev_enumerate_unref(enumerate); } +SDL_bool +SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version) +{ + struct udev_enumerate *enumerate = NULL; + struct udev_list_entry *devs = NULL; + struct udev_list_entry *item = NULL; + SDL_bool found = SDL_FALSE; + + if (_this == NULL) { + return SDL_FALSE; + } + + enumerate = _this->syms.udev_enumerate_new(_this->udev); + if (enumerate == NULL) { + SDL_SetError("udev_enumerate_new() failed"); + return SDL_FALSE; + } + + _this->syms.udev_enumerate_scan_devices(enumerate); + devs = _this->syms.udev_enumerate_get_list_entry(enumerate); + for (item = devs; item && !found; item = _this->syms.udev_list_entry_get_next(item)) { + const char *path = _this->syms.udev_list_entry_get_name(item); + struct udev_device *dev = _this->syms.udev_device_new_from_syspath(_this->udev, path); + if (dev != NULL) { + const char *val = NULL; + const char *existing_path; + + existing_path = _this->syms.udev_device_get_devnode(dev); + if (existing_path && SDL_strcmp(device_path, existing_path) == 0) { + found = SDL_TRUE; + + val = _this->syms.udev_device_get_property_value(dev, "ID_VENDOR_ID"); + if (val != NULL) { + *vendor = (Uint16)SDL_strtol(val, NULL, 16); + } + + val = _this->syms.udev_device_get_property_value(dev, "ID_MODEL_ID"); + if (val != NULL) { + *product = (Uint16)SDL_strtol(val, NULL, 16); + } + + val = _this->syms.udev_device_get_property_value(dev, "ID_REVISION"); + if (val != NULL) { + *version = (Uint16)SDL_strtol(val, NULL, 16); + } + } + _this->syms.udev_device_unref(dev); + } + } + _this->syms.udev_enumerate_unref(enumerate); + + return found; +} + + + void SDL_UDEV_UnloadLibrary(void) @@ -235,7 +291,7 @@ SDL_UDEV_UnloadLibrary(void) if (_this == NULL) { return; } - + if (_this->udev_handle != NULL) { SDL_UnloadObject(_this->udev_handle); _this->udev_handle = NULL; @@ -246,11 +302,11 @@ int SDL_UDEV_LoadLibrary(void) { int retval = 0, i; - + if (_this == NULL) { return SDL_SetError("UDEV not initialized"); } - + /* See if there is a udev library already loaded */ if (SDL_UDEV_load_syms() == 0) { return 0; @@ -282,7 +338,7 @@ SDL_UDEV_LoadLibrary(void) } } } - + if (_this->udev_handle == NULL) { retval = -1; /* Don't call SDL_SetError(): SDL_LoadObject already did. */ @@ -352,26 +408,26 @@ guess_device_class(struct udev_device *dev) &bitmask_rel[0]); } -static void -device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) +static void +device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) { const char *subsystem; const char *val = NULL; int devclass = 0; const char *path; SDL_UDEV_CallbackList *item; - + path = _this->syms.udev_device_get_devnode(dev); if (path == NULL) { return; } - + subsystem = _this->syms.udev_device_get_subsystem(dev); if (SDL_strcmp(subsystem, "sound") == 0) { devclass = SDL_UDEV_DEVICE_SOUND; } else if (SDL_strcmp(subsystem, "input") == 0) { /* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */ - + val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK"); if (val != NULL && SDL_strcmp(val, "1") == 0 ) { devclass |= SDL_UDEV_DEVICE_JOYSTICK; @@ -381,13 +437,13 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE) && val != NULL && SDL_strcmp(val, "1") == 0 ) { devclass |= SDL_UDEV_DEVICE_JOYSTICK; - } - + } + val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE"); if (val != NULL && SDL_strcmp(val, "1") == 0 ) { devclass |= SDL_UDEV_DEVICE_MOUSE; } - + val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN"); if (val != NULL && SDL_strcmp(val, "1") == 0 ) { devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; @@ -396,7 +452,7 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) /* The undocumented rule is: - All devices with keys get ID_INPUT_KEY - From this subset, if they have ESC, numbers, and Q to D, it also gets ID_INPUT_KEYBOARD - + Ref: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c#n183 */ val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_KEY"); @@ -425,14 +481,14 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) } else { return; } - + /* Process callbacks */ for (item = _this->first; item != NULL; item = item->next) { item->callback(type, devclass, path); } } -void +void SDL_UDEV_Poll(void) { struct udev_device *dev = NULL; @@ -456,12 +512,12 @@ SDL_UDEV_Poll(void) device_event(SDL_UDEV_DEVICEREMOVED, dev); } } - + _this->syms.udev_device_unref(dev); } } -int +int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb) { SDL_UDEV_CallbackList *item; @@ -469,7 +525,7 @@ SDL_UDEV_AddCallback(SDL_UDEV_Callback cb) if (item == NULL) { return SDL_OutOfMemory(); } - + item->callback = cb; if (_this->last == NULL) { @@ -478,11 +534,11 @@ SDL_UDEV_AddCallback(SDL_UDEV_Callback cb) _this->last->next = item; _this->last = item; } - + return 1; } -void +void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb) { SDL_UDEV_CallbackList *item; @@ -505,7 +561,6 @@ SDL_UDEV_DelCallback(SDL_UDEV_Callback cb) } prev = item; } - } const SDL_UDEV_Symbols * diff --git a/src/core/linux/SDL_udev.h b/src/core/linux/SDL_udev.h index da81474e7..5f64e2d79 100644 --- a/src/core/linux/SDL_udev.h +++ b/src/core/linux/SDL_udev.h @@ -101,6 +101,7 @@ extern void SDL_UDEV_UnloadLibrary(void); extern int SDL_UDEV_LoadLibrary(void); extern void SDL_UDEV_Poll(void); extern void SDL_UDEV_Scan(void); +extern SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version); extern int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb); extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb); extern const SDL_UDEV_Symbols *SDL_UDEV_GetUdevSyms(void); diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index fe82ae82f..188d05a06 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -178,7 +178,7 @@ GuessIsJoystick(int fd) } static int -IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid) +IsJoystick(const char *path, int fd, char **name_return, SDL_JoystickGUID *guid) { struct input_id inpid; Uint16 *guid16 = (Uint16 *)guid->data; @@ -187,6 +187,9 @@ IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid) if (ioctl(fd, JSIOCGNAME(sizeof(product_string)), product_string) >= 0) { SDL_zero(inpid); +#if SDL_USE_LIBUDEV + SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version); +#endif } else { /* When udev is enabled we only get joystick devices here, so there's no need to test them */ if (enumeration_method != ENUMERATION_LIBUDEV && !GuessIsJoystick(fd)) { @@ -326,7 +329,7 @@ MaybeAddDevice(const char *path) SDL_Log("Checking %s\n", path); #endif - isstick = IsJoystick(fd, &name, &guid); + isstick = IsJoystick(path, fd, &name, &guid); close(fd); if (!isstick) { return -1;