| | |
| | | /* This is the Linux implementation of the SDL joystick API */ |
| | | |
| | | #include <sys/stat.h> |
| | | #include <unistd.h> |
| | | #include <errno.h> /* errno, strerror */ |
| | | #include <fcntl.h> |
| | | #include <sys/ioctl.h> |
| | | #include <limits.h> /* For the definition of PATH_MAX */ |
| | | #include <sys/ioctl.h> |
| | | #include <unistd.h> |
| | | #include <linux/joystick.h> |
| | | |
| | | #include "SDL_assert.h" |
| | |
| | | #include "../SDL_joystick_c.h" |
| | | #include "../steam/SDL_steamcontroller.h" |
| | | #include "SDL_sysjoystick_c.h" |
| | | #include "../hidapi/SDL_hidapijoystick_c.h" |
| | | |
| | | /* This isn't defined in older Linux kernel headers */ |
| | | #ifndef SYN_DROPPED |
| | |
| | | static SDL_joylist_item *SDL_joylist = NULL; |
| | | static SDL_joylist_item *SDL_joylist_tail = NULL; |
| | | static int numjoysticks = 0; |
| | | static int instance_counter = 0; |
| | | |
| | | |
| | | #define test_bit(nr, addr) \ |
| | |
| | | return 0; |
| | | } |
| | | |
| | | #ifdef SDL_JOYSTICK_HIDAPI |
| | | if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version)) { |
| | | /* The HIDAPI driver is taking care of this device */ |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | | /* Check the joystick blacklist */ |
| | | id = MAKE_VIDPID(inpid.vendor, inpid.product); |
| | | for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) { |
| | |
| | | SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4); |
| | | } |
| | | |
| | | if (SDL_IsGameControllerNameAndGUID(namebuf, *guid) && |
| | | SDL_ShouldIgnoreGameController(namebuf, *guid)) { |
| | | if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) { |
| | | return 0; |
| | | } |
| | | return 1; |
| | |
| | | item->name = SDL_strdup(namebuf); |
| | | item->guid = guid; |
| | | |
| | | if ( (item->path == NULL) || (item->name == NULL) ) { |
| | | if ((item->path == NULL) || (item->name == NULL)) { |
| | | SDL_free(item->path); |
| | | SDL_free(item->name); |
| | | SDL_free(item); |
| | | return -1; |
| | | } |
| | | |
| | | item->device_instance = instance_counter++; |
| | | item->device_instance = SDL_GetNextJoystickInstanceID(); |
| | | if (SDL_joylist_tail == NULL) { |
| | | SDL_joylist = SDL_joylist_tail = item; |
| | | } else { |
| | |
| | | /* Need to increment the joystick count before we post the event */ |
| | | ++numjoysticks; |
| | | |
| | | SDL_PrivateJoystickAdded(numjoysticks - 1); |
| | | SDL_PrivateJoystickAdded(item->device_instance); |
| | | |
| | | return numjoysticks; |
| | | } |
| | |
| | | MaybeAddDevice(path); |
| | | } |
| | | |
| | | return numjoysticks; |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | |
| | | /* Force a scan to build the initial device list */ |
| | | SDL_UDEV_Scan(); |
| | | |
| | | return numjoysticks; |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | |
| | | return SDL_FALSE; |
| | | } |
| | | |
| | | *device_instance = item->device_instance = instance_counter++; |
| | | *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID(); |
| | | if (SDL_joylist_tail == NULL) { |
| | | SDL_joylist = SDL_joylist_tail = item; |
| | | } else { |
| | |
| | | /* Need to increment the joystick count before we post the event */ |
| | | ++numjoysticks; |
| | | |
| | | SDL_PrivateJoystickAdded(numjoysticks - 1); |
| | | SDL_PrivateJoystickAdded(item->device_instance); |
| | | |
| | | return SDL_TRUE; |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | int |
| | | SDL_SYS_JoystickInit(void) |
| | | static int |
| | | LINUX_JoystickInit(void) |
| | | { |
| | | /* First see if the user specified one or more joysticks to use */ |
| | | if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) { |
| | |
| | | #endif |
| | | } |
| | | |
| | | int |
| | | SDL_SYS_NumJoysticks(void) |
| | | static int |
| | | LINUX_JoystickGetCount(void) |
| | | { |
| | | return numjoysticks; |
| | | } |
| | | |
| | | void |
| | | SDL_SYS_JoystickDetect(void) |
| | | static void |
| | | LINUX_JoystickDetect(void) |
| | | { |
| | | #if SDL_USE_LIBUDEV |
| | | SDL_UDEV_Poll(); |
| | |
| | | } |
| | | |
| | | /* Function to get the device-dependent name of a joystick */ |
| | | const char * |
| | | SDL_SYS_JoystickNameForDeviceIndex(int device_index) |
| | | static const char * |
| | | LINUX_JoystickGetDeviceName(int device_index) |
| | | { |
| | | return JoystickByDevIndex(device_index)->name; |
| | | } |
| | | |
| | | static int |
| | | LINUX_JoystickGetDevicePlayerIndex(int device_index) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | static SDL_JoystickGUID |
| | | LINUX_JoystickGetDeviceGUID( int device_index ) |
| | | { |
| | | return JoystickByDevIndex(device_index)->guid; |
| | | } |
| | | |
| | | /* Function to perform the mapping from device index to the instance id for this index */ |
| | | SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) |
| | | static SDL_JoystickID |
| | | LINUX_JoystickGetDeviceInstanceID(int device_index) |
| | | { |
| | | return JoystickByDevIndex(device_index)->device_instance; |
| | | } |
| | |
| | | unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; |
| | | unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; |
| | | unsigned long relbit[NBITS(REL_MAX)] = { 0 }; |
| | | unsigned long ffbit[NBITS(FF_MAX)] = { 0 }; |
| | | |
| | | /* See if this device uses the new unified event API */ |
| | | if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) { |
| | | if (test_bit(FF_RUMBLE, ffbit)) { |
| | | joystick->hwdata->ff_rumble = SDL_TRUE; |
| | | } |
| | | if (test_bit(FF_SINE, ffbit)) { |
| | | joystick->hwdata->ff_sine = SDL_TRUE; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | This should fill the nbuttons and naxes fields of the joystick structure. |
| | | It returns 0, or -1 if there is an error. |
| | | */ |
| | | int |
| | | SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) |
| | | static int |
| | | LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index) |
| | | { |
| | | SDL_joylist_item *item = JoystickByDevIndex(device_index); |
| | | |
| | |
| | | } |
| | | joystick->hwdata->item = item; |
| | | joystick->hwdata->guid = item->guid; |
| | | joystick->hwdata->effect.id = -1; |
| | | joystick->hwdata->m_bSteamController = item->m_bSteamController; |
| | | |
| | | if (item->m_bSteamController) { |
| | |
| | | &joystick->naxes, |
| | | &joystick->nhats); |
| | | } else { |
| | | int fd = open(item->path, O_RDONLY, 0); |
| | | int fd = open(item->path, O_RDWR, 0); |
| | | if (fd < 0) { |
| | | SDL_free(joystick->hwdata); |
| | | joystick->hwdata = NULL; |
| | |
| | | return (0); |
| | | } |
| | | |
| | | /* Function to determine if this joystick is attached to the system right now */ |
| | | SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) |
| | | static int |
| | | LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) |
| | | { |
| | | return joystick->hwdata->item != NULL; |
| | | struct input_event event; |
| | | |
| | | if (joystick->hwdata->ff_rumble) { |
| | | struct ff_effect *effect = &joystick->hwdata->effect; |
| | | |
| | | effect->type = FF_RUMBLE; |
| | | effect->replay.length = SDL_min(duration_ms, 32767); |
| | | effect->u.rumble.strong_magnitude = low_frequency_rumble; |
| | | effect->u.rumble.weak_magnitude = high_frequency_rumble; |
| | | } else if (joystick->hwdata->ff_sine) { |
| | | /* Scale and average the two rumble strengths */ |
| | | Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2); |
| | | struct ff_effect *effect = &joystick->hwdata->effect; |
| | | |
| | | effect->type = FF_PERIODIC; |
| | | effect->replay.length = SDL_min(duration_ms, 32767); |
| | | effect->u.periodic.waveform = FF_SINE; |
| | | effect->u.periodic.magnitude = magnitude; |
| | | } else { |
| | | return SDL_Unsupported(); |
| | | } |
| | | |
| | | if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) { |
| | | return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno)); |
| | | } |
| | | |
| | | event.type = EV_FF; |
| | | event.code = joystick->hwdata->effect.id; |
| | | event.value = 1; |
| | | if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) { |
| | | return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno)); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static SDL_INLINE void |
| | |
| | | } |
| | | } |
| | | |
| | | void |
| | | SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) |
| | | static void |
| | | LINUX_JoystickUpdate(SDL_Joystick * joystick) |
| | | { |
| | | int i; |
| | | |
| | |
| | | } |
| | | |
| | | /* Function to close a joystick after use */ |
| | | void |
| | | SDL_SYS_JoystickClose(SDL_Joystick * joystick) |
| | | static void |
| | | LINUX_JoystickClose(SDL_Joystick * joystick) |
| | | { |
| | | if (joystick->hwdata) { |
| | | if (joystick->hwdata->effect.id >= 0) { |
| | | ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id); |
| | | joystick->hwdata->effect.id = -1; |
| | | } |
| | | if (joystick->hwdata->fd >= 0) { |
| | | close(joystick->hwdata->fd); |
| | | } |
| | |
| | | } |
| | | |
| | | /* Function to perform any system-specific joystick related cleanup */ |
| | | void |
| | | SDL_SYS_JoystickQuit(void) |
| | | static void |
| | | LINUX_JoystickQuit(void) |
| | | { |
| | | SDL_joylist_item *item = NULL; |
| | | SDL_joylist_item *next = NULL; |
| | |
| | | SDL_joylist = SDL_joylist_tail = NULL; |
| | | |
| | | numjoysticks = 0; |
| | | instance_counter = 0; |
| | | |
| | | #if SDL_USE_LIBUDEV |
| | | SDL_UDEV_DelCallback(joystick_udev_callback); |
| | |
| | | SDL_QuitSteamControllers(); |
| | | } |
| | | |
| | | SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) |
| | | SDL_JoystickDriver SDL_LINUX_JoystickDriver = |
| | | { |
| | | return JoystickByDevIndex(device_index)->guid; |
| | | } |
| | | |
| | | SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) |
| | | { |
| | | return joystick->hwdata->guid; |
| | | } |
| | | LINUX_JoystickInit, |
| | | LINUX_JoystickGetCount, |
| | | LINUX_JoystickDetect, |
| | | LINUX_JoystickGetDeviceName, |
| | | LINUX_JoystickGetDevicePlayerIndex, |
| | | LINUX_JoystickGetDeviceGUID, |
| | | LINUX_JoystickGetDeviceInstanceID, |
| | | LINUX_JoystickOpen, |
| | | LINUX_JoystickRumble, |
| | | LINUX_JoystickUpdate, |
| | | LINUX_JoystickClose, |
| | | LINUX_JoystickQuit, |
| | | }; |
| | | |
| | | #endif /* SDL_JOYSTICK_LINUX */ |
| | | |