+static const char wm97xx_p[] =
+ "5507 0 -831476 0 -4218 16450692 65536"; // from 4.0 fw
+
+long emu_do_read(int fd, void *buf, int count)
+{
+ int ret, pressed = 0, x, y;
+ struct {
+ u16 pressure, x, y;
+ } wm97xx;
+
+ if (count < 0) {
+ err("read(%d, %d)\n", fd, count);
+ return -EINVAL;
+ }
+
+ switch (fd) {
+ case FAKEDEV_GPIO:
+ mmsp2.btn_state = host_read_btns();
+
+ if (count > 4)
+ count = 4;
+ memcpy(buf, &mmsp2.btn_state, count);
+ break;
+ case FAKEDEV_WM97XX:
+ ret = host_read_ts(&pressed, &x, &y);
+ if (ret == 0 && pressed) {
+ wm97xx.pressure = 0x8001; // TODO: check the real thing
+ wm97xx.x = x * 3750 / 1024 + 200;
+ wm97xx.y = 3750 - y * 3750 / 1024 + 200;
+ }
+ else {
+ wm97xx.pressure = 0;
+ wm97xx.x = wm97xx.y = 200;
+ }
+
+ if (count > sizeof(wm97xx))
+ count = sizeof(wm97xx);
+ memcpy(buf, &wm97xx, count);
+ break;
+ case FAKEDEV_WM97XX_P:
+ if (count < sizeof(wm97xx_p))
+ err("incomplete pointercal read\n");
+ strncpy(buf, wm97xx_p, count);
+ break;
+ default:
+ dbg("read(%d, %d)\n", fd, count);
+ return -EINVAL;
+ }
+ return count;
+}
+
+struct dev_fd_t emu_interesting_fds[] = {
+ [IFD_SOUND] = { "/dev/dsp", -1, emu_sound_open },
+ { NULL, 0, NULL },
+};
+
+static const struct {
+ const char *from;
+ const char *to;
+} path_map[] = {
+ { "/mnt/tmp", "./tmp" },
+ { "/mnt/sd", "./mntsd" },
+};
+
+const char *emu_wrap_path(const char *path)
+{
+ char *buff, *p;
+ size_t size;
+ int i, len;
+ long ret;
+
+ // do only path mapping for now
+ for (i = 0; i < ARRAY_SIZE(path_map); i++) {
+ p = strstr(path, path_map[i].from);
+ if (p != NULL) {
+ size = strlen(path) + strlen(path_map[i].to) + 1;
+ buff = malloc(size);
+ if (buff == NULL)
+ break;
+ len = p - path;
+ strncpy(buff, path, len);
+ snprintf(buff + len, size - len, "%s%s", path_map[i].to,
+ path + len + strlen(path_map[i].from));
+ dbg("mapped path \"%s\" -> \"%s\"\n", path, buff);
+
+ ret = g_mkdir_raw(path_map[i].to, 0666);
+ if (ret != 0 && ret != -EEXIST)
+ err("mkdir(%s): %ld\n", path_map[i].to, ret);
+
+ return buff;
+ }
+ }
+
+ return path;
+}
+
+void emu_wrap_path_free(const char *w_path, const char *old_path)
+{
+ if (w_path != old_path)
+ free((void *)w_path);
+}
+
+void *emu_do_fopen(const char *path, const char *mode)
+{
+ const char *w_path;
+ FILE *ret;
+
+ if (strcmp(path, "/etc/pointercal") == 0) {
+ // use local pontercal, not host's
+ ret = fopen("pointercal", mode);
+ if (ret == NULL) {
+ ret = fopen("pointercal", "w");
+ if (ret != NULL) {
+ fwrite(wm97xx_p, 1, sizeof(wm97xx_p), ret);
+ fclose(ret);
+ }
+ ret = fopen("pointercal", mode);
+ }
+ }
+ else {
+ w_path = emu_wrap_path(path);
+ ret = fopen(w_path, mode);
+ emu_wrap_path_free(w_path, path);
+ }
+
+ return ret;
+}
+
+// FIXME: threads..
+int emu_do_system(const char *command)
+{
+ static char tmp_path[512];
+ int need_ginge = 0;
+ const char *p2;
+ char *p;
+ int ret;
+
+ if (command == NULL)
+ return -1;
+
+ for (p2 = command; *p2 && isspace(*p2); p2++)
+ ;
+
+ if (*p2 == '.') // relative path?
+ need_ginge = 1;
+ else if (*p2 == '/' && strncmp(p2, "/bin", 4) && strncmp(p2, "/lib", 4)
+ && strncmp(p2, "/sbin", 4) && strncmp(p2, "/usr", 4))
+ // absolute path, but not a system command
+ need_ginge = 1;
+
+ p2 = emu_wrap_path(command);
+ if (need_ginge) {
+ make_local_path(tmp_path, sizeof(tmp_path), "ginge_prep");
+ p = tmp_path + strlen(tmp_path);
+
+ snprintf(p, sizeof(tmp_path) - (p - tmp_path), " --nomenu %s", p2);
+ }
+ else
+ snprintf(tmp_path, sizeof(tmp_path), "%s", p2);
+ emu_wrap_path_free(p2, command);
+
+ dbg("system: \"%s\"\n", tmp_path);
+
+ // the app might want the screen too..
+ fb_thread_pause();
+ ret = system(tmp_path);
+ fb_thread_resume();
+ return ret;
+}
+
+long emu_do_execve(const char *filename, char * const argv[],
+ char * const envp[])
+{
+ const char **new_argv;
+ char *prep_path;
+ int i, argc;
+ long ret;
+
+ if (filename == NULL)
+ return -1;
+
+ if (strstr(filename, "gp2xmenu") != NULL)
+ host_forced_exit(0);
+
+ for (i = 0; argv[i] != NULL; i++)
+ ;
+ argc = i + 1;
+
+ new_argv = calloc(argc + 2, sizeof(new_argv[0]));
+ if (new_argv == NULL)
+ return -1;
+
+ prep_path = malloc(512);
+ if (prep_path == NULL)
+ return -1;
+
+ make_local_path(prep_path, 512, "ginge_prep");
+ new_argv[0] = prep_path;
+ new_argv[1] = "--nomenu";
+ new_argv[2] = emu_wrap_path(filename);
+
+ if (argv[0] != NULL)
+ for (i = 1; argv[i] != NULL; i++)
+ new_argv[i + 2] = argv[i];
+
+ dbg("execve \"%s\" %s \"%s\"\n", new_argv[0], new_argv[1], new_argv[2]);
+ ret = execve(new_argv[0], (char **)new_argv, envp);
+ err("execve(%s): %ld\n", new_argv[0], ret);
+ return ret;
+}
+
+// vim:shiftwidth=2:expandtab