initial f200 touchscreen support
[ginge.git] / loader / override.c
1 /*
2  * GINGE - GINGE Is Not Gp2x Emulator
3  * (C) notaz, 2010-2011,2016
4  *
5  * This work is licensed under the MAME license, see COPYING file for details.
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <sys/mman.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17 #include <signal.h>
18 #include <termios.h>
19 #include <errno.h>
20
21 #include "realfuncs.h"
22 #include "syscalls.h"
23 #include "llibc.h"
24 #include "header.h"
25
26 #if (DBG & 1)
27 #define strace g_printf
28 #else
29 #define strace(...)
30 #endif
31
32 #define UNUSED __attribute__((unused))
33
34 static const struct dev_fd_t takeover_devs[] = {
35   { "/dev/mem",     FAKEDEV_MEM },
36   { "/dev/GPIO",    FAKEDEV_GPIO },
37   { "/dev/fb0",     FAKEDEV_FB0 },
38   { "/dev/fb/0",    FAKEDEV_FB0 },
39   { "/dev/fb1",     FAKEDEV_FB1 },
40   { "/dev/fb/1",    FAKEDEV_FB1 },
41   { "/dev/mmuhack", FAKEDEV_MMUHACK },
42   { "/dev/tty",     FAKEDEV_TTY0 },
43   { "/dev/tty0",    FAKEDEV_TTY0 },
44   { "/dev/touchscreen/wm97xx", FAKEDEV_WM97XX },
45   { "/etc/pointercal",         FAKEDEV_WM97XX_P },
46 #ifdef PND
47   { "/dev/input/event*", -1 }, // hide for now, may cause dupe events
48 #endif
49 };
50
51 static long w_open_raw(const char *pathname, int flags, mode_t mode)
52 {
53   long ret;
54   int i;
55
56   for (i = 0; i < ARRAY_SIZE(takeover_devs); i++) {
57     const char *p, *oname;
58     int len;
59
60     oname = takeover_devs[i].name;
61     p = strchr(oname, '*');
62     if (p != NULL)
63       len = p - oname;
64     else
65       len = strlen(oname) + 1;
66
67     if (strncmp(pathname, oname, len) == 0) {
68       ret = takeover_devs[i].fd;
69       break;
70     }
71   }
72
73   if (i == ARRAY_SIZE(takeover_devs))
74     ret = g_open_raw(pathname, flags, mode);
75
76   if (ret >= 0) {
77     for (i = 0; emu_interesting_fds[i].name != NULL; i++) {
78       struct dev_fd_t *eifd = &emu_interesting_fds[i];
79       if (strcmp(pathname, eifd->name) == 0) {
80         eifd->fd = ret;
81         if (eifd->open_cb != NULL)
82           eifd->open_cb(ret);
83         break;
84       }
85     }
86   }
87
88   strace("open(%s) = %ld\n", pathname, ret);
89   return ret;
90 }
91
92 static int w_open(const char *pathname, int flags, mode_t mode)
93 {
94   long ret = w_open_raw(pathname, flags, mode);
95   return g_syscall_error(ret);
96 }
97
98 static long w_mmap_raw(void *addr, size_t length, int prot, int flags,
99   int fd, off_t offset)
100 {
101   long ret;
102
103   if (FAKEDEV_MEM <= fd && fd < FAKEDEV_FD_BOUNDARY)
104     ret = emu_do_mmap(length, prot, flags, fd, offset);
105   else
106     ret = g_mmap2_raw(addr, length, prot, flags, fd, offset >> 12);
107
108   strace("mmap(%p, %x, %x, %x, %d, %lx) = %lx\n",
109          addr, length, prot, flags, fd, (long)offset, ret);
110   return ret;
111 }
112
113 static long w_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
114 {
115   long ret = w_mmap_raw(addr, length, prot, flags, fd, offset);
116   return g_syscall_error(ret);
117 }
118 #define w_mmap2 w_mmap
119
120 static long w_munmap_raw(void *addr, size_t length)
121 {
122   long ret;
123
124   ret = emu_do_munmap(addr, length);
125   if (ret == -EAGAIN)
126     ret = g_munmap_raw(addr, length);
127
128   strace("munmap(%p, %x) = %ld\n", addr, length, ret);
129   return ret;
130 }
131
132 static int w_munmap(void *addr, size_t length)
133 {
134   long ret = w_munmap_raw(addr, length);
135   return g_syscall_error(ret);
136 }
137
138 long w_read_raw(int fd, void *buf, size_t count)
139 {
140   long ret;
141
142   if (FAKEDEV_MEM <= fd && fd < FAKEDEV_FD_BOUNDARY)
143     ret = emu_do_read(fd, buf, count);
144   else
145     ret = g_read_raw(fd, buf, count);
146
147   //strace("read(%d, %p, %zd) = %ld\n", fd, buf, count, ret);
148   return ret;
149 }
150
151 static ssize_t w_read(int fd, void *buf, size_t count)
152 {
153   long ret = w_read_raw(fd, buf, count);
154   return g_syscall_error(ret);
155 }
156
157 long w_ioctl_raw(int fd, int request, void *argp)
158 {
159   long ret;
160
161   if ((FAKEDEV_MEM <= fd && fd < FAKEDEV_FD_BOUNDARY) ||
162       fd == emu_interesting_fds[IFD_SOUND].fd)
163     ret = emu_do_ioctl(fd, request, argp);
164   else
165     ret = g_ioctl_raw(fd, request, argp);
166
167   strace("ioctl(%d, %08x, %p) = %ld\n", fd, request, argp, ret);
168   return ret;
169 }
170
171 static int w_ioctl(int fd, int request, void *argp)
172 {
173   long ret = w_ioctl_raw(fd, request, argp);
174   return g_syscall_error(ret);
175 }
176
177 static int w_sigaction(int signum, const void *act, void *oldact)
178 {
179   strace("sigaction(%d, %p, %p) = %d\n", signum, act, oldact, 0);
180   return 0;
181 }
182
183 /* dynamic only */
184 static UNUSED int w_tcgetattr(int fd, struct termios *termios_p)
185 {
186   int ret;
187   if (fd != FAKEDEV_TTY0)
188     ret = tcgetattr(fd, termios_p);
189   else
190     ret = 0;
191
192   strace("tcgetattr(%d, %p) = %d\n", fd, termios_p, ret);
193   return ret;
194 }
195
196 static UNUSED int w_tcsetattr(int fd, int optional_actions,
197                        const struct termios *termios_p)
198 {
199   int ret;
200   if (fd != FAKEDEV_TTY0)
201     ret = tcsetattr(fd, optional_actions, termios_p);
202   else
203     ret = 0;
204
205   strace("tcsetattr(%d, %x, %p) = %d\n", fd, optional_actions, termios_p, ret);
206   return ret;
207 }
208
209 static UNUSED FILE *w_fopen(const char *path, const char *mode)
210 {
211   FILE *ret = emu_do_fopen(path, mode);
212   strace("fopen(%s, %s) = %p\n", path, mode, ret);
213   return ret;
214 }
215
216 static UNUSED int w_system(const char *command)
217 {
218   int ret = emu_do_system(command);
219   strace("system(%s) = %d\n", command, ret);
220   return ret;
221 }
222
223 extern char **environ;
224
225 static UNUSED int w_execl(const char *path, const char *arg, ...)
226 {
227   // don't allow exec (for now)
228   strace("execl(%s, %s, ...) = ?\n", path, arg);
229   exit(1);
230 }
231
232 static UNUSED int w_execlp(const char *file, const char *arg, ...)
233 {
234   strace("execlp(%s, %s, ...) = ?\n", file, arg);
235   exit(1);
236 }
237
238 static UNUSED int w_execle(const char *path, const char *arg, ...)
239 {
240   strace("execle(%s, %s, ...) = ?\n", path, arg);
241   exit(1);
242 }
243
244 static UNUSED int w_execv(const char *path, char *const argv[])
245 {
246   strace("execv(%s, %p) = ?\n", path, argv);
247   return emu_do_execve(path, argv, environ);
248 }
249
250 static UNUSED int w_execvp(const char *file, char *const argv[])
251 {
252   strace("execvp(%s, %p) = ?\n", file, argv);
253   return emu_do_execve(file, argv, environ);
254 }
255
256 long w_execve_raw(const char *filename, char * const argv[],
257                   char * const envp[])
258 {
259   strace("execve(%s, %p, %p) = ?\n", filename, argv, envp);
260   return emu_do_execve(filename, argv, envp);
261 }
262
263 static UNUSED int w_execve(const char *filename, char * const argv[],
264                            char * const envp[])
265 {
266   long ret = w_execve_raw(filename, argv, envp);
267   return g_syscall_error(ret);
268 }
269
270 static int w_chdir(const char *path)
271 {
272   long ret;
273
274   if (path != NULL && strstr(path, "/usr/gp2x") != NULL)
275     ret = 0;
276   else
277     ret = g_chdir_raw(path);
278
279   strace("chdir(%s) = %ld\n", path, ret);
280   return g_syscall_error(ret);
281 }
282
283 static ssize_t w_readlink(const char *path, char *buf, size_t bufsiz)
284 {
285   long ret;
286
287 #ifndef DL
288   if (path != NULL && strncmp(path, "/proc/", 6) == 0
289       && strcmp(strrchr(path, '/'), "/exe") == 0)
290   {
291     ret = snprintf(buf, bufsiz, "%s", bin_path);
292     if (ret > bufsiz)
293       ret = bufsiz;
294   }
295   else
296 #endif
297     ret = g_readlink_raw(path, buf, bufsiz);
298
299   strace("readlink(%s, %s, %zd) = %ld\n", path, buf, bufsiz, ret);
300   return g_syscall_error(ret);
301 }
302
303 #undef open
304 #undef fopen
305 #undef mmap
306 #undef munmap
307 #undef read
308 #undef ioctl
309 #undef close
310 #undef sigaction
311 #undef tcgetattr
312 #undef tcsetattr
313 #undef system
314 #undef execl
315 #undef execlp
316 #undef execle
317 #undef execv
318 #undef execvp
319 #undef execve
320 #undef chdir
321 #undef readlink
322
323 #ifdef DL
324
325 #define MAKE_WRAP_SYM_N(sym) \
326   /* alias wrap symbols to real names */ \
327   typeof(sym) sym __attribute__((alias("w_" #sym)))
328
329 #define MAKE_WRAP_SYM(sym) \
330   MAKE_WRAP_SYM_N(sym); \
331   /* wrapper to real functions, to be set up on load */ \
332   static typeof(sym) *p_real_##sym
333
334 // note: update symver too
335 MAKE_WRAP_SYM_N(open);
336 MAKE_WRAP_SYM(fopen);
337 MAKE_WRAP_SYM_N(mmap);
338 MAKE_WRAP_SYM_N(munmap);
339 MAKE_WRAP_SYM_N(read);
340 MAKE_WRAP_SYM_N(ioctl);
341 MAKE_WRAP_SYM(sigaction);
342 MAKE_WRAP_SYM(tcgetattr);
343 MAKE_WRAP_SYM(tcsetattr);
344 MAKE_WRAP_SYM(system);
345 MAKE_WRAP_SYM_N(execl);
346 MAKE_WRAP_SYM_N(execlp);
347 MAKE_WRAP_SYM_N(execle);
348 MAKE_WRAP_SYM_N(execv);
349 MAKE_WRAP_SYM_N(execvp);
350 MAKE_WRAP_SYM_N(execve);
351 MAKE_WRAP_SYM_N(chdir);
352 MAKE_WRAP_SYM_N(readlink);
353 typeof(mmap) mmap2 __attribute__((alias("w_mmap")));
354
355 #define REAL_FUNC_NP(name) \
356   { #name, (void **)&p_real_##name }
357
358 static const struct {
359   const char *name;
360   void **func_ptr;
361 } real_funcs_np[] = {
362   //REAL_FUNC_NP(open),
363   REAL_FUNC_NP(fopen),
364   //REAL_FUNC_NP(mmap),
365   //REAL_FUNC_NP(munmap),
366   //REAL_FUNC_NP(read),
367   //REAL_FUNC_NP(ioctl),
368   REAL_FUNC_NP(sigaction),
369   REAL_FUNC_NP(tcgetattr),
370   REAL_FUNC_NP(tcsetattr),
371   REAL_FUNC_NP(system),
372   // exec* - skipped
373   //REAL_FUNC_NP(execve),
374   //REAL_FUNC_NP(chdir),
375 };
376
377 //#define open p_real_open
378 #define fopen p_real_fopen
379 //#define mmap p_real_mmap
380 //#define munmap p_real_munmap
381 //#define read p_real_read
382 //#define ioctl p_real_ioctl
383 #define sigaction p_real_sigaction
384 #define tcgetattr p_real_tcgetattr
385 #define tcsetattr p_real_tcsetattr
386 #define system p_real_system
387 //#define execve p_real_execve
388 //#define chdir p_real_chdir
389
390 #undef MAKE_WRAP_SYM
391 #undef REAL_FUNC_NP
392
393 #endif
394
395 // just call real funcs for static, pointer for dynamic
396 int real_open(const char *pathname, int flags, ...)
397 {
398   va_list ap;
399   mode_t mode;
400   long ret;
401
402   va_start(ap, flags);
403   mode = va_arg(ap, mode_t);
404   va_end(ap);
405   ret = g_open_raw(pathname, flags, mode);
406   return g_syscall_error(ret);
407 }
408
409 FILE *real_fopen(const char *path, const char *mode)
410 {
411   return fopen(path, mode);
412 }
413
414 void *real_mmap(void *addr, size_t length, int prot, int flags,
415   int fd, off_t offset)
416 {
417   long ret = g_mmap2_raw(addr, length, prot, flags, fd, offset >> 12);
418   return (void *)g_syscall_error(ret);
419 }
420
421 int real_munmap(void *addr, size_t length)
422 {
423   return g_syscall_error(g_munmap_raw(addr, length));
424 }
425
426 int real_read(int fd, void *buf, size_t count)
427 {
428   long ret = g_read_raw(fd, buf, count);
429   return g_syscall_error(ret);
430 }
431
432 int real_ioctl(int fd, int request, void *argp)
433 {
434   long ret = g_ioctl_raw(fd, request, argp);
435   return g_syscall_error(ret);
436 }
437
438 int real_close(int fd)
439 {
440   long ret = g_close_raw(fd);
441   return g_syscall_error(ret);
442 }
443
444 int real_sigaction(int signum, const sigaction_t *act, sigaction_t *oldact)
445 {
446   return sigaction(signum, act, oldact);
447 }
448
449 int real_tcgetattr(int fd, struct termios *termios_p)
450 {
451   return tcgetattr(fd, termios_p);
452 }
453
454 int real_tcsetattr(int fd, int optional_actions,
455                        const struct termios *termios_p)
456 {
457   return tcsetattr(fd, optional_actions, termios_p);
458 }
459
460 int real_system(const char *command)
461 {
462   return system(command);
463 }
464
465 // real_exec* is missing intentionally - we don't need them
466
467 int real_execve(const char *filename, char *const argv[],
468                   char *const envp[])
469 {
470   long ret = g_execve_raw(filename, argv, envp);
471   return g_syscall_error(ret);
472 }
473
474 int real_chdir(const char *path)
475 {
476   long ret = g_chdir_raw(path);
477   return g_syscall_error(ret);
478 }
479
480 ssize_t real_readlink(const char *path, char *buf, size_t bufsiz)
481 {
482   long ret = g_readlink_raw(path, buf, bufsiz);
483   return g_syscall_error(ret);
484 }
485
486 void real_sleep(unsigned int seconds)
487 {
488   struct timespec ts = { seconds, 0 };
489   g_nanosleep_raw(&ts, NULL);
490 }
491
492 void real_usleep(unsigned int usec)
493 {
494   struct timespec ts = { usec / 1000000, usec % 1000000 };
495   g_nanosleep_raw(&ts, NULL);
496 }
497
498 void real_exit(int status)
499 {
500   g_exit_group_raw(status);
501 }
502
503 // vim:shiftwidth=2:expandtab