SDL  2.0
SDL_udev.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #include "SDL_udev.h"
29 
30 #ifdef SDL_USE_LIBUDEV
31 
32 #include <linux/input.h>
33 
34 #include "SDL_assert.h"
35 #include "SDL_evdev_capabilities.h"
36 #include "SDL_loadso.h"
37 #include "SDL_timer.h"
38 #include "SDL_hints.h"
39 #include "../unix/SDL_poll.h"
40 
41 static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
42 
43 #define _THIS SDL_UDEV_PrivateData *_this
44 static _THIS = NULL;
45 
46 static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr);
47 static int SDL_UDEV_load_syms(void);
48 static SDL_bool SDL_UDEV_hotplug_update_available(void);
49 static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev);
50 
51 static SDL_bool
52 SDL_UDEV_load_sym(const char *fn, void **addr)
53 {
54  *addr = SDL_LoadFunction(_this->udev_handle, fn);
55  if (*addr == NULL) {
56  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
57  return SDL_FALSE;
58  }
59 
60  return SDL_TRUE;
61 }
62 
63 static int
64 SDL_UDEV_load_syms(void)
65 {
66  /* cast funcs to char* first, to please GCC's strict aliasing rules. */
67  #define SDL_UDEV_SYM(x) \
68  if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->syms.x)) return -1
69 
70  SDL_UDEV_SYM(udev_device_get_action);
71  SDL_UDEV_SYM(udev_device_get_devnode);
72  SDL_UDEV_SYM(udev_device_get_subsystem);
73  SDL_UDEV_SYM(udev_device_get_parent_with_subsystem_devtype);
74  SDL_UDEV_SYM(udev_device_get_property_value);
75  SDL_UDEV_SYM(udev_device_get_sysattr_value);
76  SDL_UDEV_SYM(udev_device_new_from_syspath);
77  SDL_UDEV_SYM(udev_device_unref);
78  SDL_UDEV_SYM(udev_enumerate_add_match_property);
79  SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
80  SDL_UDEV_SYM(udev_enumerate_get_list_entry);
81  SDL_UDEV_SYM(udev_enumerate_new);
82  SDL_UDEV_SYM(udev_enumerate_scan_devices);
83  SDL_UDEV_SYM(udev_enumerate_unref);
84  SDL_UDEV_SYM(udev_list_entry_get_name);
85  SDL_UDEV_SYM(udev_list_entry_get_next);
86  SDL_UDEV_SYM(udev_monitor_enable_receiving);
87  SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
88  SDL_UDEV_SYM(udev_monitor_get_fd);
89  SDL_UDEV_SYM(udev_monitor_new_from_netlink);
90  SDL_UDEV_SYM(udev_monitor_receive_device);
91  SDL_UDEV_SYM(udev_monitor_unref);
92  SDL_UDEV_SYM(udev_new);
93  SDL_UDEV_SYM(udev_unref);
94  SDL_UDEV_SYM(udev_device_new_from_devnum);
95  SDL_UDEV_SYM(udev_device_get_devnum);
96  #undef SDL_UDEV_SYM
97 
98  return 0;
99 }
100 
101 static SDL_bool
102 SDL_UDEV_hotplug_update_available(void)
103 {
104  if (_this->udev_mon != NULL) {
105  const int fd = _this->syms.udev_monitor_get_fd(_this->udev_mon);
106  if (SDL_IOReady(fd, SDL_FALSE, 0)) {
107  return SDL_TRUE;
108  }
109  }
110  return SDL_FALSE;
111 }
112 
113 
114 int
115 SDL_UDEV_Init(void)
116 {
117  int retval = 0;
118 
119  if (_this == NULL) {
120  _this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
121  if(_this == NULL) {
122  return SDL_OutOfMemory();
123  }
124 
125  retval = SDL_UDEV_LoadLibrary();
126  if (retval < 0) {
127  SDL_UDEV_Quit();
128  return retval;
129  }
130 
131  /* Set up udev monitoring
132  * Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
133  */
134 
135  _this->udev = _this->syms.udev_new();
136  if (_this->udev == NULL) {
137  SDL_UDEV_Quit();
138  return SDL_SetError("udev_new() failed");
139  }
140 
141  _this->udev_mon = _this->syms.udev_monitor_new_from_netlink(_this->udev, "udev");
142  if (_this->udev_mon == NULL) {
143  SDL_UDEV_Quit();
144  return SDL_SetError("udev_monitor_new_from_netlink() failed");
145  }
146 
147  _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
148  _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
149  _this->syms.udev_monitor_enable_receiving(_this->udev_mon);
150 
151  /* Do an initial scan of existing devices */
152  SDL_UDEV_Scan();
153 
154  }
155 
156  _this->ref_count += 1;
157 
158  return retval;
159 }
160 
161 void
162 SDL_UDEV_Quit(void)
163 {
164  SDL_UDEV_CallbackList *item;
165 
166  if (_this == NULL) {
167  return;
168  }
169 
170  _this->ref_count -= 1;
171 
172  if (_this->ref_count < 1) {
173 
174  if (_this->udev_mon != NULL) {
175  _this->syms.udev_monitor_unref(_this->udev_mon);
176  _this->udev_mon = NULL;
177  }
178  if (_this->udev != NULL) {
179  _this->syms.udev_unref(_this->udev);
180  _this->udev = NULL;
181  }
182 
183  /* Remove existing devices */
184  while (_this->first != NULL) {
185  item = _this->first;
186  _this->first = _this->first->next;
187  SDL_free(item);
188  }
189 
190  SDL_UDEV_UnloadLibrary();
191  SDL_free(_this);
192  _this = NULL;
193  }
194 }
195 
196 void
197 SDL_UDEV_Scan(void)
198 {
199  struct udev_enumerate *enumerate = NULL;
200  struct udev_list_entry *devs = NULL;
201  struct udev_list_entry *item = NULL;
202 
203  if (_this == NULL) {
204  return;
205  }
206 
207  enumerate = _this->syms.udev_enumerate_new(_this->udev);
208  if (enumerate == NULL) {
209  SDL_UDEV_Quit();
210  SDL_SetError("udev_enumerate_new() failed");
211  return;
212  }
213 
214  _this->syms.udev_enumerate_add_match_subsystem(enumerate, "input");
215  _this->syms.udev_enumerate_add_match_subsystem(enumerate, "sound");
216 
217  _this->syms.udev_enumerate_scan_devices(enumerate);
218  devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
219  for (item = devs; item; item = _this->syms.udev_list_entry_get_next(item)) {
220  const char *path = _this->syms.udev_list_entry_get_name(item);
221  struct udev_device *dev = _this->syms.udev_device_new_from_syspath(_this->udev, path);
222  if (dev != NULL) {
223  device_event(SDL_UDEV_DEVICEADDED, dev);
224  _this->syms.udev_device_unref(dev);
225  }
226  }
227 
228  _this->syms.udev_enumerate_unref(enumerate);
229 }
230 
231 
232 void
233 SDL_UDEV_UnloadLibrary(void)
234 {
235  if (_this == NULL) {
236  return;
237  }
238 
239  if (_this->udev_handle != NULL) {
240  SDL_UnloadObject(_this->udev_handle);
241  _this->udev_handle = NULL;
242  }
243 }
244 
245 int
246 SDL_UDEV_LoadLibrary(void)
247 {
248  int retval = 0, i;
249 
250  if (_this == NULL) {
251  return SDL_SetError("UDEV not initialized");
252  }
253 
254  /* See if there is a udev library already loaded */
255  if (SDL_UDEV_load_syms() == 0) {
256  return 0;
257  }
258 
259 #ifdef SDL_UDEV_DYNAMIC
260  /* Check for the build environment's libudev first */
261  if (_this->udev_handle == NULL) {
262  _this->udev_handle = SDL_LoadObject(SDL_UDEV_DYNAMIC);
263  if (_this->udev_handle != NULL) {
264  retval = SDL_UDEV_load_syms();
265  if (retval < 0) {
266  SDL_UDEV_UnloadLibrary();
267  }
268  }
269  }
270 #endif
271 
272  if (_this->udev_handle == NULL) {
273  for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
274  _this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
275  if (_this->udev_handle != NULL) {
276  retval = SDL_UDEV_load_syms();
277  if (retval < 0) {
278  SDL_UDEV_UnloadLibrary();
279  }
280  else {
281  break;
282  }
283  }
284  }
285 
286  if (_this->udev_handle == NULL) {
287  retval = -1;
288  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
289  }
290  }
291 
292  return retval;
293 }
294 
295 static void get_caps(struct udev_device *dev, struct udev_device *pdev, const char *attr, unsigned long *bitmask, size_t bitmask_len)
296 {
297  const char *value;
298  char text[4096];
299  char *word;
300  int i;
301  unsigned long v;
302 
303  SDL_memset(bitmask, 0, bitmask_len*sizeof(*bitmask));
304  value = _this->syms.udev_device_get_sysattr_value(pdev, attr);
305  if (!value) {
306  return;
307  }
308 
309  SDL_strlcpy(text, value, sizeof(text));
310  i = 0;
311  while ((word = SDL_strrchr(text, ' ')) != NULL) {
312  v = SDL_strtoul(word+1, NULL, 16);
313  if (i < bitmask_len) {
314  bitmask[i] = v;
315  }
316  ++i;
317  *word = '\0';
318  }
319  v = SDL_strtoul(text, NULL, 16);
320  if (i < bitmask_len) {
321  bitmask[i] = v;
322  }
323 }
324 
325 static int
326 guess_device_class(struct udev_device *dev)
327 {
328  struct udev_device *pdev;
329  unsigned long bitmask_ev[NBITS(EV_MAX)];
330  unsigned long bitmask_abs[NBITS(ABS_MAX)];
331  unsigned long bitmask_key[NBITS(KEY_MAX)];
332  unsigned long bitmask_rel[NBITS(REL_MAX)];
333 
334  /* walk up the parental chain until we find the real input device; the
335  * argument is very likely a subdevice of this, like eventN */
336  pdev = dev;
337  while (pdev && !_this->syms.udev_device_get_sysattr_value(pdev, "capabilities/ev")) {
338  pdev = _this->syms.udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
339  }
340  if (!pdev) {
341  return 0;
342  }
343 
344  get_caps(dev, pdev, "capabilities/ev", bitmask_ev, SDL_arraysize(bitmask_ev));
345  get_caps(dev, pdev, "capabilities/abs", bitmask_abs, SDL_arraysize(bitmask_abs));
346  get_caps(dev, pdev, "capabilities/rel", bitmask_rel, SDL_arraysize(bitmask_rel));
347  get_caps(dev, pdev, "capabilities/key", bitmask_key, SDL_arraysize(bitmask_key));
348 
349  return SDL_EVDEV_GuessDeviceClass(&bitmask_ev[0],
350  &bitmask_abs[0],
351  &bitmask_key[0],
352  &bitmask_rel[0]);
353 }
354 
355 static void
356 device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
357 {
358  const char *subsystem;
359  const char *val = NULL;
360  int devclass = 0;
361  const char *path;
362  SDL_UDEV_CallbackList *item;
363 
364  path = _this->syms.udev_device_get_devnode(dev);
365  if (path == NULL) {
366  return;
367  }
368 
369  subsystem = _this->syms.udev_device_get_subsystem(dev);
370  if (SDL_strcmp(subsystem, "sound") == 0) {
371  devclass = SDL_UDEV_DEVICE_SOUND;
372  } else if (SDL_strcmp(subsystem, "input") == 0) {
373  /* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */
374 
375  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
376  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
377  devclass |= SDL_UDEV_DEVICE_JOYSTICK;
378  }
379 
380  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER");
382  val != NULL && SDL_strcmp(val, "1") == 0 ) {
383  devclass |= SDL_UDEV_DEVICE_JOYSTICK;
384  }
385 
386  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
387  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
388  devclass |= SDL_UDEV_DEVICE_MOUSE;
389  }
390 
391  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
392  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
393  devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN;
394  }
395 
396  /* The undocumented rule is:
397  - All devices with keys get ID_INPUT_KEY
398  - From this subset, if they have ESC, numbers, and Q to D, it also gets ID_INPUT_KEYBOARD
399 
400  Ref: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c#n183
401  */
402  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_KEY");
403  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
404  devclass |= SDL_UDEV_DEVICE_KEYBOARD;
405  }
406 
407  if (devclass == 0) {
408  /* Fall back to old style input classes */
409  val = _this->syms.udev_device_get_property_value(dev, "ID_CLASS");
410  if (val != NULL) {
411  if (SDL_strcmp(val, "joystick") == 0) {
412  devclass = SDL_UDEV_DEVICE_JOYSTICK;
413  } else if (SDL_strcmp(val, "mouse") == 0) {
414  devclass = SDL_UDEV_DEVICE_MOUSE;
415  } else if (SDL_strcmp(val, "kbd") == 0) {
416  devclass = SDL_UDEV_DEVICE_KEYBOARD;
417  } else {
418  return;
419  }
420  } else {
421  /* We could be linked with libudev on a system that doesn't have udev running */
422  devclass = guess_device_class(dev);
423  }
424  }
425  } else {
426  return;
427  }
428 
429  /* Process callbacks */
430  for (item = _this->first; item != NULL; item = item->next) {
431  item->callback(type, devclass, path);
432  }
433 }
434 
435 void
436 SDL_UDEV_Poll(void)
437 {
438  struct udev_device *dev = NULL;
439  const char *action = NULL;
440 
441  if (_this == NULL) {
442  return;
443  }
444 
445  while (SDL_UDEV_hotplug_update_available()) {
446  dev = _this->syms.udev_monitor_receive_device(_this->udev_mon);
447  if (dev == NULL) {
448  break;
449  }
450  action = _this->syms.udev_device_get_action(dev);
451 
452  if (SDL_strcmp(action, "add") == 0) {
453  /* Wait for the device to finish initialization */
454  SDL_Delay(100);
455 
456  device_event(SDL_UDEV_DEVICEADDED, dev);
457  } else if (SDL_strcmp(action, "remove") == 0) {
458  device_event(SDL_UDEV_DEVICEREMOVED, dev);
459  }
460 
461  _this->syms.udev_device_unref(dev);
462  }
463 }
464 
465 int
466 SDL_UDEV_AddCallback(SDL_UDEV_Callback cb)
467 {
468  SDL_UDEV_CallbackList *item;
469  item = (SDL_UDEV_CallbackList *) SDL_calloc(1, sizeof (SDL_UDEV_CallbackList));
470  if (item == NULL) {
471  return SDL_OutOfMemory();
472  }
473 
474  item->callback = cb;
475 
476  if (_this->last == NULL) {
477  _this->first = _this->last = item;
478  } else {
479  _this->last->next = item;
480  _this->last = item;
481  }
482 
483  return 1;
484 }
485 
486 void
487 SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
488 {
489  SDL_UDEV_CallbackList *item;
490  SDL_UDEV_CallbackList *prev = NULL;
491 
492  for (item = _this->first; item != NULL; item = item->next) {
493  /* found it, remove it. */
494  if (item->callback == cb) {
495  if (prev != NULL) {
496  prev->next = item->next;
497  } else {
498  SDL_assert(_this->first == item);
499  _this->first = item->next;
500  }
501  if (item == _this->last) {
502  _this->last = prev;
503  }
504  SDL_free(item);
505  return;
506  }
507  prev = item;
508  }
509 
510 }
511 
512 const SDL_UDEV_Symbols *
513 SDL_UDEV_GetUdevSyms(void)
514 {
515  if (SDL_UDEV_Init() < 0) {
516  SDL_SetError("Could not initialize UDEV");
517  return NULL;
518  }
519 
520  return &_this->syms;
521 }
522 
523 void
524 SDL_UDEV_ReleaseUdevSyms(void)
525 {
526  SDL_UDEV_Quit();
527 }
528 
529 #endif /* SDL_USE_LIBUDEV */
530 
531 /* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#define SDL_SetError
#define SDL_memset
#define SDL_strrchr
#define SDL_LoadObject
#define SDL_UnloadObject
#define SDL_strlcpy
#define SDL_free
#define SDL_strcmp
#define SDL_Delay
#define SDL_GetHintBoolean
#define SDL_strtoul
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_HINT_ACCELEROMETER_AS_JOYSTICK
A variable controlling whether the Android / iOS built-in accelerometer should be listed as a joystic...
Definition: SDL_hints.h:454
void * SDL_LoadFunction(void *handle, const char *name)
const GLdouble * v
Definition: SDL_opengl.h:2064
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLuint GLfloat * val
GLenum const void * addr
GLsizei const GLchar *const * path
GLsizei const GLfloat * value
int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
Definition: SDL_poll.c:37
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
static SDL_VideoDevice * _this
Definition: SDL_video.c:126
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
#define SDL_UDEV_DYNAMIC
Definition: SDL_config.h:442
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF base if bpp PF set rept prefetch_distance PF set OFFSET endr endif endm macro preload_leading_step2 base if bpp ifc DST PF PF else if bpp lsl PF PF lsl PF PF lsl PF PF PF else PF lsl PF lsl PF lsl PF endif SIZE macro preload_middle scratch_holds_offset if bpp if else PF PF endif endif endif endm macro preload_trailing base if bpp if bpp *pix_per_block PF PF lsl PF PF PF PF PF else PF lsl PF lsl PF PF PF PF PF base if bpp if narrow_case &&bpp<=dst_w_bpp) PF bic, WK0, base, #31 PF pld,[WK0] PF add, WK1, base, X, LSL #bpp_shift PF sub, WK1, WK1, #1 PF bic, WK1, WK1, #31 PF cmp, WK1, WK0 PF beq, 90f PF pld,[WK1]90:.else PF bic, WK0, base, #31 PF pld,[WK0] PF add, WK1, base, X, lsl #bpp_shift PF sub, WK1, WK1, #1 PF bic, WK1, WK1, #31 PF cmp, WK1, WK0 PF beq, 92f91:PF add, WK0, WK0, #32 PF cmp, WK0, WK1 PF pld,[WK0] PF bne, 91b92:.endif .endif.endm.macro conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, 0 .if decrementx sub &cond X, X, #8 *numbytes/dst_w_bpp .endif process_tail cond, numbytes, firstreg .if !((flags) &FLAG_PROCESS_DOES_STORE) pixst cond, numbytes, firstreg, DST .endif.endm.macro conditional_process1 cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx .if(flags) &FLAG_BRANCH_OVER .ifc cond, mi bpl 100f .endif .ifc cond, cs bcc 100f .endif .ifc cond, ne beq 100f .endif conditional_process1_helper, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx100:.else conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx .endif.endm.macro conditional_process2 test, cond1, cond2, process_head, process_tail, numbytes1, numbytes2, firstreg1, firstreg2, unaligned_src, unaligned_mask, decrementx .if(flags) &(FLAG_DST_READWRITE|FLAG_BRANCH_OVER|FLAG_PROCESS_CORRUPTS_PSR|FLAG_PROCESS_DOES_STORE) test conditional_process1 cond1, process_head, process_tail, numbytes1, firstreg1, unaligned_src, unaligned_mask, decrementx .if(flags) &FLAG_PROCESS_CORRUPTS_PSR test .endif conditional_process1 cond2, process_head, process_tail, numbytes2, firstreg2, unaligned_src, unaligned_mask, decrementx .else test process_head cond1, numbytes1, firstreg1, unaligned_src, unaligned_mask, 0 process_head cond2, numbytes2, firstreg2, unaligned_src, unaligned_mask, 0 .if decrementx sub &cond1 X, X, #8 *numbytes1/dst_w_bpp sub &cond2 X, X, #8 *numbytes2/dst_w_bpp .endif process_tail cond1, numbytes1, firstreg1 process_tail cond2, numbytes2, firstreg2 pixst cond1, numbytes1, firstreg1, DST pixst cond2, numbytes2, firstreg2, DST .endif.endm.macro test_bits_1_0_ptr .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 movs SCRATCH, X, lsl #32-1 .else movs SCRATCH, WK0, lsl #32-1 .endif.endm.macro test_bits_3_2_ptr .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 movs SCRATCH, X, lsl #32-3 .else movs SCRATCH, WK0, lsl #32-3 .endif.endm.macro leading_15bytes process_head, process_tail .set DECREMENT_X, 1 .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 .set DECREMENT_X, 0 sub X, X, WK0, lsr #dst_bpp_shift str X,[sp, #LINE_SAVED_REG_COUNT *4] mov X, WK0 .endif .if dst_w_bpp==8 conditional_process2 test_bits_1_0_ptr, mi, cs, process_head, process_tail, 1, 2, 1, 2, 1, 1, DECREMENT_X .elseif dst_w_bpp==16 test_bits_1_0_ptr conditional_process1 cs, process_head, process_tail, 2, 2, 1, 1, DECREMENT_X .endif conditional_process2 test_bits_3_2_ptr, mi, cs, process_head, process_tail, 4, 8, 1, 2, 1, 1, DECREMENT_X .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 ldr X,[sp, #LINE_SAVED_REG_COUNT *4] .endif.endm.macro test_bits_3_2_pix movs SCRATCH, X, lsl #dst_bpp_shift+32-3.endm.macro test_bits_1_0_pix .if dst_w_bpp==8 movs SCRATCH, X, lsl #dst_bpp_shift+32-1 .else movs SCRATCH, X, lsr #1 .endif.endm.macro trailing_15bytes process_head, process_tail, unaligned_src, unaligned_mask conditional_process2 test_bits_3_2_pix, cs, mi, process_head, process_tail, 8, 4, 0, 2, unaligned_src, unaligned_mask, 0 .if dst_w_bpp==16 test_bits_1_0_pix conditional_process1 cs, process_head, process_tail, 2, 0, unaligned_src, unaligned_mask, 0 .elseif dst_w_bpp==8 conditional_process2 test_bits_1_0_pix, cs, mi, process_head, process_tail, 2, 1, 0, 1, unaligned_src, unaligned_mask, 0 .endif.endm.macro wide_case_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, dst_alignment110:.set SUBBLOCK, 0 .rept pix_per_block *dst_w_bpp/128 process_head, 16, 0, unaligned_src, unaligned_mask, 1 .if(src_bpp > 0) &&(mask_bpp==0) &&((flags) &FLAG_PROCESS_PRESERVES_SCRATCH) preload_middle src_bpp, SRC, 1 .elseif(src_bpp==0) &&(mask_bpp > 0) &&((flags) &FLAG_PROCESS_PRESERVES_SCRATCH) preload_middle mask_bpp, MASK, 1 .else preload_middle src_bpp, SRC, 0 preload_middle mask_bpp, MASK, 0 .endif .if(dst_r_bpp > 0) &&((SUBBLOCK % 2)==0) &&(((flags) &FLAG_NO_PRELOAD_DST)==0) PF pld,[DST, #32 *prefetch_distance - dst_alignment] .endif process_tail, 16, 0 .if !((flags) &FLAG_PROCESS_DOES_STORE) pixst, 16, 0, DST .endif .set SUBBLOCK, SUBBLOCK+1 .endr subs X, X, #pix_per_block bhs 110b.endm.macro wide_case_inner_loop_and_trailing_pixels process_head, process_tail, process_inner_loop, exit_label, unaligned_src, unaligned_mask .if dst_r_bpp > tst bne process_inner_loop DST_PRELOAD_BIAS endif preload_trailing SRC preload_trailing MASK DST endif add medium_case_inner_loop_and_trailing_pixels unaligned_mask endm macro medium_case_inner_loop_and_trailing_pixels DST endif subs bhs tst beq exit_label trailing_15bytes unaligned_mask endm macro narrow_case_inner_loop_and_trailing_pixels unaligned_mask tst conditional_process1 trailing_15bytes unaligned_mask endm macro switch_on_alignment action
SDL_bool retval
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47