+ err("bad/ni ioctl(%d, %08x, %p)\n", fd, request, argp);
+ return -EINVAL;
+}
+
+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;