Fixed bug 4267 - linkage failure with --enable-hidapi because of missing libudev symbols

Ozkan Sezer

hidapi dynamic udev initial patch
This commit is contained in:
Sam Lantinga 2018-09-24 16:33:14 -07:00
parent e0fe8f3cb3
commit cd90e2ca58
3 changed files with 83 additions and 52 deletions

View File

@ -63,7 +63,7 @@ SDL_UDEV_load_syms(void)
{ {
/* cast funcs to char* first, to please GCC's strict aliasing rules. */ /* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_UDEV_SYM(x) \ #define SDL_UDEV_SYM(x) \
if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->x)) return -1 if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->syms.x)) return -1
SDL_UDEV_SYM(udev_device_get_action); SDL_UDEV_SYM(udev_device_get_action);
SDL_UDEV_SYM(udev_device_get_devnode); SDL_UDEV_SYM(udev_device_get_devnode);
@ -100,7 +100,7 @@ static SDL_bool
SDL_UDEV_hotplug_update_available(void) SDL_UDEV_hotplug_update_available(void)
{ {
if (_this->udev_mon != NULL) { if (_this->udev_mon != NULL) {
const int fd = _this->udev_monitor_get_fd(_this->udev_mon); const int fd = _this->syms.udev_monitor_get_fd(_this->udev_mon);
if (SDL_IOReady(fd, SDL_FALSE, 0)) { if (SDL_IOReady(fd, SDL_FALSE, 0)) {
return SDL_TRUE; return SDL_TRUE;
} }
@ -130,21 +130,21 @@ SDL_UDEV_Init(void)
* Listen for input devices (mouse, keyboard, joystick, etc) and sound devices * Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
*/ */
_this->udev = _this->udev_new(); _this->udev = _this->syms.udev_new();
if (_this->udev == NULL) { if (_this->udev == NULL) {
SDL_UDEV_Quit(); SDL_UDEV_Quit();
return SDL_SetError("udev_new() failed"); return SDL_SetError("udev_new() failed");
} }
_this->udev_mon = _this->udev_monitor_new_from_netlink(_this->udev, "udev"); _this->udev_mon = _this->syms.udev_monitor_new_from_netlink(_this->udev, "udev");
if (_this->udev_mon == NULL) { if (_this->udev_mon == NULL) {
SDL_UDEV_Quit(); SDL_UDEV_Quit();
return SDL_SetError("udev_monitor_new_from_netlink() failed"); return SDL_SetError("udev_monitor_new_from_netlink() failed");
} }
_this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL); _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
_this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL); _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
_this->udev_monitor_enable_receiving(_this->udev_mon); _this->syms.udev_monitor_enable_receiving(_this->udev_mon);
/* Do an initial scan of existing devices */ /* Do an initial scan of existing devices */
SDL_UDEV_Scan(); SDL_UDEV_Scan();
@ -170,11 +170,11 @@ SDL_UDEV_Quit(void)
if (_this->ref_count < 1) { if (_this->ref_count < 1) {
if (_this->udev_mon != NULL) { if (_this->udev_mon != NULL) {
_this->udev_monitor_unref(_this->udev_mon); _this->syms.udev_monitor_unref(_this->udev_mon);
_this->udev_mon = NULL; _this->udev_mon = NULL;
} }
if (_this->udev != NULL) { if (_this->udev != NULL) {
_this->udev_unref(_this->udev); _this->syms.udev_unref(_this->udev);
_this->udev = NULL; _this->udev = NULL;
} }
@ -202,28 +202,28 @@ SDL_UDEV_Scan(void)
return; return;
} }
enumerate = _this->udev_enumerate_new(_this->udev); enumerate = _this->syms.udev_enumerate_new(_this->udev);
if (enumerate == NULL) { if (enumerate == NULL) {
SDL_UDEV_Quit(); SDL_UDEV_Quit();
SDL_SetError("udev_enumerate_new() failed"); SDL_SetError("udev_enumerate_new() failed");
return; return;
} }
_this->udev_enumerate_add_match_subsystem(enumerate, "input"); _this->syms.udev_enumerate_add_match_subsystem(enumerate, "input");
_this->udev_enumerate_add_match_subsystem(enumerate, "sound"); _this->syms.udev_enumerate_add_match_subsystem(enumerate, "sound");
_this->udev_enumerate_scan_devices(enumerate); _this->syms.udev_enumerate_scan_devices(enumerate);
devs = _this->udev_enumerate_get_list_entry(enumerate); devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
for (item = devs; item; item = _this->udev_list_entry_get_next(item)) { for (item = devs; item; item = _this->syms.udev_list_entry_get_next(item)) {
const char *path = _this->udev_list_entry_get_name(item); const char *path = _this->syms.udev_list_entry_get_name(item);
struct udev_device *dev = _this->udev_device_new_from_syspath(_this->udev, path); struct udev_device *dev = _this->syms.udev_device_new_from_syspath(_this->udev, path);
if (dev != NULL) { if (dev != NULL) {
device_event(SDL_UDEV_DEVICEADDED, dev); device_event(SDL_UDEV_DEVICEADDED, dev);
_this->udev_device_unref(dev); _this->syms.udev_device_unref(dev);
} }
} }
_this->udev_enumerate_unref(enumerate); _this->syms.udev_enumerate_unref(enumerate);
} }
@ -305,7 +305,7 @@ static void get_caps(struct udev_device *dev, struct udev_device *pdev, const ch
unsigned long v; unsigned long v;
SDL_memset(bitmask, 0, bitmask_len*sizeof(*bitmask)); SDL_memset(bitmask, 0, bitmask_len*sizeof(*bitmask));
value = _this->udev_device_get_sysattr_value(pdev, attr); value = _this->syms.udev_device_get_sysattr_value(pdev, attr);
if (!value) { if (!value) {
return; return;
} }
@ -340,8 +340,8 @@ guess_device_class(struct udev_device *dev)
/* walk up the parental chain until we find the real input device; the /* walk up the parental chain until we find the real input device; the
* argument is very likely a subdevice of this, like eventN */ * argument is very likely a subdevice of this, like eventN */
pdev = dev; pdev = dev;
while (pdev && !_this->udev_device_get_sysattr_value(pdev, "capabilities/ev")) { while (pdev && !_this->syms.udev_device_get_sysattr_value(pdev, "capabilities/ev")) {
pdev = _this->udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL); pdev = _this->syms.udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
} }
if (!pdev) { if (!pdev) {
return 0; return 0;
@ -405,28 +405,28 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
const char *path; const char *path;
SDL_UDEV_CallbackList *item; SDL_UDEV_CallbackList *item;
path = _this->udev_device_get_devnode(dev); path = _this->syms.udev_device_get_devnode(dev);
if (path == NULL) { if (path == NULL) {
return; return;
} }
subsystem = _this->udev_device_get_subsystem(dev); subsystem = _this->syms.udev_device_get_subsystem(dev);
if (SDL_strcmp(subsystem, "sound") == 0) { if (SDL_strcmp(subsystem, "sound") == 0) {
devclass = SDL_UDEV_DEVICE_SOUND; devclass = SDL_UDEV_DEVICE_SOUND;
} else if (SDL_strcmp(subsystem, "input") == 0) { } else if (SDL_strcmp(subsystem, "input") == 0) {
/* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */ /* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */
val = _this->udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK"); val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) { if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK; devclass |= SDL_UDEV_DEVICE_JOYSTICK;
} }
val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE"); val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) { if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_MOUSE; devclass |= SDL_UDEV_DEVICE_MOUSE;
} }
val = _this->udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN"); val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) { if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN;
} }
@ -437,14 +437,14 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
Ref: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c#n183 Ref: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c#n183
*/ */
val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEY"); val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_KEY");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) { if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_KEYBOARD; devclass |= SDL_UDEV_DEVICE_KEYBOARD;
} }
if (devclass == 0) { if (devclass == 0) {
/* Fall back to old style input classes */ /* Fall back to old style input classes */
val = _this->udev_device_get_property_value(dev, "ID_CLASS"); val = _this->syms.udev_device_get_property_value(dev, "ID_CLASS");
if (val != NULL) { if (val != NULL) {
if (SDL_strcmp(val, "joystick") == 0) { if (SDL_strcmp(val, "joystick") == 0) {
devclass = SDL_UDEV_DEVICE_JOYSTICK; devclass = SDL_UDEV_DEVICE_JOYSTICK;
@ -481,11 +481,11 @@ SDL_UDEV_Poll(void)
} }
while (SDL_UDEV_hotplug_update_available()) { while (SDL_UDEV_hotplug_update_available()) {
dev = _this->udev_monitor_receive_device(_this->udev_mon); dev = _this->syms.udev_monitor_receive_device(_this->udev_mon);
if (dev == NULL) { if (dev == NULL) {
break; break;
} }
action = _this->udev_device_get_action(dev); action = _this->syms.udev_device_get_action(dev);
if (SDL_strcmp(action, "add") == 0) { if (SDL_strcmp(action, "add") == 0) {
/* Wait for the device to finish initialization */ /* Wait for the device to finish initialization */
@ -496,7 +496,7 @@ SDL_UDEV_Poll(void)
device_event(SDL_UDEV_DEVICEREMOVED, dev); device_event(SDL_UDEV_DEVICEREMOVED, dev);
} }
_this->udev_device_unref(dev); _this->syms.udev_device_unref(dev);
} }
} }
@ -547,6 +547,22 @@ SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
} }
const SDL_UDEV_Symbols *
SDL_UDEV_GetUdevSyms(void)
{
if (SDL_UDEV_Init() < 0) {
SDL_SetError("Could not initialize UDEV");
return NULL;
}
return &_this->syms;
}
void
SDL_UDEV_ReleaseUdevSyms(void)
{
SDL_UDEV_Quit();
}
#endif /* SDL_USE_LIBUDEV */ #endif /* SDL_USE_LIBUDEV */

View File

@ -64,16 +64,7 @@ typedef struct SDL_UDEV_CallbackList {
struct SDL_UDEV_CallbackList *next; struct SDL_UDEV_CallbackList *next;
} SDL_UDEV_CallbackList; } SDL_UDEV_CallbackList;
typedef struct SDL_UDEV_PrivateData typedef struct SDL_UDEV_Symbols {
{
const char *udev_library;
void *udev_handle;
struct udev *udev;
struct udev_monitor *udev_mon;
int ref_count;
SDL_UDEV_CallbackList *first, *last;
/* Function pointers */
const char *(*udev_device_get_action)(struct udev_device *); const char *(*udev_device_get_action)(struct udev_device *);
const char *(*udev_device_get_devnode)(struct udev_device *); const char *(*udev_device_get_devnode)(struct udev_device *);
const char *(*udev_device_get_subsystem)(struct udev_device *); const char *(*udev_device_get_subsystem)(struct udev_device *);
@ -100,6 +91,19 @@ typedef struct SDL_UDEV_PrivateData
void (*udev_unref)(struct udev *); void (*udev_unref)(struct udev *);
struct udev_device * (*udev_device_new_from_devnum)(struct udev *udev, char type, dev_t devnum); struct udev_device * (*udev_device_new_from_devnum)(struct udev *udev, char type, dev_t devnum);
dev_t (*udev_device_get_devnum) (struct udev_device *udev_device); dev_t (*udev_device_get_devnum) (struct udev_device *udev_device);
} SDL_UDEV_Symbols;
typedef struct SDL_UDEV_PrivateData
{
const char *udev_library;
void *udev_handle;
struct udev *udev;
struct udev_monitor *udev_mon;
int ref_count;
SDL_UDEV_CallbackList *first, *last;
/* Function pointers */
SDL_UDEV_Symbols syms;
} SDL_UDEV_PrivateData; } SDL_UDEV_PrivateData;
extern int SDL_UDEV_Init(void); extern int SDL_UDEV_Init(void);
@ -110,8 +114,8 @@ extern void SDL_UDEV_Poll(void);
extern void SDL_UDEV_Scan(void); extern void SDL_UDEV_Scan(void);
extern int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb); extern int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb);
extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb); extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
extern const SDL_UDEV_Symbols *SDL_UDEV_GetUdevSyms(void);
extern void SDL_UDEV_ReleaseUdevSyms(void);
#endif /* HAVE_LIBUDEV_H */ #endif /* HAVE_LIBUDEV_H */

View File

@ -97,6 +97,10 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
static SDL_HIDAPI_Device *SDL_HIDAPI_devices; static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
static int SDL_HIDAPI_numjoysticks = 0; static int SDL_HIDAPI_numjoysticks = 0;
#if defined(SDL_USE_LIBUDEV)
static const SDL_UDEV_Symbols * usyms = NULL;
#endif
static struct static struct
{ {
SDL_bool m_bHaveDevicesChanged; SDL_bool m_bHaveDevicesChanged;
@ -272,12 +276,15 @@ HIDAPI_InitializeDiscovery()
SDL_HIDAPI_discovery.m_pUdevMonitor = NULL; SDL_HIDAPI_discovery.m_pUdevMonitor = NULL;
SDL_HIDAPI_discovery.m_nUdevFd = -1; SDL_HIDAPI_discovery.m_nUdevFd = -1;
SDL_HIDAPI_discovery.m_pUdev = udev_new(); usyms = SDL_UDEV_GetUdevSyms();
if (usyms) {
SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new();
}
if (SDL_HIDAPI_discovery.m_pUdev) { if (SDL_HIDAPI_discovery.m_pUdev) {
SDL_HIDAPI_discovery.m_pUdevMonitor = udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev"); SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev");
if (SDL_HIDAPI_discovery.m_pUdevMonitor) { if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor); usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor);
SDL_HIDAPI_discovery.m_nUdevFd = udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor); SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor);
SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE; SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
} }
} }
@ -339,9 +346,9 @@ HIDAPI_UpdateDiscovery()
SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE; SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
pUdevDevice = udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor); pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor);
if (pUdevDevice) { if (pUdevDevice) {
udev_device_unref(pUdevDevice); usyms->udev_device_unref(pUdevDevice);
} }
} }
} }
@ -370,10 +377,14 @@ HIDAPI_ShutdownDiscovery()
#if defined(SDL_USE_LIBUDEV) #if defined(SDL_USE_LIBUDEV)
if (SDL_HIDAPI_discovery.m_pUdevMonitor) { if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor); usyms->udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor);
} }
if (SDL_HIDAPI_discovery.m_pUdev) { if (SDL_HIDAPI_discovery.m_pUdev) {
udev_unref(SDL_HIDAPI_discovery.m_pUdev); usyms->udev_unref(SDL_HIDAPI_discovery.m_pUdev);
}
if (usyms) {
SDL_UDEV_ReleaseUdevSyms();
usyms = NULL;
} }
#endif #endif
} }