52
52
#define SYN_DROPPED 3
56
* !!! FIXME: move all the udev stuff to src/core/linux, so I can reuse it
57
* !!! FIXME: for audio hardware disconnects.
60
#define SDL_USE_LIBUDEV 1
61
#include "SDL_loadso.h"
64
#include <sys/types.h>
66
/* we never link directly to libudev. */
67
/* !!! FIXME: can we generalize this? ALSA, etc, do the same things. */
68
static const char *udev_library = "libudev.so.0";
69
static void *udev_handle = NULL;
71
/* !!! FIXME: this is kinda ugly. */
73
load_udev_sym(const char *fn, void **addr)
75
*addr = SDL_LoadFunction(udev_handle, fn);
77
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
84
/* libudev entry points... */
85
static const char *(*UDEV_udev_device_get_action)(struct udev_device *) = NULL;
86
static const char *(*UDEV_udev_device_get_devnode)(struct udev_device *) = NULL;
87
static const char *(*UDEV_udev_device_get_property_value)(struct udev_device *, const char *) = NULL;
88
static struct udev_device *(*UDEV_udev_device_new_from_syspath)(struct udev *, const char *) = NULL;
89
static void (*UDEV_udev_device_unref)(struct udev_device *) = NULL;
90
static int (*UDEV_udev_enumerate_add_match_property)(struct udev_enumerate *, const char *, const char *) = NULL;
91
static int (*UDEV_udev_enumerate_add_match_subsystem)(struct udev_enumerate *, const char *) = NULL;
92
static struct udev_list_entry *(*UDEV_udev_enumerate_get_list_entry)(struct udev_enumerate *) = NULL;
93
static struct udev_enumerate *(*UDEV_udev_enumerate_new)(struct udev *) = NULL;
94
static int (*UDEV_udev_enumerate_scan_devices)(struct udev_enumerate *) = NULL;
95
static void (*UDEV_udev_enumerate_unref)(struct udev_enumerate *) = NULL;
96
static const char *(*UDEV_udev_list_entry_get_name)(struct udev_list_entry *) = NULL;
97
static struct udev_list_entry *(*UDEV_udev_list_entry_get_next)(struct udev_list_entry *) = NULL;
98
static int (*UDEV_udev_monitor_enable_receiving)(struct udev_monitor *) = NULL;
99
static int (*UDEV_udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor *, const char *, const char *) = NULL;
100
static int (*UDEV_udev_monitor_get_fd)(struct udev_monitor *) = NULL;
101
static struct udev_monitor *(*UDEV_udev_monitor_new_from_netlink)(struct udev *, const char *) = NULL;
102
static struct udev_device *(*UDEV_udev_monitor_receive_device)(struct udev_monitor *) = NULL;
103
static void (*UDEV_udev_monitor_unref)(struct udev_monitor *) = NULL;
104
static struct udev *(*UDEV_udev_new)(void) = NULL;
105
static void (*UDEV_udev_unref)(struct udev *) = NULL;
110
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
111
#define SDL_UDEV_SYM(x) \
112
if (!load_udev_sym(#x, (void **) (char *) &UDEV_##x)) return -1
114
SDL_UDEV_SYM(udev_device_get_action);
115
SDL_UDEV_SYM(udev_device_get_devnode);
116
SDL_UDEV_SYM(udev_device_get_property_value);
117
SDL_UDEV_SYM(udev_device_new_from_syspath);
118
SDL_UDEV_SYM(udev_device_unref);
119
SDL_UDEV_SYM(udev_enumerate_add_match_property);
120
SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
121
SDL_UDEV_SYM(udev_enumerate_get_list_entry);
122
SDL_UDEV_SYM(udev_enumerate_new);
123
SDL_UDEV_SYM(udev_enumerate_scan_devices);
124
SDL_UDEV_SYM(udev_enumerate_unref);
125
SDL_UDEV_SYM(udev_list_entry_get_name);
126
SDL_UDEV_SYM(udev_list_entry_get_next);
127
SDL_UDEV_SYM(udev_monitor_enable_receiving);
128
SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
129
SDL_UDEV_SYM(udev_monitor_get_fd);
130
SDL_UDEV_SYM(udev_monitor_new_from_netlink);
131
SDL_UDEV_SYM(udev_monitor_receive_device);
132
SDL_UDEV_SYM(udev_monitor_unref);
133
SDL_UDEV_SYM(udev_new);
134
SDL_UDEV_SYM(udev_unref);
142
UnloadUDEVLibrary(void)
144
if (udev_handle != NULL) {
145
SDL_UnloadObject(udev_handle);
151
LoadUDEVLibrary(void)
154
if (udev_handle == NULL) {
155
udev_handle = SDL_LoadObject(udev_library);
156
if (udev_handle == NULL) {
158
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
160
retval = load_udev_syms();
170
static struct udev *udev = NULL;
171
static struct udev_monitor *udev_mon = NULL;
55
#include "../../core/linux/SDL_udev.h"
57
static int MaybeAddDevice(const char *path);
59
static int MaybeRemoveDevice(const char *path);
60
void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
61
#endif /* SDL_USE_LIBUDEV */
175
64
/* A linked list of available joysticks */
381
327
JoystickInitWithUdev(void)
383
struct udev_enumerate *enumerate = NULL;
384
struct udev_list_entry *devs = NULL;
385
struct udev_list_entry *item = NULL;
387
SDL_assert(udev == NULL);
388
udev = UDEV_udev_new();
390
return SDL_SetError("udev_new() failed");
393
udev_mon = UDEV_udev_monitor_new_from_netlink(udev, "udev");
394
if (udev_mon != NULL) { /* okay if it's NULL, we just lose hotplugging. */
395
UDEV_udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
397
UDEV_udev_monitor_enable_receiving(udev_mon);
400
enumerate = UDEV_udev_enumerate_new(udev);
401
if (enumerate == NULL) {
402
return SDL_SetError("udev_enumerate_new() failed");
405
UDEV_udev_enumerate_add_match_subsystem(enumerate, "input");
406
UDEV_udev_enumerate_add_match_property(enumerate, "ID_INPUT_JOYSTICK", "1");
407
UDEV_udev_enumerate_scan_devices(enumerate);
408
devs = UDEV_udev_enumerate_get_list_entry(enumerate);
409
for (item = devs; item; item = UDEV_udev_list_entry_get_next(item)) {
410
const char *path = UDEV_udev_list_entry_get_name(item);
411
struct udev_device *dev = UDEV_udev_device_new_from_syspath(udev, path);
412
MaybeAddDevice(UDEV_udev_device_get_devnode(dev));
413
UDEV_udev_device_unref(dev);
416
UDEV_udev_enumerate_unref(enumerate);
330
if (SDL_UDEV_Init() < 0) {
331
return SDL_SetError("Could not initialize UDEV");
334
/* Set up the udev callback */
335
if ( SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
337
return SDL_SetError("Could not set up joystick <-> udev callback");
340
/* Force a scan to build the initial device list */
418
343
return numjoysticks;
452
375
return numjoysticks;
456
HotplugUpdateAvailable(void)
459
if (udev_mon != NULL) {
460
const int fd = UDEV_udev_monitor_get_fd(udev_mon);
468
if ((select(fd+1, &fds, NULL, NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
477
378
void SDL_SYS_JoystickDetect()
479
380
#if SDL_USE_LIBUDEV
480
struct udev_device *dev = NULL;
481
const char *devnode = NULL;
482
const char *action = NULL;
483
const char *val = NULL;
485
while (HotplugUpdateAvailable()) {
486
dev = UDEV_udev_monitor_receive_device(udev_mon);
490
val = UDEV_udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
491
if ((!val) || (SDL_strcmp(val, "1") != 0)) {
495
action = UDEV_udev_device_get_action(dev);
496
devnode = UDEV_udev_device_get_devnode(dev);
498
if (SDL_strcmp(action, "add") == 0) {
499
const int device_index = MaybeAddDevice(devnode);
500
if (device_index != -1) {
501
/* !!! FIXME: Move this to an SDL_PrivateJoyDeviceAdded() function? */
502
#if !SDL_EVENTS_DISABLED
504
event.type = SDL_JOYDEVICEADDED;
506
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
507
event.jdevice.which = device_index;
508
if ( (SDL_EventOK == NULL) ||
509
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
510
SDL_PushEvent(&event);
513
#endif /* !SDL_EVENTS_DISABLED */
515
} else if (SDL_strcmp(action, "remove") == 0) {
516
const int inst = MaybeRemoveDevice(devnode);
518
/* !!! FIXME: Move this to an SDL_PrivateJoyDeviceRemoved() function? */
519
#if !SDL_EVENTS_DISABLED
521
event.type = SDL_JOYDEVICEREMOVED;
523
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
524
event.jdevice.which = inst;
525
if ( (SDL_EventOK == NULL) ||
526
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
527
SDL_PushEvent(&event);
530
#endif /* !SDL_EVENTS_DISABLED */
533
UDEV_udev_device_unref(dev);
538
386
SDL_bool SDL_SYS_JoystickNeedsPolling()
541
* This results in a select() call, so technically we're polling to
542
* decide if we should poll, but I think this function is here because
543
* Windows has to do an enormous amount of work to detect new sticks,
544
* whereas libudev just needs to see if there's more data available on
545
* a socket...so this should be acceptable, I hope.
547
return HotplugUpdateAvailable();
550
395
static SDL_joylist_item *