diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c index 59d37d0e9..a2d5bb62f 100644 --- a/src/core/linux/SDL_udev.c +++ b/src/core/linux/SDL_udev.c @@ -42,6 +42,9 @@ static SDL_UDEV_PrivateData *_this = NULL; static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr); static int SDL_UDEV_load_syms(void); static SDL_bool SDL_UDEV_hotplug_update_available(void); +static void get_caps(struct udev_device *dev, struct udev_device *pdev, const char *attr, unsigned long *bitmask, size_t bitmask_len); +static int guess_device_class(struct udev_device *dev); +static int device_class(struct udev_device *dev); static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev); static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr) @@ -218,7 +221,7 @@ int SDL_UDEV_Scan(void) return 0; } -SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version) +SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version, int *class) { struct udev_enumerate *enumerate = NULL; struct udev_list_entry *devs = NULL; @@ -246,6 +249,7 @@ SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 existing_path = _this->syms.udev_device_get_devnode(dev); if (existing_path && SDL_strcmp(device_path, existing_path) == 0) { + int class_temp; found = SDL_TRUE; val = _this->syms.udev_device_get_property_value(dev, "ID_VENDOR_ID"); @@ -262,6 +266,11 @@ SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 if (val) { *version = (Uint16)SDL_strtol(val, NULL, 16); } + + class_temp = device_class(dev); + if (class_temp) { + *class = class_temp; + } } _this->syms.udev_device_unref(dev); } @@ -393,29 +402,23 @@ static int guess_device_class(struct udev_device *dev) &bitmask_rel[0]); } -static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) +static int device_class(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) { - return; - } subsystem = _this->syms.udev_device_get_subsystem(dev); + if (!subsystem) { + return 0; + } if (SDL_strcmp(subsystem, "sound") == 0) { devclass = SDL_UDEV_DEVICE_SOUND; } else if (SDL_strcmp(subsystem, "video4linux") == 0) { - devclass = SDL_UDEV_DEVICE_VIDEO_CAPTURE; - val = _this->syms.udev_device_get_property_value(dev, "ID_V4L_CAPABILITIES"); - if (!val || !SDL_strcasestr(val, "capture")) { - return; + if (val && SDL_strcasestr(val, "capture")) { + devclass = SDL_UDEV_DEVICE_VIDEO_CAPTURE; } } else if (SDL_strcmp(subsystem, "input") == 0) { /* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */ @@ -467,18 +470,33 @@ static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) devclass = SDL_UDEV_DEVICE_MOUSE; } else if (SDL_strcmp(val, "kbd") == 0) { devclass = SDL_UDEV_DEVICE_HAS_KEYS | SDL_UDEV_DEVICE_KEYBOARD; - } else { - return; } } else { /* We could be linked with libudev on a system that doesn't have udev running */ devclass = guess_device_class(dev); } } - } else { + } + + return devclass; +} + +static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) +{ + int devclass = 0; + const char *path; + SDL_UDEV_CallbackList *item; + + path = _this->syms.udev_device_get_devnode(dev); + if (!path) { return; } + devclass = device_class(dev); + if (!devclass) { + return; + } + /* Process callbacks */ for (item = _this->first; item; item = item->next) { item->callback(type, devclass, path); diff --git a/src/core/linux/SDL_udev.h b/src/core/linux/SDL_udev.h index ff6399e40..60bef169c 100644 --- a/src/core/linux/SDL_udev.h +++ b/src/core/linux/SDL_udev.h @@ -102,7 +102,7 @@ extern void SDL_UDEV_UnloadLibrary(void); extern int SDL_UDEV_LoadLibrary(void); extern void SDL_UDEV_Poll(void); extern int SDL_UDEV_Scan(void); -extern SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version); +extern SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version, int *class); 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 660887a93..6d55e9cc4 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -282,18 +282,20 @@ static int IsJoystick(const char *path, int fd, char **name_return, Uint16 *vend struct input_id inpid; char *name; char product_string[128]; + int class = 0; - if (ioctl(fd, JSIOCGNAME(sizeof(product_string)), product_string) >= 0) { - SDL_zero(inpid); + SDL_zero(inpid); #ifdef SDL_USE_LIBUDEV - SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version); + SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version, &class); #endif - } else { + if (ioctl(fd, JSIOCGNAME(sizeof(product_string)), product_string) <= 0) { /* 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)) { + if (enumeration_method != ENUMERATION_LIBUDEV && + !(class & SDL_UDEV_DEVICE_JOYSTICK) && ( class || !GuessIsJoystick(fd))) { return 0; } + /* Could have vendor and product already from udev, but should agree with evdev */ if (ioctl(fd, EVIOCGID, &inpid) < 0) { return 0; }