zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_udev.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /*
23  * To list the properties of a device, try something like:
24  * udevadm info -a -n snd/hwC0D0 (for a sound card)
25  * udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc)
26  * udevadm info --query=property -n input/event2
27  */
28 
29 #include "SDL_udev.h"
30 
31 #ifdef SDL_USE_LIBUDEV
32 
33 static char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
34 
35 #define _THIS SDL_UDEV_PrivateData *_this
36 static _THIS = NULL;
37 
38 #include "SDL.h"
39 
40 static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr);
41 static int SDL_UDEV_load_syms(void);
42 static SDL_bool SDL_UDEV_hotplug_update_available(void);
43 static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev);
44 
45 static SDL_bool
46 SDL_UDEV_load_sym(const char *fn, void **addr)
47 {
48  *addr = SDL_LoadFunction(_this->udev_handle, fn);
49  if (*addr == NULL) {
50  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
51  return SDL_FALSE;
52  }
53 
54  return SDL_TRUE;
55 }
56 
57 static int
58 SDL_UDEV_load_syms(void)
59 {
60  /* cast funcs to char* first, to please GCC's strict aliasing rules. */
61  #define SDL_UDEV_SYM(x) \
62  if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->x)) return -1
63 
64  SDL_UDEV_SYM(udev_device_get_action);
65  SDL_UDEV_SYM(udev_device_get_devnode);
66  SDL_UDEV_SYM(udev_device_get_subsystem);
67  SDL_UDEV_SYM(udev_device_get_property_value);
68  SDL_UDEV_SYM(udev_device_new_from_syspath);
69  SDL_UDEV_SYM(udev_device_unref);
70  SDL_UDEV_SYM(udev_enumerate_add_match_property);
71  SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
72  SDL_UDEV_SYM(udev_enumerate_get_list_entry);
73  SDL_UDEV_SYM(udev_enumerate_new);
74  SDL_UDEV_SYM(udev_enumerate_scan_devices);
75  SDL_UDEV_SYM(udev_enumerate_unref);
76  SDL_UDEV_SYM(udev_list_entry_get_name);
77  SDL_UDEV_SYM(udev_list_entry_get_next);
78  SDL_UDEV_SYM(udev_monitor_enable_receiving);
79  SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
80  SDL_UDEV_SYM(udev_monitor_get_fd);
81  SDL_UDEV_SYM(udev_monitor_new_from_netlink);
82  SDL_UDEV_SYM(udev_monitor_receive_device);
83  SDL_UDEV_SYM(udev_monitor_unref);
84  SDL_UDEV_SYM(udev_new);
85  SDL_UDEV_SYM(udev_unref);
86  SDL_UDEV_SYM(udev_device_new_from_devnum);
87  SDL_UDEV_SYM(udev_device_get_devnum);
88  #undef SDL_UDEV_SYM
89 
90  return 0;
91 }
92 
93 static SDL_bool
94 SDL_UDEV_hotplug_update_available(void)
95 {
96  if (_this->udev_mon != NULL) {
97  const int fd = _this->udev_monitor_get_fd(_this->udev_mon);
98  fd_set fds;
99  struct timeval tv;
100 
101  FD_ZERO(&fds);
102  FD_SET(fd, &fds);
103  tv.tv_sec = 0;
104  tv.tv_usec = 0;
105  if ((select(fd+1, &fds, NULL, NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
106  return SDL_TRUE;
107  }
108  }
109  return SDL_FALSE;
110 }
111 
112 
113 int
114 SDL_UDEV_Init(void)
115 {
116  int retval = 0;
117 
118  if (_this == NULL) {
119  _this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
120  if(_this == NULL) {
121  return SDL_OutOfMemory();
122  }
123 
124  retval = SDL_UDEV_LoadLibrary();
125  if (retval < 0) {
126  SDL_UDEV_Quit();
127  return retval;
128  }
129 
130  /* Set up udev monitoring
131  * Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
132  */
133 
134  _this->udev = _this->udev_new();
135  if (_this->udev == NULL) {
136  SDL_UDEV_Quit();
137  return SDL_SetError("udev_new() failed");
138  }
139 
140  _this->udev_mon = _this->udev_monitor_new_from_netlink(_this->udev, "udev");
141  if (_this->udev_mon == NULL) {
142  SDL_UDEV_Quit();
143  return SDL_SetError("udev_monitor_new_from_netlink() failed");
144  }
145 
146  _this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
147  _this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
148  _this->udev_monitor_enable_receiving(_this->udev_mon);
149 
150  /* Do an initial scan of existing devices */
151  SDL_UDEV_Scan();
152 
153  }
154 
155  _this->ref_count += 1;
156 
157  return retval;
158 }
159 
160 void
161 SDL_UDEV_Quit(void)
162 {
163  SDL_UDEV_CallbackList *item;
164 
165  if (_this == NULL) {
166  return;
167  }
168 
169  _this->ref_count -= 1;
170 
171  if (_this->ref_count < 1) {
172 
173  if (_this->udev_mon != NULL) {
174  _this->udev_monitor_unref(_this->udev_mon);
175  _this->udev_mon = NULL;
176  }
177  if (_this->udev != NULL) {
178  _this->udev_unref(_this->udev);
179  _this->udev = NULL;
180  }
181 
182  /* Remove existing devices */
183  while (_this->first != NULL) {
184  item = _this->first;
185  _this->first = _this->first->next;
186  SDL_free(item);
187  }
188 
189  SDL_UDEV_UnloadLibrary();
190  SDL_free(_this);
191  _this = NULL;
192  }
193 }
194 
195 void
196 SDL_UDEV_Scan(void)
197 {
198  struct udev_enumerate *enumerate = NULL;
199  struct udev_list_entry *devs = NULL;
200  struct udev_list_entry *item = NULL;
201 
202  if (_this == NULL) {
203  return;
204  }
205 
206  enumerate = _this->udev_enumerate_new(_this->udev);
207  if (enumerate == NULL) {
208  SDL_UDEV_Quit();
209  SDL_SetError("udev_monitor_new_from_netlink() failed");
210  return;
211  }
212 
213  _this->udev_enumerate_add_match_subsystem(enumerate, "input");
214  _this->udev_enumerate_add_match_subsystem(enumerate, "sound");
215 
216  _this->udev_enumerate_scan_devices(enumerate);
217  devs = _this->udev_enumerate_get_list_entry(enumerate);
218  for (item = devs; item; item = _this->udev_list_entry_get_next(item)) {
219  const char *path = _this->udev_list_entry_get_name(item);
220  struct udev_device *dev = _this->udev_device_new_from_syspath(_this->udev, path);
221  if (dev != NULL) {
222  device_event(SDL_UDEV_DEVICEADDED, dev);
223  _this->udev_device_unref(dev);
224  }
225  }
226 
227  _this->udev_enumerate_unref(enumerate);
228 }
229 
230 
231 void
232 SDL_UDEV_UnloadLibrary(void)
233 {
234  if (_this == NULL) {
235  return;
236  }
237 
238  if (_this->udev_handle != NULL) {
239  SDL_UnloadObject(_this->udev_handle);
240  _this->udev_handle = NULL;
241  }
242 }
243 
244 int
245 SDL_UDEV_LoadLibrary(void)
246 {
247  int retval = 0, i;
248 
249  if (_this == NULL) {
250  return SDL_SetError("UDEV not initialized");
251  }
252 
253 
254  if (_this->udev_handle == NULL) {
255  for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
256  _this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
257  if (_this->udev_handle != NULL) {
258  retval = SDL_UDEV_load_syms();
259  if (retval < 0) {
260  SDL_UDEV_UnloadLibrary();
261  }
262  else {
263  break;
264  }
265  }
266  }
267 
268  if (_this->udev_handle == NULL) {
269  retval = -1;
270  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
271  }
272  }
273 
274  return retval;
275 }
276 
277 static void
278 device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
279 {
280  const char *subsystem;
281  const char *val = NULL;
282  SDL_UDEV_deviceclass devclass = 0;
283  const char *path;
284  SDL_UDEV_CallbackList *item;
285 
286  path = _this->udev_device_get_devnode(dev);
287  if (path == NULL) {
288  return;
289  }
290 
291  subsystem = _this->udev_device_get_subsystem(dev);
292  if (SDL_strcmp(subsystem, "sound") == 0) {
293  devclass = SDL_UDEV_DEVICE_SOUND;
294  }
295  else if (SDL_strcmp(subsystem, "input") == 0) {
296  val = _this->udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
297  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
298  devclass = SDL_UDEV_DEVICE_JOYSTICK;
299  }
300 
301  if (devclass == 0) {
302  val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
303  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
304  devclass = SDL_UDEV_DEVICE_MOUSE;
305  }
306  }
307 
308  if (devclass == 0) {
309  val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD");
310  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
311  devclass = SDL_UDEV_DEVICE_KEYBOARD;
312  }
313  }
314 
315  if (devclass == 0) {
316  return;
317  }
318  }
319  else {
320  return;
321  }
322 
323  /* Process callbacks */
324  for (item = _this->first; item != NULL; item = item->next) {
325  item->callback(type, devclass, path);
326  }
327 }
328 
329 void
330 SDL_UDEV_Poll(void)
331 {
332  struct udev_device *dev = NULL;
333  const char *action = NULL;
334 
335  if (_this == NULL) {
336  return;
337  }
338 
339  while (SDL_UDEV_hotplug_update_available()) {
340  dev = _this->udev_monitor_receive_device(_this->udev_mon);
341  if (dev == NULL) {
342  break;
343  }
344  action = _this->udev_device_get_action(dev);
345 
346  if (SDL_strcmp(action, "add") == 0) {
347  device_event(SDL_UDEV_DEVICEADDED, dev);
348  } else if (SDL_strcmp(action, "remove") == 0) {
349  device_event(SDL_UDEV_DEVICEREMOVED, dev);
350  }
351 
352  _this->udev_device_unref(dev);
353  }
354 }
355 
356 int
357 SDL_UDEV_AddCallback(SDL_UDEV_Callback cb)
358 {
359  SDL_UDEV_CallbackList *item;
360  item = (SDL_UDEV_CallbackList *) SDL_calloc(1, sizeof (SDL_UDEV_CallbackList));
361  if (item == NULL) {
362  return SDL_OutOfMemory();
363  }
364 
365  item->callback = cb;
366 
367  if (_this->last == NULL) {
368  _this->first = _this->last = item;
369  } else {
370  _this->last->next = item;
371  _this->last = item;
372  }
373 
374  return 1;
375 }
376 
377 void
378 SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
379 {
380  SDL_UDEV_CallbackList *item;
381  SDL_UDEV_CallbackList *prev = NULL;
382 
383  for (item = _this->first; item != NULL; item = item->next) {
384  /* found it, remove it. */
385  if (item->callback == cb) {
386  if (prev != NULL) {
387  prev->next = item->next;
388  } else {
389  SDL_assert(_this->first == item);
390  _this->first = item->next;
391  }
392  if (item == _this->last) {
393  _this->last = prev;
394  }
395  SDL_free(item);
396  return;
397  }
398  prev = item;
399  }
400 
401 }
402 
403 
404 #endif /* SDL_USE_LIBUDEV */
GLuint const GLfloat * val
Definition: glew.h:2715
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
DECLSPEC void *SDLCALL SDL_calloc(size_t nmemb, size_t size)
#define NULL
Definition: ftobjs.h:61
GLenum GLvoid * addr
Definition: glew.h:10667
SDL_bool
Definition: SDL_stdinc.h:116
DECLSPEC void SDLCALL SDL_free(void *mem)
GLsizei const GLchar *const * path
Definition: glew.h:5828
static SDL_VideoDevice * _this
Definition: SDL_video.c:92
#define _THIS
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
Definition: SDL_string.c:910
#define SDL_assert(condition)
Definition: SDL_assert.h:159
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:83
int i
Definition: pngrutil.c:1377
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)