main.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. /*
  2. * meg4/platform/fbdev_alsa/main.c
  3. *
  4. * Copyright (C) 2023 bzt
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. *
  20. * @brief Linux FrameBuffer + ALSA "platform" for the MEG-4
  21. *
  22. */
  23. #define _POSIX_C_SOURCE 199309L /* needed for timespec and nanosleep() */
  24. #include <time.h>
  25. #include <fcntl.h>
  26. #include <dirent.h>
  27. #include <unistd.h>
  28. #include <pthread.h>
  29. #include <termios.h>
  30. #include <sys/time.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/wait.h>
  33. #include <sys/mman.h>
  34. #include <sys/reboot.h>
  35. #include <sys/mount.h>
  36. #include <linux/kd.h>
  37. #include <linux/fb.h>
  38. #include <linux/input.h>
  39. #include <sound/asound.h>
  40. #include "meg4.h"
  41. #define ALSA_BUFFER_SIZE 4096
  42. #define ALSA_PERIOD_SIZE 1024
  43. enum { KBD, MOUSE, PAD };
  44. int fb = -1, en = 0, ed[256], *sax = NULL, *say = NULL;
  45. struct fb_fix_screeninfo fb_fix;
  46. struct fb_var_screeninfo fb_var, fb_orig;
  47. uint32_t *scrbuf = NULL;
  48. uint8_t *fbuf = NULL, *foffs, *ffull;
  49. struct termios oldt, newt;
  50. int afd = -1, audio = 0;
  51. volatile unsigned int period_size, boundary;
  52. struct snd_pcm_mmap_status *mmap_status;
  53. struct snd_pcm_mmap_control *mmap_control;
  54. float abuf[ALSA_BUFFER_SIZE];
  55. int16_t ibuf[2*ALSA_BUFFER_SIZE];
  56. pthread_t th = 0;
  57. void sync(void);
  58. int main_w = 0, main_h = 0, main_exit = 0, main_alt = 0, main_sh = 0, main_meta = 0, main_caps = 0, main_keymap[512], main_kbd = 0;
  59. int win_f = 0, win_w, win_h, win_fw, win_fh, win_dp, win_dp2, win_dp3, win_dp4, win_dp5, win_dp6, win_dp7, win_dp8;
  60. void main_delay(int msec);
  61. /* keyboard layout mapping */
  62. const char *main_kbdlayout[2][128*4] = { {
  63. /* KEY_RESERVED 0 */ "", "", "", "", /* first layout is user configurable */
  64. /* KEY_ESC 1 */ "", "", "", "",
  65. #ifdef KBDMAP
  66. #include KBDMAP
  67. #else
  68. #include "us.h"
  69. #endif
  70. }, {
  71. /* KEY_RESERVED 0 */ "", "", "", "", /* second layout is always International */
  72. /* KEY_ESC 1 */ "", "", "", "",
  73. #include "us.h"
  74. } };
  75. /* interface's language */
  76. #ifndef LANG
  77. #define LANG "en"
  78. #endif
  79. /* the device and partition with the "MEG-4" directory, where the floppy images reside */
  80. #ifndef FLOPPYDEV
  81. #define FLOPPYDEV "/dev/sda1"
  82. #endif
  83. #define meg4_showcursor()
  84. #define meg4_hidecursor()
  85. #include "../common.h"
  86. /* helpers for hw_params */
  87. static struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
  88. {
  89. return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
  90. }
  91. static struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
  92. {
  93. return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
  94. }
  95. static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
  96. {
  97. struct snd_mask *m = param_to_mask(p, n);
  98. if (bit >= SNDRV_MASK_MAX)
  99. return;
  100. m->bits[0] = 0;
  101. m->bits[1] = 0;
  102. m->bits[bit >> 5] |= (1 << (bit & 31));
  103. }
  104. static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned int val)
  105. {
  106. struct snd_interval *i = param_to_interval(p, n);
  107. i->min = val;
  108. }
  109. static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int val)
  110. {
  111. struct snd_interval *i = param_to_interval(p, n);
  112. i->min = val;
  113. i->max = val;
  114. i->integer = 1;
  115. }
  116. static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n)
  117. {
  118. struct snd_interval *i = param_to_interval(p, n);
  119. return (i->integer) ? i->max : 0;
  120. }
  121. static void param_init(struct snd_pcm_hw_params *p)
  122. {
  123. struct snd_mask *m;
  124. struct snd_interval *i;
  125. int n;
  126. memset(p, 0, sizeof(struct snd_pcm_hw_params));
  127. for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
  128. n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
  129. m = param_to_mask(p, n);
  130. m->bits[0] = ~0;
  131. m->bits[1] = ~0;
  132. }
  133. for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
  134. n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
  135. i = param_to_interval(p, n);
  136. i->min = 0;
  137. i->max = ~0;
  138. }
  139. p->rmask = ~0U;
  140. p->cmask = 0;
  141. p->info = ~0U;
  142. }
  143. /**
  144. * Exit emulator
  145. */
  146. void main_quit(void)
  147. {
  148. #ifdef USE_INIT
  149. pid_t pid;
  150. #endif
  151. int i;
  152. main_log(1, "quitting... ");
  153. meg4_poweroff();
  154. for(i = 0; i < en; i += 2)
  155. if(ed[i] > 0) { close(ed[i]); ed[i] = -1; }
  156. if(audio) {
  157. period_size = 0;
  158. if(th) { pthread_cancel(th); pthread_join(th, NULL); th = 0; }
  159. if(mmap_status) munmap(mmap_status, 4096);
  160. if(mmap_control) munmap(mmap_control, 4096);
  161. if(afd > 0) { ioctl(afd, SNDRV_PCM_IOCTL_DRAIN); close(afd); afd = -1; }
  162. }
  163. if(scrbuf) { free(scrbuf); scrbuf = NULL; }
  164. if(sax) { free(sax); sax = NULL; }
  165. if(say) { free(say); say = NULL; }
  166. if(fbuf) { memset(fbuf, 0, fb_fix.smem_len); msync(fbuf, fb_fix.smem_len, MS_SYNC); munmap(fbuf, fb_fix.smem_len); fbuf = NULL; }
  167. if(fb >= 0) {
  168. if(fb_orig.bits_per_pixel != 32) ioctl(fb, FBIOPUT_VSCREENINFO, &fb_orig);
  169. close(fb);
  170. fprintf(stdout, "\x1b[H\x1b[2J");
  171. }
  172. fprintf(stdout, "\x1b[?0c\x1b[?1q\x1b[?25h"); fflush(stdout);
  173. tcsetattr(STDIN_FILENO, TCSAFLUSH, &oldt);
  174. #ifdef USE_INIT
  175. /* if we're running as init, make sure everything is written out to disk, and then power off the machine */
  176. sync();
  177. umount("/mnt");
  178. if((pid = fork()) == 0) { reboot(RB_POWER_OFF); exit(0); }
  179. waitpid(pid, NULL, 0);
  180. sleep(1);
  181. #endif
  182. exit(0);
  183. }
  184. /**
  185. * Create window
  186. */
  187. void main_win(void)
  188. {
  189. DIR *dh;
  190. struct dirent *de;
  191. /* Linux kernel limits device names in 256 bytes, so this must be enough even with the path prefix */
  192. char dev[512] = "/dev/input", *fbd;
  193. int l, x, y, k = 0, c = 0;
  194. uint64_t ev_type, key_type[KEY_MAX/64 + 1];
  195. tcgetattr(STDIN_FILENO, &oldt);
  196. memcpy(&newt, &oldt, sizeof(newt));
  197. oldt.c_lflag |= ECHO;
  198. newt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
  199. tcsetattr(STDIN_FILENO, TCSAFLUSH, &newt);
  200. /* get keyboard, mouse and gamepad event devices */
  201. dh = opendir(dev); en = 0; memset(ed, 0, sizeof(ed)); dev[10] = '/';
  202. if(dh) {
  203. while(en < 256 && (de = readdir(dh)) != NULL) {
  204. if(memcmp(de->d_name, "event", 5)) continue;
  205. strcpy(dev + 11, de->d_name);
  206. ed[en] = open(dev, O_RDONLY | O_NDELAY | O_NONBLOCK);
  207. if(ed[en] > 0) {
  208. /* detect event device's type */
  209. ev_type = 0; memset(key_type, 0, sizeof(key_type));
  210. if(ioctl(ed[en], EVIOCGBIT(0, sizeof(ev_type)), &ev_type) >= 0 && (ev_type & (1 << EV_KEY)) &&
  211. ioctl(ed[en], EVIOCGBIT(EV_KEY, KEY_MAX+1), &key_type) >= 0) {
  212. /* let's see what keys are produced with EV_KEY events */
  213. if(key_type[BTN_GAMEPAD / 64] & (1UL << (BTN_GAMEPAD & 63))) { ed[en + 1] = PAD + c; c++; en += 2; } else
  214. if(key_type[BTN_MOUSE / 64] & (1UL << (BTN_MOUSE & 63))) { ed[en + 1] = MOUSE; en += 2; } else
  215. if(key_type[KEY_ENTER / 64] & (1UL << (KEY_ENTER & 63))) { ed[en + 1] = KBD; k++; en += 2; } else ev_type = 0;
  216. }
  217. if(!ev_type) { close(ed[en]); ed[en] = -1; }
  218. }
  219. }
  220. closedir(dh);
  221. }
  222. if(k < 1) { main_log(0, "no keyboard device"); return; }
  223. /* get video device */
  224. fbd = "/dev/fb0"; fb = open(fbd, O_RDWR);
  225. if(fb < 0) { fbd = "/dev/graphics/fb0"; fb = open(fbd, O_RDWR); }
  226. if(fb < 0) return;
  227. /* configure framebuffer */
  228. if(ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) != 0 || fb_var.xres < 640 || fb_var.yres < 400) {
  229. /* try to set resolution */
  230. close(fb);
  231. l = open("/sys/class/graphics/fb0/mode", O_WRONLY); if(l > 0) { x = write(l, "U:1280x800p-0\n", 14); close(l); }
  232. fb = open(fbd, O_RDWR); if(fb < 0) return;
  233. if(ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) != 0 || fb_var.xres < 640 || fb_var.yres < 400) { close(fb); fb = -1; return; }
  234. }
  235. memcpy(&fb_orig, &fb_var, sizeof(struct fb_var_screeninfo));
  236. /* clear screen and hide cursor */
  237. fprintf(stdout, "\x1b[H\x1b[2J\x1b[?12l\x1b[?17c\x1b[?2q\x1b[?25l"); fflush(stdout);
  238. l = open("/sys/class/graphics/fbcon/cursor_blink", O_WRONLY); if(l > 0) { x = write(l, "0\n", 2); close(l); }
  239. if(fb_var.bits_per_pixel != 32) {
  240. fb_var.bits_per_pixel = 32;
  241. if(ioctl(fb, FBIOPUT_VSCREENINFO, &fb_var) != 0 ||
  242. ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) != 0 || fb_var.bits_per_pixel != 32) { close(fb); fb = -1; return; }
  243. }
  244. if(ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) != 0 || fb_fix.type != FB_TYPE_PACKED_PIXELS) { close(fb); fb = -1; return; }
  245. fbuf = (uint8_t*)mmap(0, fb_fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
  246. if(fbuf == NULL || (intptr_t)fbuf == -1) { close(fb); fb = -1; fbuf = NULL; return; }
  247. memset(fbuf, 0, fb_fix.smem_len);
  248. /* calculate windowed and full screen sizes, keeping aspect ratio */
  249. main_w = fb_var.xres; main_h = fb_var.yres;
  250. win_w = 640; win_h = 400;
  251. while(main_w >= win_w + 640 && main_h >= win_h + 400) { win_w += 640; win_h += 400; }
  252. x = (main_w - win_w) >> 1; y = (main_h - win_h) >> 1;
  253. foffs = fbuf + y * fb_fix.line_length + (x << 2);
  254. win_fw = main_w; win_fh = 400 * main_w / 640;
  255. if(win_fh > main_h) { win_fh = main_h; win_fw = 640 * main_h / 400; }
  256. x = (main_w - win_fw) >> 1; y = (main_h - win_fh) >> 1;
  257. ffull = fbuf + y * fb_fix.line_length + (x << 2);
  258. l = (win_fw > win_fh ? win_fw : win_fh) + 1;
  259. sax = (int*)malloc(l * sizeof(int)); say = (int*)malloc(l * sizeof(int));
  260. win_dp = fb_fix.line_length >> 2; win_dp2 = win_dp << 1; win_dp3 = win_dp * 3; win_dp4 = win_dp << 2;
  261. win_dp5 = win_dp * 5; win_dp6 = win_dp * 6; win_dp7 = win_dp * 7; win_dp8 = win_dp << 3;
  262. }
  263. /**
  264. * Toggle fullscreen
  265. */
  266. void main_fullscreen(void)
  267. {
  268. memset(fbuf, 0, fb_fix.smem_len);
  269. win_f ^= 1;
  270. }
  271. /**
  272. * Make window focused
  273. */
  274. void main_focus(void)
  275. {
  276. }
  277. /**
  278. * Get text from clipboard (must be freed by caller)
  279. */
  280. char *main_getclipboard(void)
  281. {
  282. return NULL;
  283. }
  284. /**
  285. * Set text to clipboard
  286. */
  287. void main_setclipboard(char *str)
  288. {
  289. (void)str;
  290. }
  291. /**
  292. * Show on-screen keyboard
  293. */
  294. void main_osk_show(void)
  295. {
  296. }
  297. /**
  298. * Hide on-screen keyboard
  299. */
  300. void main_osk_hide(void)
  301. {
  302. }
  303. /**
  304. * Audio callback
  305. */
  306. static void *main_audio(void *data)
  307. {
  308. struct snd_xferi xfer = { 0 };
  309. int16_t *buf;
  310. unsigned int i, j, numframes = period_size;
  311. int ret, avail;
  312. (void)data;
  313. while(period_size) {
  314. numframes = period_size;
  315. meg4_audiofeed((float*)abuf, numframes);
  316. for(i = j = 0; i < numframes; i++, j += 2)
  317. ibuf[j] = ibuf[j + 1] = abuf[i] * 32767.0f;
  318. buf = ibuf;
  319. do {
  320. xfer.buf = buf;
  321. xfer.frames = numframes > period_size ? period_size : numframes;
  322. xfer.result = 0;
  323. if(!(ret = ioctl(afd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xfer))) {
  324. avail = mmap_status->hw_ptr + ALSA_BUFFER_SIZE - mmap_control->appl_ptr;
  325. if(avail < 0) avail += boundary; else
  326. if((unsigned int)avail >= boundary) avail -= boundary;
  327. numframes -= xfer.result;
  328. buf += xfer.result;
  329. } else if(ret < 0) break;
  330. } while(period_size && numframes > 0);
  331. }
  332. return NULL;
  333. }
  334. /**
  335. * Delay
  336. */
  337. void main_delay(int msec)
  338. {
  339. struct timespec tv;
  340. tv.tv_sec = 0; tv.tv_nsec = msec * 1000000;
  341. while(nanosleep(&tv, &tv) == -1 && tv.tv_nsec > 1000000);
  342. }
  343. /**
  344. * Display screen with fixed scaler ("windowed" mode, pixel perfect, but does not fill the entire screen)
  345. */
  346. void main_fix_scaler(void)
  347. {
  348. uint32_t *src, *dst;
  349. int i, j, k, l, m, p;
  350. src = scrbuf;
  351. dst = (uint32_t*)foffs;
  352. /* optimized upscaler for 1x, 2x, 3x, 4x, 6x and 8x */
  353. p = win_h / meg4.screen.h;
  354. if(!fb_var.red.offset) {
  355. /* RGBA */
  356. switch(p) {
  357. case 1:
  358. for(j = 0, i = meg4.screen.w << 2; j < meg4.screen.h; j++, src += 640, dst += win_dp)
  359. memcpy(dst, src, i);
  360. break;
  361. case 2:
  362. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp2)
  363. for(i = k = 0; i < meg4.screen.w; i++, k += 2)
  364. dst[k] = dst[k + 1] = dst[k + win_dp] = dst[k + win_dp + 1] = src[i];
  365. break;
  366. case 3:
  367. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp3)
  368. for(i = k = 0; i < meg4.screen.w; i++, k += 3)
  369. dst[k] = dst[k + 1] = dst[k + 2] =
  370. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] =
  371. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = src[i];
  372. break;
  373. case 4:
  374. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp4)
  375. for(i = k = 0; i < meg4.screen.w; i++, k += 4)
  376. dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] =
  377. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] =
  378. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
  379. dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] = src[i];
  380. break;
  381. case 6:
  382. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp6)
  383. for(i = k = 0; i < meg4.screen.w; i++, k += 6)
  384. dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] =
  385. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] = dst[k + win_dp + 4] = dst[k + win_dp + 5] =
  386. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
  387. dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] =
  388. dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
  389. dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] =
  390. dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
  391. dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] =
  392. dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
  393. dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] = src[i];
  394. break;
  395. case 8:
  396. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp8)
  397. for(i = k = 0; i < meg4.screen.w; i++, k += 8)
  398. dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] = dst[k + 6] = dst[k + 7] =
  399. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] =
  400. dst[k + win_dp + 4] = dst[k + win_dp + 5] = dst[k + win_dp + 6] = dst[k + win_dp + 7] =
  401. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
  402. dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] = dst[k + win_dp2 + 6] = dst[k + win_dp2 + 7] =
  403. dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
  404. dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] = dst[k + win_dp3 + 6] = dst[k + win_dp3 + 7] =
  405. dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
  406. dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] = dst[k + win_dp4 + 6] = dst[k + win_dp4 + 7] =
  407. dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
  408. dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] = dst[k + win_dp5 + 6] = dst[k + win_dp5 + 7] =
  409. dst[k + win_dp6] = dst[k + win_dp6 + 1] = dst[k + win_dp6 + 2] = dst[k + win_dp6 + 3] =
  410. dst[k + win_dp6 + 4] = dst[k + win_dp6 + 5] = dst[k + win_dp6 + 6] = dst[k + win_dp6 + 7] =
  411. dst[k + win_dp7] = dst[k + win_dp7 + 1] = dst[k + win_dp7 + 2] = dst[k + win_dp7 + 3] =
  412. dst[k + win_dp7 + 4] = dst[k + win_dp7 + 5] = dst[k + win_dp7 + 6] = dst[k + win_dp7 + 7] = src[i];
  413. break;
  414. default:
  415. for(j = 0; j < meg4.screen.h; j++, src += 640)
  416. for(m = 0; m < p; m++, dst += win_dp)
  417. for(i = k = 0; i < meg4.screen.w; i++)
  418. for(l = 0; l < p; l++, k++)
  419. dst[k] = src[i];
  420. break;
  421. }
  422. } else {
  423. /* BGRA */
  424. switch(p) {
  425. case 1:
  426. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp)
  427. for(i = 0; i < meg4.screen.w; i++)
  428. dst[i] = ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
  429. break;
  430. case 2:
  431. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp2)
  432. for(i = k = 0; i < meg4.screen.w; i++, k += 2)
  433. dst[k] = dst[k + 1] = dst[k + win_dp] = dst[k + win_dp + 1] =
  434. ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
  435. break;
  436. case 3:
  437. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp3)
  438. for(i = k = 0; i < meg4.screen.w; i++, k += 3)
  439. dst[k] = dst[k + 1] = dst[k + 2] =
  440. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] =
  441. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] =
  442. ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
  443. break;
  444. case 4:
  445. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp4)
  446. for(i = k = 0; i < meg4.screen.w; i++, k += 4)
  447. dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] =
  448. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] =
  449. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
  450. dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
  451. ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
  452. break;
  453. case 6:
  454. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp6)
  455. for(i = k = 0; i < meg4.screen.w; i++, k += 6)
  456. dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] =
  457. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] = dst[k + win_dp + 4] = dst[k + win_dp + 5] =
  458. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
  459. dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] =
  460. dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
  461. dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] =
  462. dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
  463. dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] =
  464. dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
  465. dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] =
  466. ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
  467. break;
  468. case 8:
  469. for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp8)
  470. for(i = k = 0; i < meg4.screen.w; i++, k += 8)
  471. dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] = dst[k + 6] = dst[k + 7] =
  472. dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] =
  473. dst[k + win_dp + 4] = dst[k + win_dp + 5] = dst[k + win_dp + 6] = dst[k + win_dp + 7] =
  474. dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
  475. dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] = dst[k + win_dp2 + 6] = dst[k + win_dp2 + 7] =
  476. dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
  477. dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] = dst[k + win_dp3 + 6] = dst[k + win_dp3 + 7] =
  478. dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
  479. dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] = dst[k + win_dp4 + 6] = dst[k + win_dp4 + 7] =
  480. dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
  481. dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] = dst[k + win_dp5 + 6] = dst[k + win_dp5 + 7] =
  482. dst[k + win_dp6] = dst[k + win_dp6 + 1] = dst[k + win_dp6 + 2] = dst[k + win_dp6 + 3] =
  483. dst[k + win_dp6 + 4] = dst[k + win_dp6 + 5] = dst[k + win_dp6 + 6] = dst[k + win_dp6 + 7] =
  484. dst[k + win_dp7] = dst[k + win_dp7 + 1] = dst[k + win_dp7 + 2] = dst[k + win_dp7 + 3] =
  485. dst[k + win_dp7 + 4] = dst[k + win_dp7 + 5] = dst[k + win_dp7 + 6] = dst[k + win_dp7 + 7] =
  486. ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
  487. break;
  488. default:
  489. for(j = 0; j < meg4.screen.h; j++, src += 640)
  490. for(m = 0; m < p; m++, dst += win_dp)
  491. for(i = k = 0; i < meg4.screen.w; i++)
  492. for(l = 0; l < p; l++, k++)
  493. dst[k] = ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
  494. break;
  495. }
  496. }
  497. }
  498. /**
  499. * Display screen with arbitrary scaler (fullscreen mode, might be blurry, linear interpolation)
  500. */
  501. void main_arb_scaler(void)
  502. {
  503. uint8_t b[4];
  504. uint32_t *src, *dst, *c00, *c01, *c10, *c11, *csp, *dp, *ep;
  505. int o = 0, x, y, sx, sy, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, lx, ly, l;
  506. int sw = meg4.screen.w, sh = meg4.screen.h, sp = 640, w = win_fw, h = win_fh, p = fb_fix.line_length;
  507. src = scrbuf;
  508. dst = (uint32_t*)ffull;
  509. sx = (int) (65536.0 * (float)sw / (float)w); sy = (int) (65536.0 * (float)sh / (float)h);
  510. csp = src; ep = src + sp * sh - 1; dp = (uint32_t*)((uint8_t*)dst + o);
  511. csx = 0; csax = sax; for(x = 0; x <= w; x++) { *csax = csx; csax++; csx &= 0xffff; csx += sx; }
  512. csy = 0; csay = say; for(y = 0; y <= h; y++) { *csay = csy; csay++; csy &= 0xffff; csy += sy; }
  513. csay = say; ly = 0;
  514. for(y = l = 0; y < h; y++) {
  515. c00 = csp; c01 = csp; c01++; c10 = csp; c10 += sp; c11 = c10; c11++; csax = sax; lx = 0;
  516. for(x = 0; x < w - 1; x++) {
  517. if(c00 > ep) { c00 = ep; } if(c01 > ep) { c01 = ep; } if(c10 > ep) { c10 = ep; } if(c11 > ep) { c11 = ep; }
  518. ex = (*csax & 0xffff); ey = (*csay & 0xffff);
  519. t1 = (((((*c01 >> 24) - (*c00 >> 24)) * ex) >> 16) + (*c00 >> 24)) & 0xff;
  520. t2 = (((((*c11 >> 24) - (*c10 >> 24)) * ex) >> 16) + (*c10 >> 24)) & 0xff;
  521. b[3] = ((((t2 - t1) * ey) >> 16) + t1); if(b[3] == 254) b[3] = 255;
  522. t1 = (((((*c01 & 0xff) - (*c00 & 0xff)) * ex) >> 16) + (*c00 & 0xff)) & 0xff;
  523. t2 = (((((*c11 & 0xff) - (*c10 & 0xff)) * ex) >> 16) + (*c10 & 0xff)) & 0xff;
  524. b[0] = ((((t2 - t1) * ey) >> 16) + t1);
  525. t1 = ((((((*c01 >> 8) & 0xff) - ((*c00 >> 8) & 0xff)) * ex) >> 16) + ((*c00 >> 8) & 0xff)) & 0xff;
  526. t2 = ((((((*c11 >> 8) & 0xff) - ((*c10 >> 8) & 0xff)) * ex) >> 16) + ((*c10 >> 8) & 0xff)) & 0xff;
  527. b[1] = ((((t2 - t1) * ey) >> 16) + t1);
  528. t1 = ((((((*c01 >> 16) & 0xff) - ((*c00 >> 16) & 0xff)) * ex) >> 16) + ((*c00 >> 16) & 0xff)) & 0xff;
  529. t2 = ((((((*c11 >> 16) & 0xff) - ((*c10 >> 16) & 0xff)) * ex) >> 16) + ((*c10 >> 16) & 0xff)) & 0xff;
  530. b[2] = ((((t2 - t1) * ey) >> 16) + t1);
  531. *dp = !fb_var.red.offset ? /* RGBA */ *((uint32_t*)b) : /* BGRA */ (uint32_t)((b[0] << 16) | (b[1] << 8) | b[2]);
  532. dp++; csax++; if(*csax > 0) { sstep = (*csax >> 16); lx += sstep; if(lx < sw) { c00 += sstep; c01 += sstep; c10 += sstep; c11 += sstep; } }
  533. }
  534. csay++; if(*csay > 0) { sstep = (*csay >> 16); ly += sstep; if(ly < sh) csp += (sstep * sp); }
  535. o += p; dp = (uint32_t*)((uint8_t*)dst + o);
  536. }
  537. }
  538. /**
  539. * Print program version and copyright
  540. */
  541. void main_hdr(void)
  542. {
  543. printf("\r\nMEG-4 v%s (fbdev, build %u) by bzt Copyright (C) 2023 GPLv3+\r\n\r\n", meg4ver, BUILD);
  544. }
  545. /**
  546. * The real main procedure
  547. */
  548. int main(int argc, char **argv)
  549. {
  550. struct snd_pcm_hw_params params;
  551. struct snd_pcm_sw_params spar;
  552. struct snd_ctl_elem_list elist;
  553. struct snd_ctl_elem_info ei;
  554. struct snd_ctl_elem_value av;
  555. struct input_event ev[64];
  556. struct timespec ts;
  557. int i, j, k, n, mx = 160, my = 100, emptyalt = 0;
  558. char **infile = NULL, *fn;
  559. char s[5];
  560. uint32_t rrate = 44100;
  561. uint8_t *ptr;
  562. int32_t tickdiff;
  563. uint64_t ticks;
  564. #ifdef USE_INIT
  565. #define MNTFLAGS (MS_SYNCHRONOUS | MS_NODEV | MS_NOEXEC)
  566. struct stat st;
  567. char *lng = LANG, *devs[] = { FLOPPYDEV, "/dev/sda1", "/dev/sdb1", "/dev/sdc1", "/dev/sdd1" };
  568. (void)argc; (void)argv;
  569. /* we must do some housekeeping when we run as the init process. Assume read-only root fs */
  570. mount("none", "/dev", "devtmpfs", 0, NULL);
  571. mount("none", "/proc", "procfs", 0, NULL);
  572. mount("none", "/sys", "sysfs", 0, NULL);
  573. mount("none", "/tmp", "tmpfs", 0, NULL);
  574. /* let's try to mount an external USB stick with the floppy images */
  575. main_floppydir = "/mnt/MEG-4";
  576. for(i = 0; i < (int)(sizeof(devs)/sizeof(devs[0])); i++)
  577. if(!mount(devs[i], "/mnt", "vfat", MNTFLAGS, NULL) || !mount(devs[i], "/mnt", "fat", MNTFLAGS, NULL)) {
  578. /* does this partition already have a MEG-4 directory? If so, look no further */
  579. if(!stat(main_floppydir, &st) ||
  580. /* is this not our internal disk and can we create the floppy data directory on it? */
  581. (stat("/mnt/initrd", &st) && !mkdir(main_floppydir, 0777))) break;
  582. /* no luck, umount and continue */
  583. umount("/mnt");
  584. }
  585. verbose = 1;
  586. main_hdr();
  587. if(i < (int)(sizeof(devs)/sizeof(devs[0])))
  588. main_log(0, "floppy directory on '%s'", devs[i]);
  589. else {
  590. main_log(0, "unable to mount floppy directory");
  591. main_floppydir = NULL;
  592. }
  593. #else
  594. char *lng = getenv("LANG");
  595. main_parsecommandline(argc, argv, &lng, &infile);
  596. main_hdr();
  597. for(i = 0; i < 3; i++) printf(" %s\r\n", copyright[i]);
  598. printf("\r\n");
  599. #endif
  600. fflush(stdout);
  601. strcpy(meg4plat, "fbdev_alsa");
  602. /* set up keymap */
  603. memset(main_keymap, 0, sizeof(main_keymap));
  604. main_keymap[KEY_SPACE] = MEG4_KEY_SPACE;
  605. main_keymap[KEY_APOSTROPHE] = MEG4_KEY_APOSTROPHE;
  606. main_keymap[KEY_COMMA] = MEG4_KEY_COMMA;
  607. main_keymap[KEY_MINUS] = MEG4_KEY_MINUS;
  608. main_keymap[KEY_DOT] = MEG4_KEY_PERIOD;
  609. main_keymap[KEY_SLASH] = MEG4_KEY_SLASH;
  610. main_keymap[KEY_0] = MEG4_KEY_0;
  611. main_keymap[KEY_1] = MEG4_KEY_1;
  612. main_keymap[KEY_2] = MEG4_KEY_2;
  613. main_keymap[KEY_3] = MEG4_KEY_3;
  614. main_keymap[KEY_4] = MEG4_KEY_4;
  615. main_keymap[KEY_5] = MEG4_KEY_5;
  616. main_keymap[KEY_6] = MEG4_KEY_6;
  617. main_keymap[KEY_7] = MEG4_KEY_7;
  618. main_keymap[KEY_8] = MEG4_KEY_8;
  619. main_keymap[KEY_9] = MEG4_KEY_9;
  620. main_keymap[KEY_SEMICOLON] = MEG4_KEY_SEMICOLON;
  621. main_keymap[KEY_EQUAL] = MEG4_KEY_EQUAL;
  622. main_keymap[KEY_A] = MEG4_KEY_A;
  623. main_keymap[KEY_B] = MEG4_KEY_B;
  624. main_keymap[KEY_C] = MEG4_KEY_C;
  625. main_keymap[KEY_D] = MEG4_KEY_D;
  626. main_keymap[KEY_E] = MEG4_KEY_E;
  627. main_keymap[KEY_F] = MEG4_KEY_F;
  628. main_keymap[KEY_G] = MEG4_KEY_G;
  629. main_keymap[KEY_H] = MEG4_KEY_H;
  630. main_keymap[KEY_I] = MEG4_KEY_I;
  631. main_keymap[KEY_J] = MEG4_KEY_J;
  632. main_keymap[KEY_K] = MEG4_KEY_K;
  633. main_keymap[KEY_L] = MEG4_KEY_L;
  634. main_keymap[KEY_M] = MEG4_KEY_M;
  635. main_keymap[KEY_N] = MEG4_KEY_N;
  636. main_keymap[KEY_O] = MEG4_KEY_O;
  637. main_keymap[KEY_P] = MEG4_KEY_P;
  638. main_keymap[KEY_Q] = MEG4_KEY_Q;
  639. main_keymap[KEY_R] = MEG4_KEY_R;
  640. main_keymap[KEY_S] = MEG4_KEY_S;
  641. main_keymap[KEY_T] = MEG4_KEY_T;
  642. main_keymap[KEY_U] = MEG4_KEY_U;
  643. main_keymap[KEY_V] = MEG4_KEY_V;
  644. main_keymap[KEY_X] = MEG4_KEY_X;
  645. main_keymap[KEY_Y] = MEG4_KEY_Y;
  646. main_keymap[KEY_Z] = MEG4_KEY_Z;
  647. main_keymap[KEY_LEFTBRACE] = MEG4_KEY_LBRACKET;
  648. main_keymap[KEY_BACKSLASH] = MEG4_KEY_BACKSLASH;
  649. main_keymap[KEY_RIGHTBRACE] = MEG4_KEY_RBRACKET;
  650. main_keymap[KEY_ENTER] = MEG4_KEY_ENTER;
  651. main_keymap[KEY_TAB] = MEG4_KEY_TAB;
  652. main_keymap[KEY_BACKSPACE] = MEG4_KEY_BACKSPACE;
  653. main_keymap[KEY_INSERT] = MEG4_KEY_INS;
  654. main_keymap[KEY_DELETE] = MEG4_KEY_DEL;
  655. main_keymap[KEY_RIGHT] = MEG4_KEY_RIGHT;
  656. main_keymap[KEY_LEFT] = MEG4_KEY_LEFT;
  657. main_keymap[KEY_DOWN] = MEG4_KEY_DOWN;
  658. main_keymap[KEY_UP] = MEG4_KEY_UP;
  659. main_keymap[KEY_PAGEUP] = MEG4_KEY_PGUP;
  660. main_keymap[KEY_PAGEDOWN] = MEG4_KEY_PGDN;
  661. main_keymap[KEY_HOME] = MEG4_KEY_HOME;
  662. main_keymap[KEY_END] = MEG4_KEY_END;
  663. main_keymap[KEY_CAPSLOCK] = MEG4_KEY_CAPSLOCK;
  664. main_keymap[KEY_SCROLLLOCK] = MEG4_KEY_SCRLOCK;
  665. main_keymap[KEY_NUMLOCK] = MEG4_KEY_NUMLOCK;
  666. main_keymap[KEY_PRINT] = MEG4_KEY_PRSCR;
  667. main_keymap[KEY_PAUSE] = MEG4_KEY_PAUSE;
  668. main_keymap[KEY_F1] = MEG4_KEY_F1;
  669. main_keymap[KEY_F2] = MEG4_KEY_F2;
  670. main_keymap[KEY_F3] = MEG4_KEY_F3;
  671. main_keymap[KEY_F4] = MEG4_KEY_F4;
  672. main_keymap[KEY_F5] = MEG4_KEY_F5;
  673. main_keymap[KEY_F6] = MEG4_KEY_F6;
  674. main_keymap[KEY_F7] = MEG4_KEY_F7;
  675. main_keymap[KEY_F8] = MEG4_KEY_F8;
  676. main_keymap[KEY_F9] = MEG4_KEY_F9;
  677. main_keymap[KEY_F10] = MEG4_KEY_F10;
  678. main_keymap[KEY_F11] = MEG4_KEY_F11;
  679. main_keymap[KEY_F12] = MEG4_KEY_F12;
  680. main_keymap[KEY_KP0] = MEG4_KEY_KP_0;
  681. main_keymap[KEY_KP1] = MEG4_KEY_KP_1;
  682. main_keymap[KEY_KP2] = MEG4_KEY_KP_2;
  683. main_keymap[KEY_KP3] = MEG4_KEY_KP_3;
  684. main_keymap[KEY_KP4] = MEG4_KEY_KP_4;
  685. main_keymap[KEY_KP5] = MEG4_KEY_KP_5;
  686. main_keymap[KEY_KP6] = MEG4_KEY_KP_6;
  687. main_keymap[KEY_KP7] = MEG4_KEY_KP_7;
  688. main_keymap[KEY_KP8] = MEG4_KEY_KP_8;
  689. main_keymap[KEY_KP9] = MEG4_KEY_KP_9;
  690. main_keymap[KEY_KPDOT] = MEG4_KEY_KP_DEC;
  691. main_keymap[KEY_KPSLASH] = MEG4_KEY_KP_DIV;
  692. main_keymap[KEY_KPASTERISK] = MEG4_KEY_KP_MUL;
  693. main_keymap[KEY_KPMINUS] = MEG4_KEY_KP_SUB;
  694. main_keymap[KEY_KPPLUS] = MEG4_KEY_KP_ADD;
  695. main_keymap[KEY_KPENTER] = MEG4_KEY_KP_ENTER;
  696. main_keymap[KEY_KPEQUAL] = MEG4_KEY_KP_EQUAL;
  697. main_keymap[KEY_LEFTSHIFT] = MEG4_KEY_LSHIFT;
  698. main_keymap[KEY_LEFTCTRL] = MEG4_KEY_LCTRL;
  699. main_keymap[KEY_LEFTALT] = MEG4_KEY_LALT;
  700. main_keymap[KEY_LEFTMETA] = MEG4_KEY_LSUPER;
  701. main_keymap[KEY_RIGHTSHIFT] = MEG4_KEY_RSHIFT;
  702. main_keymap[KEY_RIGHTCTRL] = MEG4_KEY_RCTRL;
  703. main_keymap[KEY_RIGHTALT] = MEG4_KEY_RALT;
  704. main_keymap[KEY_RIGHTMETA] = MEG4_KEY_RSUPER;
  705. main_keymap[KEY_MENU] = MEG4_KEY_MENU;
  706. /* huh, wanna see some seriously and conceptually fucked up api? */
  707. if((afd = open("/dev/snd/pcmC0D0p", O_RDWR)) > 0) {
  708. /* set up PCM device */
  709. param_init(&params);
  710. param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
  711. param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_FORMAT_S16_LE);
  712. param_set_min(&params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, ALSA_BUFFER_SIZE);
  713. param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, ALSA_PERIOD_SIZE);
  714. param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, ALSA_BUFFER_SIZE / ALSA_PERIOD_SIZE);
  715. param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 44100);
  716. param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
  717. if(ioctl(afd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) { close(afd); afd = -1; goto noaudio; }
  718. period_size = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
  719. memset(&spar, 0, sizeof(spar));
  720. spar.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
  721. spar.period_step = 1;
  722. spar.avail_min = period_size;
  723. spar.start_threshold = ALSA_BUFFER_SIZE - period_size;
  724. spar.stop_threshold = ALSA_BUFFER_SIZE;
  725. spar.xfer_align = period_size / 2; /* for old kernels */
  726. if(ioctl(afd, SNDRV_PCM_IOCTL_SW_PARAMS, &spar)) { close(afd); afd = -1; goto noaudio; }
  727. boundary = spar.boundary;
  728. mmap_status = mmap(NULL, 4096, PROT_READ, MAP_SHARED, afd, SNDRV_PCM_MMAP_OFFSET_STATUS);
  729. if(!mmap_status || mmap_status == MAP_FAILED) { mmap_status = NULL; close(afd); afd = -1; goto noaudio; }
  730. mmap_control = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, afd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
  731. if(!mmap_control || mmap_control == MAP_FAILED) {
  732. munmap(mmap_status, 4096); mmap_status = NULL; mmap_control = NULL; close(afd); afd = -1; goto noaudio;
  733. }
  734. audio = 1;
  735. /* try to unmute and set hardware volume to max */
  736. if((k = open("/dev/snd/controlC0", O_RDWR)) > 0) {
  737. memset(&elist, 0, sizeof(elist));
  738. if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_LIST, &elist)) {
  739. elist.pids = malloc(elist.count * sizeof(struct snd_ctl_elem_id));
  740. if(elist.pids) {
  741. memset(elist.pids, 0, elist.count * sizeof(struct snd_ctl_elem_id));
  742. elist.space = elist.count;
  743. if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_LIST, &elist))
  744. for(i = 0; i < (int)elist.count; i++) {
  745. memset(&ei, 0, sizeof(ei));
  746. ei.id.numid = elist.pids[i].numid;
  747. if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_INFO, &ei) &&
  748. (ei.access & SNDRV_CTL_ELEM_ACCESS_READWRITE) == SNDRV_CTL_ELEM_ACCESS_READWRITE &&
  749. (ei.type == SNDRV_CTL_ELEM_TYPE_INTEGER || ei.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN) &&
  750. strstr((char*)ei.id.name, SNDRV_CTL_NAME_PLAYBACK)) {
  751. memset(&av, 0, sizeof(av));
  752. av.id.numid = ei.id.numid;
  753. if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_READ, &av)) {
  754. for(j = 0; j < (int)ei.count; j++) av.value.integer.value[j] = ei.value.integer.max;
  755. ioctl(k, SNDRV_CTL_IOCTL_ELEM_WRITE, &av);
  756. }
  757. }
  758. }
  759. free(elist.pids);
  760. }
  761. }
  762. close(k);
  763. }
  764. }
  765. noaudio:
  766. if(verbose && audio) main_log(1, "audio opened %uHz, %u bits", rrate, 16);
  767. scrbuf = (uint32_t*)malloc(640 * 400 * sizeof(uint32_t));
  768. if(!scrbuf) {
  769. main_log(0, "unable to allocate screen buffer");
  770. return 1;
  771. }
  772. main_win();
  773. if(fbuf == NULL) {
  774. main_log(0, "unable to initialize framebuffer");
  775. main_quit();
  776. return 1;
  777. }
  778. win_f = 1;
  779. /* turn on the emulator */
  780. meg4_poweron(lng);
  781. #ifndef NOEDITORS
  782. for(; infile && *infile; infile++) {
  783. if((ptr = main_readfile(*infile, &i))) {
  784. fn = strrchr(*infile, SEP[0]); if(!fn) fn = *infile; else fn++;
  785. meg4_insert(fn, ptr, i);
  786. free(ptr);
  787. }
  788. }
  789. #else
  790. (void)ptr; (void)infile;
  791. #endif
  792. if(audio) {
  793. pthread_create(&th, NULL, main_audio, NULL);
  794. if(ioctl(afd, SNDRV_PCM_IOCTL_PREPARE) < 0) {
  795. munmap(mmap_status, 4096); munmap(mmap_control, 4096); mmap_status = NULL; mmap_control = NULL;
  796. close(afd); afd = -1; audio = 0; period_size = 0;
  797. }
  798. }
  799. meg4_setptr(mx, my);
  800. while(!main_exit) {
  801. clock_gettime(CLOCK_MONOTONIC, &ts);
  802. ticks = (uint64_t) ts.tv_sec * 1000000000 + (uint64_t) ts.tv_nsec;
  803. /* handle user input events */
  804. for(n = 0; n < en; n += 2)
  805. if((k = read(ed[n], ev, sizeof(ev))) >= (int)sizeof(ev[0])) {
  806. for(i = 0, k /= sizeof(ev[0]); i < k; i++)
  807. switch(ed[n + 1]) {
  808. case MOUSE:
  809. /* mouse events */
  810. if(ev[i].type == EV_KEY && ev[i].value >= 0 && ev[i].value <= 1) {
  811. j = ev[i].code == BTN_LEFT ? MEG4_BTN_L : (ev[i].code == BTN_RIGHT ? MEG4_BTN_R : MEG4_BTN_M);
  812. if(ev[i].value) meg4_setbtn(j); else meg4_clrbtn(j);
  813. } else
  814. if(ev[i].type == EV_REL)
  815. switch(ev[i].code) {
  816. case REL_X:
  817. mx += ev[i].value;
  818. if(mx < 0) mx = 0;
  819. if(mx > meg4.screen.w) mx = meg4.screen.w;
  820. meg4_setptr(mx, my);
  821. break;
  822. case REL_Y:
  823. my += ev[i].value;
  824. if(my < 0) my = 0;
  825. if(my > meg4.screen.h) my = meg4.screen.h;
  826. meg4_setptr(mx, my);
  827. break;
  828. case REL_WHEEL: meg4_setscr(ev[i].value > 0, ev[i].value < 0, 0, 0); break;
  829. }
  830. break;
  831. case KBD:
  832. /* keyboard events */
  833. if(ev[i].type == EV_KEY && ev[i].value >= 0 && ev[i].value <= 2) {
  834. if(ev[i].code > 0 && ev[i].code < (sizeof(main_keymap)/sizeof(main_keymap[0]))) {
  835. if(ev[i].value == 0) {
  836. /* key release */
  837. if(ev[i].code == KEY_LEFTCTRL || ev[i].code == KEY_LEFTALT) main_alt = 0;
  838. if(ev[i].code == KEY_LEFTMETA || ev[i].code == KEY_RIGHTMETA || ev[i].code == KEY_RIGHTALT) main_meta = 0;
  839. if(ev[i].code == KEY_LEFTSHIFT || ev[i].code == KEY_RIGHTSHIFT) main_sh = 0;
  840. if(ev[i].code == KEY_CAPSLOCK) main_caps = 0;
  841. if(ev[i].code == KEY_LEFTALT && main_sh && emptyalt) main_kbd ^= 1;
  842. emptyalt = 0;
  843. meg4_clrkey(main_keymap[ev[i].code]);
  844. } else
  845. if(ev[i].value == 1) {
  846. /* key press */
  847. if(ev[i].code == KEY_LEFTCTRL || ev[i].code == KEY_LEFTALT) main_alt = 1;
  848. if(ev[i].code == KEY_LEFTMETA || ev[i].code == KEY_RIGHTMETA || ev[i].code == KEY_RIGHTALT) { main_meta = 1; main_alt = 0; }
  849. if(ev[i].code == KEY_LEFTSHIFT || ev[i].code == KEY_RIGHTSHIFT) main_sh = 1;
  850. if(ev[i].code == KEY_CAPSLOCK) main_caps = 1;
  851. emptyalt = ev[i].code == KEY_LEFTALT;
  852. switch(ev[i].code) {
  853. case KEY_ESC: if(main_alt) main_exit = 1; else meg4_pushkey("\x1b\0\0"); break;
  854. case KEY_F1: meg4_pushkey("F1\0"); break;
  855. case KEY_F2: meg4_pushkey("F2\0"); break;
  856. case KEY_F3: meg4_pushkey("F3\0"); break;
  857. case KEY_F4: meg4_pushkey("F4\0"); break;
  858. case KEY_F5: meg4_pushkey("F5\0"); break;
  859. case KEY_F6: meg4_pushkey("F6\0"); break;
  860. case KEY_F7: meg4_pushkey("F7\0"); break;
  861. case KEY_F8: meg4_pushkey("F8\0"); break;
  862. case KEY_F9: meg4_pushkey("F9\0"); break;
  863. case KEY_F10: meg4_pushkey("F10"); break;
  864. case KEY_F11: main_fullscreen(); break;
  865. case KEY_F12: meg4_pushkey("F12"); break;
  866. case KEY_PRINT: meg4_pushkey("PSc"); break;
  867. case KEY_SCROLLLOCK: meg4_pushkey("SLk"); break;
  868. case KEY_NUMLOCK: meg4_pushkey("NLk"); break;
  869. case KEY_BACKSPACE: meg4_pushkey("\b\0\0"); break;
  870. case KEY_TAB: meg4_pushkey("\t\0\0"); break;
  871. case KEY_ENTER: case KEY_KPENTER: if(main_alt) main_fullscreen(); else meg4_pushkey("\n\0\0"); break;
  872. case KEY_CAPSLOCK: meg4_pushkey("CLk"); break;
  873. case KEY_UP: meg4_pushkey("Up\0"); break;
  874. case KEY_DOWN: meg4_pushkey("Down"); break;
  875. case KEY_LEFT: meg4_pushkey("Left"); break;
  876. case KEY_RIGHT: meg4_pushkey("Rght"); break;
  877. case KEY_HOME: meg4_pushkey("Home"); break;
  878. case KEY_END: meg4_pushkey("End"); break;
  879. case KEY_PAGEUP: meg4_pushkey("PgUp"); break;
  880. case KEY_PAGEDOWN: meg4_pushkey("PgDn"); break;
  881. case KEY_INSERT: meg4_pushkey("Ins"); break;
  882. case KEY_DELETE: meg4_pushkey("Del"); break;
  883. default:
  884. if(main_alt && s[0] == 'q' && !s[1]) main_exit = 1;
  885. if(!main_alt && ev[i].code < sizeof(main_kbdlayout[0])/(sizeof(main_kbdlayout[0][0])*4)) {
  886. memset(s, 0, sizeof(s));
  887. strncpy(s, main_kbdlayout[main_kbd][(ev[i].code << 2) | (main_meta << 1) | (main_caps ^ main_sh)], 4);
  888. if(s[0]) meg4_pushkey(s);
  889. }
  890. break;
  891. }
  892. meg4_setkey(main_keymap[ev[i].code]);
  893. }
  894. }
  895. }
  896. break;
  897. default:
  898. /* controller events */
  899. j = ed[n + 1] - PAD;
  900. if(j < 4 && ev[i].type == EV_KEY) {
  901. if(ev[i].value == 0) {
  902. switch(ev[i].code) {
  903. case BTN_DPAD_DOWN: meg4_clrpad(j, MEG4_BTN_D); break;
  904. case BTN_DPAD_UP: meg4_clrpad(j, MEG4_BTN_U); break;
  905. case BTN_DPAD_LEFT: meg4_clrpad(j, MEG4_BTN_L); break;
  906. case BTN_DPAD_RIGHT:meg4_clrpad(j, MEG4_BTN_R); break;
  907. case BTN_A: meg4_clrpad(j, MEG4_BTN_A); break;
  908. case BTN_B: meg4_clrpad(j, MEG4_BTN_B); break;
  909. case BTN_X: meg4_clrpad(j, MEG4_BTN_X); break;
  910. case BTN_Y: meg4_clrpad(j, MEG4_BTN_Y); break;
  911. }
  912. } else
  913. if(ev[i].value == 1) {
  914. switch(ev[i].code) {
  915. case BTN_DPAD_DOWN: meg4_setpad(j, MEG4_BTN_D); break;
  916. case BTN_DPAD_UP: meg4_setpad(j, MEG4_BTN_U); break;
  917. case BTN_DPAD_LEFT: meg4_setpad(j, MEG4_BTN_L); break;
  918. case BTN_DPAD_RIGHT:meg4_setpad(j, MEG4_BTN_R); break;
  919. case BTN_A: meg4_setpad(j, MEG4_BTN_A); break;
  920. case BTN_B: meg4_setpad(j, MEG4_BTN_B); break;
  921. case BTN_X: meg4_setpad(j, MEG4_BTN_X); break;
  922. case BTN_Y: meg4_setpad(j, MEG4_BTN_Y); break;
  923. }
  924. }
  925. }
  926. break;
  927. }
  928. }
  929. /* run the emulator and display screen */
  930. meg4_run();
  931. meg4_redraw(scrbuf, 640, 400, 640 * 4);
  932. if(win_f) main_arb_scaler();
  933. else main_fix_scaler();
  934. /* delay to run loop at 60 FPS */
  935. clock_gettime(CLOCK_MONOTONIC, &ts);
  936. tickdiff = ((1000000000/60) - (((uint64_t) ts.tv_sec * 1000000000 + (uint64_t) ts.tv_nsec) - ticks)) / 1000000;
  937. if(tickdiff > 0 && tickdiff < 1000) main_delay(tickdiff);
  938. }
  939. main_quit();
  940. return 0;
  941. }