+ return -EINVAL;
+ }
+
+ umem = uppermem_lookup(offset, &umem_end);
+ if (umem + length > umem_end)
+ err("warning: uppermem @ %08x overflows by %d bytes\n",
+ offset, umem + length - umem_end);
+
+ dbg("upper mem @ %08x %x = %p\n", offset, length, umem);
+ return (long)umem;
+}
+
+long emu_do_mmap(unsigned int length, int prot, int flags, int fd,
+ unsigned int offset)
+{
+ if (fd == FAKEDEV_MEM)
+ return emu_mmap_dev(length, prot, flags, offset);
+
+ if (fd == FAKEDEV_FB0)
+ return emu_mmap_dev(length, prot, flags, offset + 0x03101000);
+
+ if (fd == FAKEDEV_FB1)
+ return emu_mmap_dev(length, prot, flags, offset + 0x03381000);
+
+ err("bad/ni mmap(?, %d, %x, %x, %d, %08x)\n", length, prot, flags, fd, offset);
+ return -EINVAL;
+}
+
+long emu_do_munmap(void *addr, unsigned int length)
+{
+ u8 *p = addr;
+
+ // don't allow to unmap upper mem
+ if ((u8 *)mmsp2.umem <= p && p < (u8 *)mmsp2.umem + 0x2000000) {
+ dbg("ignoring munmap: %p %x\n", addr, length);
+ return 0;
+ }
+
+ return -EAGAIN;
+}
+
+static void emu_sound_open(int fd)
+{
+#ifdef PND
+ int ret, frag;
+
+ // set default buffer size to 16 * 1K
+ frag = (16<<16) | 10; // 16K
+ ret = g_ioctl_raw(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+ if (ret != 0)
+ err("snd ioctl SETFRAGMENT %08x: %d\n", frag, ret);
+#endif
+}
+
+static long emu_sound_ioctl(int fd, int request, void *argp)
+{
+ int *arg = argp;
+
+#if 0
+ dbg("snd ioctl(%d, %08x, %p)", fd, request, argp);
+ if (arg != NULL)
+ dbg_c(" [%d]", *arg);
+ dbg_c("\n");
+#endif
+
+ /* People set strange frag settings on GP2X, which even manage
+ * to break audio on pandora (causes writes to fail).
+ * Catch this and set to something that works. */
+ switch(request) {
+ case SNDCTL_DSP_SETFRAGMENT: {
+ int bsize, frag, frag_cnt;
+ long ret;
+
+ if (arg == NULL)
+ break;
+
+ frag = *arg & 0xffff;
+ frag_cnt = *arg >> 16;
+ bsize = frag_cnt << frag;
+ if (frag < 10 || bsize < 4096*4 || bsize > 4096*4*2) {
+ /*
+ * ~4ms. gpSP wants small buffers or else it stutters
+ * because of it's audio thread sync stuff
+ * XXX: hardcoding, as low samplerates will result in small fragment size,
+ * which itself causes ALSA stall and hangs the program.
+ * Also some apps change samplerate without reopening /dev/dsp,
+ * which causes ALSA to reject SNDCTL_DSP_SETFRAGMENT.
+ */
+ bsize = 44100 / 250 * 4;
+
+ for (frag = 0; bsize; bsize >>= 1, frag++)
+ ;
+
+ frag_cnt = 16;
+ }
+
+ frag |= frag_cnt << 16;
+ ret = g_ioctl_raw(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+ if (ret != 0)
+ err("snd ioctl SETFRAGMENT %08x: %ld\n", frag, ret);
+ // indicate success even if we fail (because of ALSA mostly),
+ // things like MikMod will bail out otherwise.
+ return 0;
+ }
+ case SNDCTL_DSP_SYNC:
+ // Franxis tends to use sync/write loops, bad idea under ALSA
+ return 0;
+ default:
+ break;
+ }