123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983 |
- /*
- * meg4/platform/fbdev_alsa/main.c
- *
- * Copyright (C) 2023 bzt
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * @brief Linux FrameBuffer + ALSA "platform" for the MEG-4
- *
- */
- #define _POSIX_C_SOURCE 199309L /* needed for timespec and nanosleep() */
- #include <time.h>
- #include <fcntl.h>
- #include <dirent.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <termios.h>
- #include <sys/time.h>
- #include <sys/ioctl.h>
- #include <sys/wait.h>
- #include <sys/mman.h>
- #include <sys/reboot.h>
- #include <sys/mount.h>
- #include <linux/kd.h>
- #include <linux/fb.h>
- #include <linux/input.h>
- #include <sound/asound.h>
- #include "meg4.h"
- #define ALSA_BUFFER_SIZE 4096
- #define ALSA_PERIOD_SIZE 1024
- enum { KBD, MOUSE, PAD };
- int fb = -1, en = 0, ed[256], *sax = NULL, *say = NULL;
- struct fb_fix_screeninfo fb_fix;
- struct fb_var_screeninfo fb_var, fb_orig;
- uint32_t *scrbuf = NULL;
- uint8_t *fbuf = NULL, *foffs, *ffull;
- struct termios oldt, newt;
- int afd = -1, audio = 0;
- volatile unsigned int period_size, boundary;
- struct snd_pcm_mmap_status *mmap_status;
- struct snd_pcm_mmap_control *mmap_control;
- float abuf[ALSA_BUFFER_SIZE];
- int16_t ibuf[2*ALSA_BUFFER_SIZE];
- pthread_t th = 0;
- void sync(void);
- 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;
- 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;
- void main_delay(int msec);
- /* keyboard layout mapping */
- const char *main_kbdlayout[2][128*4] = { {
- /* KEY_RESERVED 0 */ "", "", "", "", /* first layout is user configurable */
- /* KEY_ESC 1 */ "", "", "", "",
- #ifdef KBDMAP
- #include KBDMAP
- #else
- #include "us.h"
- #endif
- }, {
- /* KEY_RESERVED 0 */ "", "", "", "", /* second layout is always International */
- /* KEY_ESC 1 */ "", "", "", "",
- #include "us.h"
- } };
- /* interface's language */
- #ifndef LANG
- #define LANG "en"
- #endif
- /* the device and partition with the "MEG-4" directory, where the floppy images reside */
- #ifndef FLOPPYDEV
- #define FLOPPYDEV "/dev/sda1"
- #endif
- #define meg4_showcursor()
- #define meg4_hidecursor()
- #include "../common.h"
- /* helpers for hw_params */
- static struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
- {
- return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
- }
- static struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
- {
- return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
- }
- static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
- {
- struct snd_mask *m = param_to_mask(p, n);
- if (bit >= SNDRV_MASK_MAX)
- return;
- m->bits[0] = 0;
- m->bits[1] = 0;
- m->bits[bit >> 5] |= (1 << (bit & 31));
- }
- static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned int val)
- {
- struct snd_interval *i = param_to_interval(p, n);
- i->min = val;
- }
- static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int val)
- {
- struct snd_interval *i = param_to_interval(p, n);
- i->min = val;
- i->max = val;
- i->integer = 1;
- }
- static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n)
- {
- struct snd_interval *i = param_to_interval(p, n);
- return (i->integer) ? i->max : 0;
- }
- static void param_init(struct snd_pcm_hw_params *p)
- {
- struct snd_mask *m;
- struct snd_interval *i;
- int n;
- memset(p, 0, sizeof(struct snd_pcm_hw_params));
- for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
- n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
- m = param_to_mask(p, n);
- m->bits[0] = ~0;
- m->bits[1] = ~0;
- }
- for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
- n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
- i = param_to_interval(p, n);
- i->min = 0;
- i->max = ~0;
- }
- p->rmask = ~0U;
- p->cmask = 0;
- p->info = ~0U;
- }
- /**
- * Exit emulator
- */
- void main_quit(void)
- {
- #ifdef USE_INIT
- pid_t pid;
- #endif
- int i;
- main_log(1, "quitting... ");
- meg4_poweroff();
- for(i = 0; i < en; i += 2)
- if(ed[i] > 0) { close(ed[i]); ed[i] = -1; }
- if(audio) {
- period_size = 0;
- if(th) { pthread_cancel(th); pthread_join(th, NULL); th = 0; }
- if(mmap_status) munmap(mmap_status, 4096);
- if(mmap_control) munmap(mmap_control, 4096);
- if(afd > 0) { ioctl(afd, SNDRV_PCM_IOCTL_DRAIN); close(afd); afd = -1; }
- }
- if(scrbuf) { free(scrbuf); scrbuf = NULL; }
- if(sax) { free(sax); sax = NULL; }
- if(say) { free(say); say = NULL; }
- 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; }
- if(fb >= 0) {
- if(fb_orig.bits_per_pixel != 32) ioctl(fb, FBIOPUT_VSCREENINFO, &fb_orig);
- close(fb);
- fprintf(stdout, "\x1b[H\x1b[2J");
- }
- fprintf(stdout, "\x1b[?0c\x1b[?1q\x1b[?25h"); fflush(stdout);
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &oldt);
- #ifdef USE_INIT
- /* if we're running as init, make sure everything is written out to disk, and then power off the machine */
- sync();
- umount("/mnt");
- if((pid = fork()) == 0) { reboot(RB_POWER_OFF); exit(0); }
- waitpid(pid, NULL, 0);
- sleep(1);
- #endif
- exit(0);
- }
- /**
- * Create window
- */
- void main_win(void)
- {
- DIR *dh;
- struct dirent *de;
- /* Linux kernel limits device names in 256 bytes, so this must be enough even with the path prefix */
- char dev[512] = "/dev/input", *fbd;
- int l, x, y, k = 0, c = 0;
- uint64_t ev_type, key_type[KEY_MAX/64 + 1];
- tcgetattr(STDIN_FILENO, &oldt);
- memcpy(&newt, &oldt, sizeof(newt));
- oldt.c_lflag |= ECHO;
- newt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &newt);
- /* get keyboard, mouse and gamepad event devices */
- dh = opendir(dev); en = 0; memset(ed, 0, sizeof(ed)); dev[10] = '/';
- if(dh) {
- while(en < 256 && (de = readdir(dh)) != NULL) {
- if(memcmp(de->d_name, "event", 5)) continue;
- strcpy(dev + 11, de->d_name);
- ed[en] = open(dev, O_RDONLY | O_NDELAY | O_NONBLOCK);
- if(ed[en] > 0) {
- /* detect event device's type */
- ev_type = 0; memset(key_type, 0, sizeof(key_type));
- if(ioctl(ed[en], EVIOCGBIT(0, sizeof(ev_type)), &ev_type) >= 0 && (ev_type & (1 << EV_KEY)) &&
- ioctl(ed[en], EVIOCGBIT(EV_KEY, KEY_MAX+1), &key_type) >= 0) {
- /* let's see what keys are produced with EV_KEY events */
- if(key_type[BTN_GAMEPAD / 64] & (1UL << (BTN_GAMEPAD & 63))) { ed[en + 1] = PAD + c; c++; en += 2; } else
- if(key_type[BTN_MOUSE / 64] & (1UL << (BTN_MOUSE & 63))) { ed[en + 1] = MOUSE; en += 2; } else
- if(key_type[KEY_ENTER / 64] & (1UL << (KEY_ENTER & 63))) { ed[en + 1] = KBD; k++; en += 2; } else ev_type = 0;
- }
- if(!ev_type) { close(ed[en]); ed[en] = -1; }
- }
- }
- closedir(dh);
- }
- if(k < 1) { main_log(0, "no keyboard device"); return; }
- /* get video device */
- fbd = "/dev/fb0"; fb = open(fbd, O_RDWR);
- if(fb < 0) { fbd = "/dev/graphics/fb0"; fb = open(fbd, O_RDWR); }
- if(fb < 0) return;
- /* configure framebuffer */
- if(ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) != 0 || fb_var.xres < 640 || fb_var.yres < 400) {
- /* try to set resolution */
- close(fb);
- l = open("/sys/class/graphics/fb0/mode", O_WRONLY); if(l > 0) { x = write(l, "U:1280x800p-0\n", 14); close(l); }
- fb = open(fbd, O_RDWR); if(fb < 0) return;
- if(ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) != 0 || fb_var.xres < 640 || fb_var.yres < 400) { close(fb); fb = -1; return; }
- }
- memcpy(&fb_orig, &fb_var, sizeof(struct fb_var_screeninfo));
- /* clear screen and hide cursor */
- fprintf(stdout, "\x1b[H\x1b[2J\x1b[?12l\x1b[?17c\x1b[?2q\x1b[?25l"); fflush(stdout);
- l = open("/sys/class/graphics/fbcon/cursor_blink", O_WRONLY); if(l > 0) { x = write(l, "0\n", 2); close(l); }
- if(fb_var.bits_per_pixel != 32) {
- fb_var.bits_per_pixel = 32;
- if(ioctl(fb, FBIOPUT_VSCREENINFO, &fb_var) != 0 ||
- ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) != 0 || fb_var.bits_per_pixel != 32) { close(fb); fb = -1; return; }
- }
- if(ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) != 0 || fb_fix.type != FB_TYPE_PACKED_PIXELS) { close(fb); fb = -1; return; }
- fbuf = (uint8_t*)mmap(0, fb_fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
- if(fbuf == NULL || (intptr_t)fbuf == -1) { close(fb); fb = -1; fbuf = NULL; return; }
- memset(fbuf, 0, fb_fix.smem_len);
- /* calculate windowed and full screen sizes, keeping aspect ratio */
- main_w = fb_var.xres; main_h = fb_var.yres;
- win_w = 640; win_h = 400;
- while(main_w >= win_w + 640 && main_h >= win_h + 400) { win_w += 640; win_h += 400; }
- x = (main_w - win_w) >> 1; y = (main_h - win_h) >> 1;
- foffs = fbuf + y * fb_fix.line_length + (x << 2);
- win_fw = main_w; win_fh = 400 * main_w / 640;
- if(win_fh > main_h) { win_fh = main_h; win_fw = 640 * main_h / 400; }
- x = (main_w - win_fw) >> 1; y = (main_h - win_fh) >> 1;
- ffull = fbuf + y * fb_fix.line_length + (x << 2);
- l = (win_fw > win_fh ? win_fw : win_fh) + 1;
- sax = (int*)malloc(l * sizeof(int)); say = (int*)malloc(l * sizeof(int));
- win_dp = fb_fix.line_length >> 2; win_dp2 = win_dp << 1; win_dp3 = win_dp * 3; win_dp4 = win_dp << 2;
- win_dp5 = win_dp * 5; win_dp6 = win_dp * 6; win_dp7 = win_dp * 7; win_dp8 = win_dp << 3;
- }
- /**
- * Toggle fullscreen
- */
- void main_fullscreen(void)
- {
- memset(fbuf, 0, fb_fix.smem_len);
- win_f ^= 1;
- }
- /**
- * Make window focused
- */
- void main_focus(void)
- {
- }
- /**
- * Get text from clipboard (must be freed by caller)
- */
- char *main_getclipboard(void)
- {
- return NULL;
- }
- /**
- * Set text to clipboard
- */
- void main_setclipboard(char *str)
- {
- (void)str;
- }
- /**
- * Show on-screen keyboard
- */
- void main_osk_show(void)
- {
- }
- /**
- * Hide on-screen keyboard
- */
- void main_osk_hide(void)
- {
- }
- /**
- * Audio callback
- */
- static void *main_audio(void *data)
- {
- struct snd_xferi xfer = { 0 };
- int16_t *buf;
- unsigned int i, j, numframes = period_size;
- int ret, avail;
- (void)data;
- while(period_size) {
- numframes = period_size;
- meg4_audiofeed((float*)abuf, numframes);
- for(i = j = 0; i < numframes; i++, j += 2)
- ibuf[j] = ibuf[j + 1] = abuf[i] * 32767.0f;
- buf = ibuf;
- do {
- xfer.buf = buf;
- xfer.frames = numframes > period_size ? period_size : numframes;
- xfer.result = 0;
- if(!(ret = ioctl(afd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xfer))) {
- avail = mmap_status->hw_ptr + ALSA_BUFFER_SIZE - mmap_control->appl_ptr;
- if(avail < 0) avail += boundary; else
- if((unsigned int)avail >= boundary) avail -= boundary;
- numframes -= xfer.result;
- buf += xfer.result;
- } else if(ret < 0) break;
- } while(period_size && numframes > 0);
- }
- return NULL;
- }
- /**
- * Delay
- */
- void main_delay(int msec)
- {
- struct timespec tv;
- tv.tv_sec = 0; tv.tv_nsec = msec * 1000000;
- while(nanosleep(&tv, &tv) == -1 && tv.tv_nsec > 1000000);
- }
- /**
- * Display screen with fixed scaler ("windowed" mode, pixel perfect, but does not fill the entire screen)
- */
- void main_fix_scaler(void)
- {
- uint32_t *src, *dst;
- int i, j, k, l, m, p;
- src = scrbuf;
- dst = (uint32_t*)foffs;
- /* optimized upscaler for 1x, 2x, 3x, 4x, 6x and 8x */
- p = win_h / meg4.screen.h;
- if(!fb_var.red.offset) {
- /* RGBA */
- switch(p) {
- case 1:
- for(j = 0, i = meg4.screen.w << 2; j < meg4.screen.h; j++, src += 640, dst += win_dp)
- memcpy(dst, src, i);
- break;
- case 2:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp2)
- for(i = k = 0; i < meg4.screen.w; i++, k += 2)
- dst[k] = dst[k + 1] = dst[k + win_dp] = dst[k + win_dp + 1] = src[i];
- break;
- case 3:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp3)
- for(i = k = 0; i < meg4.screen.w; i++, k += 3)
- dst[k] = dst[k + 1] = dst[k + 2] =
- dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = src[i];
- break;
- case 4:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp4)
- for(i = k = 0; i < meg4.screen.w; i++, k += 4)
- dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] =
- dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
- dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] = src[i];
- break;
- case 6:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp6)
- for(i = k = 0; i < meg4.screen.w; i++, k += 6)
- dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] =
- 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] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
- dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] =
- dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
- dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] =
- dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
- dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] =
- dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
- dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] = src[i];
- break;
- case 8:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp8)
- for(i = k = 0; i < meg4.screen.w; i++, k += 8)
- dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] = dst[k + 6] = dst[k + 7] =
- 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] = dst[k + win_dp + 6] = dst[k + win_dp + 7] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
- dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] = dst[k + win_dp2 + 6] = dst[k + win_dp2 + 7] =
- dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
- dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] = dst[k + win_dp3 + 6] = dst[k + win_dp3 + 7] =
- dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
- dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] = dst[k + win_dp4 + 6] = dst[k + win_dp4 + 7] =
- dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
- dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] = dst[k + win_dp5 + 6] = dst[k + win_dp5 + 7] =
- dst[k + win_dp6] = dst[k + win_dp6 + 1] = dst[k + win_dp6 + 2] = dst[k + win_dp6 + 3] =
- dst[k + win_dp6 + 4] = dst[k + win_dp6 + 5] = dst[k + win_dp6 + 6] = dst[k + win_dp6 + 7] =
- dst[k + win_dp7] = dst[k + win_dp7 + 1] = dst[k + win_dp7 + 2] = dst[k + win_dp7 + 3] =
- dst[k + win_dp7 + 4] = dst[k + win_dp7 + 5] = dst[k + win_dp7 + 6] = dst[k + win_dp7 + 7] = src[i];
- break;
- default:
- for(j = 0; j < meg4.screen.h; j++, src += 640)
- for(m = 0; m < p; m++, dst += win_dp)
- for(i = k = 0; i < meg4.screen.w; i++)
- for(l = 0; l < p; l++, k++)
- dst[k] = src[i];
- break;
- }
- } else {
- /* BGRA */
- switch(p) {
- case 1:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp)
- for(i = 0; i < meg4.screen.w; i++)
- dst[i] = ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
- break;
- case 2:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp2)
- for(i = k = 0; i < meg4.screen.w; i++, k += 2)
- dst[k] = dst[k + 1] = dst[k + win_dp] = dst[k + win_dp + 1] =
- ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
- break;
- case 3:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp3)
- for(i = k = 0; i < meg4.screen.w; i++, k += 3)
- dst[k] = dst[k + 1] = dst[k + 2] =
- dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] =
- ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
- break;
- case 4:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp4)
- for(i = k = 0; i < meg4.screen.w; i++, k += 4)
- dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] =
- dst[k + win_dp] = dst[k + win_dp + 1] = dst[k + win_dp + 2] = dst[k + win_dp + 3] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
- dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
- ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
- break;
- case 6:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp6)
- for(i = k = 0; i < meg4.screen.w; i++, k += 6)
- dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] =
- 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] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
- dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] =
- dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
- dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] =
- dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
- dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] =
- dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
- dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] =
- ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
- break;
- case 8:
- for(j = 0; j < meg4.screen.h; j++, src += 640, dst += win_dp8)
- for(i = k = 0; i < meg4.screen.w; i++, k += 8)
- dst[k] = dst[k + 1] = dst[k + 2] = dst[k + 3] = dst[k + 4] = dst[k + 5] = dst[k + 6] = dst[k + 7] =
- 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] = dst[k + win_dp + 6] = dst[k + win_dp + 7] =
- dst[k + win_dp2] = dst[k + win_dp2 + 1] = dst[k + win_dp2 + 2] = dst[k + win_dp2 + 3] =
- dst[k + win_dp2 + 4] = dst[k + win_dp2 + 5] = dst[k + win_dp2 + 6] = dst[k + win_dp2 + 7] =
- dst[k + win_dp3] = dst[k + win_dp3 + 1] = dst[k + win_dp3 + 2] = dst[k + win_dp3 + 3] =
- dst[k + win_dp3 + 4] = dst[k + win_dp3 + 5] = dst[k + win_dp3 + 6] = dst[k + win_dp3 + 7] =
- dst[k + win_dp4] = dst[k + win_dp4 + 1] = dst[k + win_dp4 + 2] = dst[k + win_dp4 + 3] =
- dst[k + win_dp4 + 4] = dst[k + win_dp4 + 5] = dst[k + win_dp4 + 6] = dst[k + win_dp4 + 7] =
- dst[k + win_dp5] = dst[k + win_dp5 + 1] = dst[k + win_dp5 + 2] = dst[k + win_dp5 + 3] =
- dst[k + win_dp5 + 4] = dst[k + win_dp5 + 5] = dst[k + win_dp5 + 6] = dst[k + win_dp5 + 7] =
- dst[k + win_dp6] = dst[k + win_dp6 + 1] = dst[k + win_dp6 + 2] = dst[k + win_dp6 + 3] =
- dst[k + win_dp6 + 4] = dst[k + win_dp6 + 5] = dst[k + win_dp6 + 6] = dst[k + win_dp6 + 7] =
- dst[k + win_dp7] = dst[k + win_dp7 + 1] = dst[k + win_dp7 + 2] = dst[k + win_dp7 + 3] =
- dst[k + win_dp7 + 4] = dst[k + win_dp7 + 5] = dst[k + win_dp7 + 6] = dst[k + win_dp7 + 7] =
- ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
- break;
- default:
- for(j = 0; j < meg4.screen.h; j++, src += 640)
- for(m = 0; m < p; m++, dst += win_dp)
- for(i = k = 0; i < meg4.screen.w; i++)
- for(l = 0; l < p; l++, k++)
- dst[k] = ((src[i] & 0xff) << 16) | (src[i] & 0xff00) | ((src[i] >> 16) & 0xff);
- break;
- }
- }
- }
- /**
- * Display screen with arbitrary scaler (fullscreen mode, might be blurry, linear interpolation)
- */
- void main_arb_scaler(void)
- {
- uint8_t b[4];
- uint32_t *src, *dst, *c00, *c01, *c10, *c11, *csp, *dp, *ep;
- int o = 0, x, y, sx, sy, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, lx, ly, l;
- int sw = meg4.screen.w, sh = meg4.screen.h, sp = 640, w = win_fw, h = win_fh, p = fb_fix.line_length;
- src = scrbuf;
- dst = (uint32_t*)ffull;
- sx = (int) (65536.0 * (float)sw / (float)w); sy = (int) (65536.0 * (float)sh / (float)h);
- csp = src; ep = src + sp * sh - 1; dp = (uint32_t*)((uint8_t*)dst + o);
- csx = 0; csax = sax; for(x = 0; x <= w; x++) { *csax = csx; csax++; csx &= 0xffff; csx += sx; }
- csy = 0; csay = say; for(y = 0; y <= h; y++) { *csay = csy; csay++; csy &= 0xffff; csy += sy; }
- csay = say; ly = 0;
- for(y = l = 0; y < h; y++) {
- c00 = csp; c01 = csp; c01++; c10 = csp; c10 += sp; c11 = c10; c11++; csax = sax; lx = 0;
- for(x = 0; x < w - 1; x++) {
- if(c00 > ep) { c00 = ep; } if(c01 > ep) { c01 = ep; } if(c10 > ep) { c10 = ep; } if(c11 > ep) { c11 = ep; }
- ex = (*csax & 0xffff); ey = (*csay & 0xffff);
- t1 = (((((*c01 >> 24) - (*c00 >> 24)) * ex) >> 16) + (*c00 >> 24)) & 0xff;
- t2 = (((((*c11 >> 24) - (*c10 >> 24)) * ex) >> 16) + (*c10 >> 24)) & 0xff;
- b[3] = ((((t2 - t1) * ey) >> 16) + t1); if(b[3] == 254) b[3] = 255;
- t1 = (((((*c01 & 0xff) - (*c00 & 0xff)) * ex) >> 16) + (*c00 & 0xff)) & 0xff;
- t2 = (((((*c11 & 0xff) - (*c10 & 0xff)) * ex) >> 16) + (*c10 & 0xff)) & 0xff;
- b[0] = ((((t2 - t1) * ey) >> 16) + t1);
- t1 = ((((((*c01 >> 8) & 0xff) - ((*c00 >> 8) & 0xff)) * ex) >> 16) + ((*c00 >> 8) & 0xff)) & 0xff;
- t2 = ((((((*c11 >> 8) & 0xff) - ((*c10 >> 8) & 0xff)) * ex) >> 16) + ((*c10 >> 8) & 0xff)) & 0xff;
- b[1] = ((((t2 - t1) * ey) >> 16) + t1);
- t1 = ((((((*c01 >> 16) & 0xff) - ((*c00 >> 16) & 0xff)) * ex) >> 16) + ((*c00 >> 16) & 0xff)) & 0xff;
- t2 = ((((((*c11 >> 16) & 0xff) - ((*c10 >> 16) & 0xff)) * ex) >> 16) + ((*c10 >> 16) & 0xff)) & 0xff;
- b[2] = ((((t2 - t1) * ey) >> 16) + t1);
- *dp = !fb_var.red.offset ? /* RGBA */ *((uint32_t*)b) : /* BGRA */ (uint32_t)((b[0] << 16) | (b[1] << 8) | b[2]);
- dp++; csax++; if(*csax > 0) { sstep = (*csax >> 16); lx += sstep; if(lx < sw) { c00 += sstep; c01 += sstep; c10 += sstep; c11 += sstep; } }
- }
- csay++; if(*csay > 0) { sstep = (*csay >> 16); ly += sstep; if(ly < sh) csp += (sstep * sp); }
- o += p; dp = (uint32_t*)((uint8_t*)dst + o);
- }
- }
- /**
- * Print program version and copyright
- */
- void main_hdr(void)
- {
- printf("\r\nMEG-4 v%s (fbdev, build %u) by bzt Copyright (C) 2023 GPLv3+\r\n\r\n", meg4ver, BUILD);
- }
- /**
- * The real main procedure
- */
- int main(int argc, char **argv)
- {
- struct snd_pcm_hw_params params;
- struct snd_pcm_sw_params spar;
- struct snd_ctl_elem_list elist;
- struct snd_ctl_elem_info ei;
- struct snd_ctl_elem_value av;
- struct input_event ev[64];
- struct timespec ts;
- int i, j, k, n, mx = 160, my = 100, emptyalt = 0;
- char **infile = NULL, *fn;
- char s[5];
- uint32_t rrate = 44100;
- uint8_t *ptr;
- int32_t tickdiff;
- uint64_t ticks;
- #ifdef USE_INIT
- #define MNTFLAGS (MS_SYNCHRONOUS | MS_NODEV | MS_NOEXEC)
- struct stat st;
- char *lng = LANG, *devs[] = { FLOPPYDEV, "/dev/sda1", "/dev/sdb1", "/dev/sdc1", "/dev/sdd1" };
- (void)argc; (void)argv;
- /* we must do some housekeeping when we run as the init process. Assume read-only root fs */
- mount("none", "/dev", "devtmpfs", 0, NULL);
- mount("none", "/proc", "procfs", 0, NULL);
- mount("none", "/sys", "sysfs", 0, NULL);
- mount("none", "/tmp", "tmpfs", 0, NULL);
- /* let's try to mount an external USB stick with the floppy images */
- main_floppydir = "/mnt/MEG-4";
- for(i = 0; i < (int)(sizeof(devs)/sizeof(devs[0])); i++)
- if(!mount(devs[i], "/mnt", "vfat", MNTFLAGS, NULL) || !mount(devs[i], "/mnt", "fat", MNTFLAGS, NULL)) {
- /* does this partition already have a MEG-4 directory? If so, look no further */
- if(!stat(main_floppydir, &st) ||
- /* is this not our internal disk and can we create the floppy data directory on it? */
- (stat("/mnt/initrd", &st) && !mkdir(main_floppydir, 0777))) break;
- /* no luck, umount and continue */
- umount("/mnt");
- }
- verbose = 1;
- main_hdr();
- if(i < (int)(sizeof(devs)/sizeof(devs[0])))
- main_log(0, "floppy directory on '%s'", devs[i]);
- else {
- main_log(0, "unable to mount floppy directory");
- main_floppydir = NULL;
- }
- #else
- char *lng = getenv("LANG");
- main_parsecommandline(argc, argv, &lng, &infile);
- main_hdr();
- for(i = 0; i < 3; i++) printf(" %s\r\n", copyright[i]);
- printf("\r\n");
- #endif
- fflush(stdout);
- strcpy(meg4plat, "fbdev_alsa");
- /* set up keymap */
- memset(main_keymap, 0, sizeof(main_keymap));
- main_keymap[KEY_SPACE] = MEG4_KEY_SPACE;
- main_keymap[KEY_APOSTROPHE] = MEG4_KEY_APOSTROPHE;
- main_keymap[KEY_COMMA] = MEG4_KEY_COMMA;
- main_keymap[KEY_MINUS] = MEG4_KEY_MINUS;
- main_keymap[KEY_DOT] = MEG4_KEY_PERIOD;
- main_keymap[KEY_SLASH] = MEG4_KEY_SLASH;
- main_keymap[KEY_0] = MEG4_KEY_0;
- main_keymap[KEY_1] = MEG4_KEY_1;
- main_keymap[KEY_2] = MEG4_KEY_2;
- main_keymap[KEY_3] = MEG4_KEY_3;
- main_keymap[KEY_4] = MEG4_KEY_4;
- main_keymap[KEY_5] = MEG4_KEY_5;
- main_keymap[KEY_6] = MEG4_KEY_6;
- main_keymap[KEY_7] = MEG4_KEY_7;
- main_keymap[KEY_8] = MEG4_KEY_8;
- main_keymap[KEY_9] = MEG4_KEY_9;
- main_keymap[KEY_SEMICOLON] = MEG4_KEY_SEMICOLON;
- main_keymap[KEY_EQUAL] = MEG4_KEY_EQUAL;
- main_keymap[KEY_A] = MEG4_KEY_A;
- main_keymap[KEY_B] = MEG4_KEY_B;
- main_keymap[KEY_C] = MEG4_KEY_C;
- main_keymap[KEY_D] = MEG4_KEY_D;
- main_keymap[KEY_E] = MEG4_KEY_E;
- main_keymap[KEY_F] = MEG4_KEY_F;
- main_keymap[KEY_G] = MEG4_KEY_G;
- main_keymap[KEY_H] = MEG4_KEY_H;
- main_keymap[KEY_I] = MEG4_KEY_I;
- main_keymap[KEY_J] = MEG4_KEY_J;
- main_keymap[KEY_K] = MEG4_KEY_K;
- main_keymap[KEY_L] = MEG4_KEY_L;
- main_keymap[KEY_M] = MEG4_KEY_M;
- main_keymap[KEY_N] = MEG4_KEY_N;
- main_keymap[KEY_O] = MEG4_KEY_O;
- main_keymap[KEY_P] = MEG4_KEY_P;
- main_keymap[KEY_Q] = MEG4_KEY_Q;
- main_keymap[KEY_R] = MEG4_KEY_R;
- main_keymap[KEY_S] = MEG4_KEY_S;
- main_keymap[KEY_T] = MEG4_KEY_T;
- main_keymap[KEY_U] = MEG4_KEY_U;
- main_keymap[KEY_V] = MEG4_KEY_V;
- main_keymap[KEY_X] = MEG4_KEY_X;
- main_keymap[KEY_Y] = MEG4_KEY_Y;
- main_keymap[KEY_Z] = MEG4_KEY_Z;
- main_keymap[KEY_LEFTBRACE] = MEG4_KEY_LBRACKET;
- main_keymap[KEY_BACKSLASH] = MEG4_KEY_BACKSLASH;
- main_keymap[KEY_RIGHTBRACE] = MEG4_KEY_RBRACKET;
- main_keymap[KEY_ENTER] = MEG4_KEY_ENTER;
- main_keymap[KEY_TAB] = MEG4_KEY_TAB;
- main_keymap[KEY_BACKSPACE] = MEG4_KEY_BACKSPACE;
- main_keymap[KEY_INSERT] = MEG4_KEY_INS;
- main_keymap[KEY_DELETE] = MEG4_KEY_DEL;
- main_keymap[KEY_RIGHT] = MEG4_KEY_RIGHT;
- main_keymap[KEY_LEFT] = MEG4_KEY_LEFT;
- main_keymap[KEY_DOWN] = MEG4_KEY_DOWN;
- main_keymap[KEY_UP] = MEG4_KEY_UP;
- main_keymap[KEY_PAGEUP] = MEG4_KEY_PGUP;
- main_keymap[KEY_PAGEDOWN] = MEG4_KEY_PGDN;
- main_keymap[KEY_HOME] = MEG4_KEY_HOME;
- main_keymap[KEY_END] = MEG4_KEY_END;
- main_keymap[KEY_CAPSLOCK] = MEG4_KEY_CAPSLOCK;
- main_keymap[KEY_SCROLLLOCK] = MEG4_KEY_SCRLOCK;
- main_keymap[KEY_NUMLOCK] = MEG4_KEY_NUMLOCK;
- main_keymap[KEY_PRINT] = MEG4_KEY_PRSCR;
- main_keymap[KEY_PAUSE] = MEG4_KEY_PAUSE;
- main_keymap[KEY_F1] = MEG4_KEY_F1;
- main_keymap[KEY_F2] = MEG4_KEY_F2;
- main_keymap[KEY_F3] = MEG4_KEY_F3;
- main_keymap[KEY_F4] = MEG4_KEY_F4;
- main_keymap[KEY_F5] = MEG4_KEY_F5;
- main_keymap[KEY_F6] = MEG4_KEY_F6;
- main_keymap[KEY_F7] = MEG4_KEY_F7;
- main_keymap[KEY_F8] = MEG4_KEY_F8;
- main_keymap[KEY_F9] = MEG4_KEY_F9;
- main_keymap[KEY_F10] = MEG4_KEY_F10;
- main_keymap[KEY_F11] = MEG4_KEY_F11;
- main_keymap[KEY_F12] = MEG4_KEY_F12;
- main_keymap[KEY_KP0] = MEG4_KEY_KP_0;
- main_keymap[KEY_KP1] = MEG4_KEY_KP_1;
- main_keymap[KEY_KP2] = MEG4_KEY_KP_2;
- main_keymap[KEY_KP3] = MEG4_KEY_KP_3;
- main_keymap[KEY_KP4] = MEG4_KEY_KP_4;
- main_keymap[KEY_KP5] = MEG4_KEY_KP_5;
- main_keymap[KEY_KP6] = MEG4_KEY_KP_6;
- main_keymap[KEY_KP7] = MEG4_KEY_KP_7;
- main_keymap[KEY_KP8] = MEG4_KEY_KP_8;
- main_keymap[KEY_KP9] = MEG4_KEY_KP_9;
- main_keymap[KEY_KPDOT] = MEG4_KEY_KP_DEC;
- main_keymap[KEY_KPSLASH] = MEG4_KEY_KP_DIV;
- main_keymap[KEY_KPASTERISK] = MEG4_KEY_KP_MUL;
- main_keymap[KEY_KPMINUS] = MEG4_KEY_KP_SUB;
- main_keymap[KEY_KPPLUS] = MEG4_KEY_KP_ADD;
- main_keymap[KEY_KPENTER] = MEG4_KEY_KP_ENTER;
- main_keymap[KEY_KPEQUAL] = MEG4_KEY_KP_EQUAL;
- main_keymap[KEY_LEFTSHIFT] = MEG4_KEY_LSHIFT;
- main_keymap[KEY_LEFTCTRL] = MEG4_KEY_LCTRL;
- main_keymap[KEY_LEFTALT] = MEG4_KEY_LALT;
- main_keymap[KEY_LEFTMETA] = MEG4_KEY_LSUPER;
- main_keymap[KEY_RIGHTSHIFT] = MEG4_KEY_RSHIFT;
- main_keymap[KEY_RIGHTCTRL] = MEG4_KEY_RCTRL;
- main_keymap[KEY_RIGHTALT] = MEG4_KEY_RALT;
- main_keymap[KEY_RIGHTMETA] = MEG4_KEY_RSUPER;
- main_keymap[KEY_MENU] = MEG4_KEY_MENU;
- /* huh, wanna see some seriously and conceptually fucked up api? */
- if((afd = open("/dev/snd/pcmC0D0p", O_RDWR)) > 0) {
- /* set up PCM device */
- param_init(¶ms);
- param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
- param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_FORMAT_S16_LE);
- param_set_min(¶ms, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, ALSA_BUFFER_SIZE);
- param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, ALSA_PERIOD_SIZE);
- param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, ALSA_BUFFER_SIZE / ALSA_PERIOD_SIZE);
- param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, 44100);
- param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
- if(ioctl(afd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { close(afd); afd = -1; goto noaudio; }
- period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
- memset(&spar, 0, sizeof(spar));
- spar.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
- spar.period_step = 1;
- spar.avail_min = period_size;
- spar.start_threshold = ALSA_BUFFER_SIZE - period_size;
- spar.stop_threshold = ALSA_BUFFER_SIZE;
- spar.xfer_align = period_size / 2; /* for old kernels */
- if(ioctl(afd, SNDRV_PCM_IOCTL_SW_PARAMS, &spar)) { close(afd); afd = -1; goto noaudio; }
- boundary = spar.boundary;
- mmap_status = mmap(NULL, 4096, PROT_READ, MAP_SHARED, afd, SNDRV_PCM_MMAP_OFFSET_STATUS);
- if(!mmap_status || mmap_status == MAP_FAILED) { mmap_status = NULL; close(afd); afd = -1; goto noaudio; }
- mmap_control = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, afd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
- if(!mmap_control || mmap_control == MAP_FAILED) {
- munmap(mmap_status, 4096); mmap_status = NULL; mmap_control = NULL; close(afd); afd = -1; goto noaudio;
- }
- audio = 1;
- /* try to unmute and set hardware volume to max */
- if((k = open("/dev/snd/controlC0", O_RDWR)) > 0) {
- memset(&elist, 0, sizeof(elist));
- if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_LIST, &elist)) {
- elist.pids = malloc(elist.count * sizeof(struct snd_ctl_elem_id));
- if(elist.pids) {
- memset(elist.pids, 0, elist.count * sizeof(struct snd_ctl_elem_id));
- elist.space = elist.count;
- if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_LIST, &elist))
- for(i = 0; i < (int)elist.count; i++) {
- memset(&ei, 0, sizeof(ei));
- ei.id.numid = elist.pids[i].numid;
- if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_INFO, &ei) &&
- (ei.access & SNDRV_CTL_ELEM_ACCESS_READWRITE) == SNDRV_CTL_ELEM_ACCESS_READWRITE &&
- (ei.type == SNDRV_CTL_ELEM_TYPE_INTEGER || ei.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN) &&
- strstr((char*)ei.id.name, SNDRV_CTL_NAME_PLAYBACK)) {
- memset(&av, 0, sizeof(av));
- av.id.numid = ei.id.numid;
- if(!ioctl(k, SNDRV_CTL_IOCTL_ELEM_READ, &av)) {
- for(j = 0; j < (int)ei.count; j++) av.value.integer.value[j] = ei.value.integer.max;
- ioctl(k, SNDRV_CTL_IOCTL_ELEM_WRITE, &av);
- }
- }
- }
- free(elist.pids);
- }
- }
- close(k);
- }
- }
- noaudio:
- if(verbose && audio) main_log(1, "audio opened %uHz, %u bits", rrate, 16);
- scrbuf = (uint32_t*)malloc(640 * 400 * sizeof(uint32_t));
- if(!scrbuf) {
- main_log(0, "unable to allocate screen buffer");
- return 1;
- }
- main_win();
- if(fbuf == NULL) {
- main_log(0, "unable to initialize framebuffer");
- main_quit();
- return 1;
- }
- win_f = 1;
- /* turn on the emulator */
- meg4_poweron(lng);
- #ifndef NOEDITORS
- for(; infile && *infile; infile++) {
- if((ptr = main_readfile(*infile, &i))) {
- fn = strrchr(*infile, SEP[0]); if(!fn) fn = *infile; else fn++;
- meg4_insert(fn, ptr, i);
- free(ptr);
- }
- }
- #else
- (void)ptr; (void)infile;
- #endif
- if(audio) {
- pthread_create(&th, NULL, main_audio, NULL);
- if(ioctl(afd, SNDRV_PCM_IOCTL_PREPARE) < 0) {
- munmap(mmap_status, 4096); munmap(mmap_control, 4096); mmap_status = NULL; mmap_control = NULL;
- close(afd); afd = -1; audio = 0; period_size = 0;
- }
- }
- meg4_setptr(mx, my);
- while(!main_exit) {
- clock_gettime(CLOCK_MONOTONIC, &ts);
- ticks = (uint64_t) ts.tv_sec * 1000000000 + (uint64_t) ts.tv_nsec;
- /* handle user input events */
- for(n = 0; n < en; n += 2)
- if((k = read(ed[n], ev, sizeof(ev))) >= (int)sizeof(ev[0])) {
- for(i = 0, k /= sizeof(ev[0]); i < k; i++)
- switch(ed[n + 1]) {
- case MOUSE:
- /* mouse events */
- if(ev[i].type == EV_KEY && ev[i].value >= 0 && ev[i].value <= 1) {
- j = ev[i].code == BTN_LEFT ? MEG4_BTN_L : (ev[i].code == BTN_RIGHT ? MEG4_BTN_R : MEG4_BTN_M);
- if(ev[i].value) meg4_setbtn(j); else meg4_clrbtn(j);
- } else
- if(ev[i].type == EV_REL)
- switch(ev[i].code) {
- case REL_X:
- mx += ev[i].value;
- if(mx < 0) mx = 0;
- if(mx > meg4.screen.w) mx = meg4.screen.w;
- meg4_setptr(mx, my);
- break;
- case REL_Y:
- my += ev[i].value;
- if(my < 0) my = 0;
- if(my > meg4.screen.h) my = meg4.screen.h;
- meg4_setptr(mx, my);
- break;
- case REL_WHEEL: meg4_setscr(ev[i].value > 0, ev[i].value < 0, 0, 0); break;
- }
- break;
- case KBD:
- /* keyboard events */
- if(ev[i].type == EV_KEY && ev[i].value >= 0 && ev[i].value <= 2) {
- if(ev[i].code > 0 && ev[i].code < (sizeof(main_keymap)/sizeof(main_keymap[0]))) {
- if(ev[i].value == 0) {
- /* key release */
- if(ev[i].code == KEY_LEFTCTRL || ev[i].code == KEY_LEFTALT) main_alt = 0;
- if(ev[i].code == KEY_LEFTMETA || ev[i].code == KEY_RIGHTMETA || ev[i].code == KEY_RIGHTALT) main_meta = 0;
- if(ev[i].code == KEY_LEFTSHIFT || ev[i].code == KEY_RIGHTSHIFT) main_sh = 0;
- if(ev[i].code == KEY_CAPSLOCK) main_caps = 0;
- if(ev[i].code == KEY_LEFTALT && main_sh && emptyalt) main_kbd ^= 1;
- emptyalt = 0;
- meg4_clrkey(main_keymap[ev[i].code]);
- } else
- if(ev[i].value == 1) {
- /* key press */
- if(ev[i].code == KEY_LEFTCTRL || ev[i].code == KEY_LEFTALT) main_alt = 1;
- if(ev[i].code == KEY_LEFTMETA || ev[i].code == KEY_RIGHTMETA || ev[i].code == KEY_RIGHTALT) { main_meta = 1; main_alt = 0; }
- if(ev[i].code == KEY_LEFTSHIFT || ev[i].code == KEY_RIGHTSHIFT) main_sh = 1;
- if(ev[i].code == KEY_CAPSLOCK) main_caps = 1;
- emptyalt = ev[i].code == KEY_LEFTALT;
- switch(ev[i].code) {
- case KEY_ESC: if(main_alt) main_exit = 1; else meg4_pushkey("\x1b\0\0"); break;
- case KEY_F1: meg4_pushkey("F1\0"); break;
- case KEY_F2: meg4_pushkey("F2\0"); break;
- case KEY_F3: meg4_pushkey("F3\0"); break;
- case KEY_F4: meg4_pushkey("F4\0"); break;
- case KEY_F5: meg4_pushkey("F5\0"); break;
- case KEY_F6: meg4_pushkey("F6\0"); break;
- case KEY_F7: meg4_pushkey("F7\0"); break;
- case KEY_F8: meg4_pushkey("F8\0"); break;
- case KEY_F9: meg4_pushkey("F9\0"); break;
- case KEY_F10: meg4_pushkey("F10"); break;
- case KEY_F11: main_fullscreen(); break;
- case KEY_F12: meg4_pushkey("F12"); break;
- case KEY_PRINT: meg4_pushkey("PSc"); break;
- case KEY_SCROLLLOCK: meg4_pushkey("SLk"); break;
- case KEY_NUMLOCK: meg4_pushkey("NLk"); break;
- case KEY_BACKSPACE: meg4_pushkey("\b\0\0"); break;
- case KEY_TAB: meg4_pushkey("\t\0\0"); break;
- case KEY_ENTER: case KEY_KPENTER: if(main_alt) main_fullscreen(); else meg4_pushkey("\n\0\0"); break;
- case KEY_CAPSLOCK: meg4_pushkey("CLk"); break;
- case KEY_UP: meg4_pushkey("Up\0"); break;
- case KEY_DOWN: meg4_pushkey("Down"); break;
- case KEY_LEFT: meg4_pushkey("Left"); break;
- case KEY_RIGHT: meg4_pushkey("Rght"); break;
- case KEY_HOME: meg4_pushkey("Home"); break;
- case KEY_END: meg4_pushkey("End"); break;
- case KEY_PAGEUP: meg4_pushkey("PgUp"); break;
- case KEY_PAGEDOWN: meg4_pushkey("PgDn"); break;
- case KEY_INSERT: meg4_pushkey("Ins"); break;
- case KEY_DELETE: meg4_pushkey("Del"); break;
- default:
- if(main_alt && s[0] == 'q' && !s[1]) main_exit = 1;
- if(!main_alt && ev[i].code < sizeof(main_kbdlayout[0])/(sizeof(main_kbdlayout[0][0])*4)) {
- memset(s, 0, sizeof(s));
- strncpy(s, main_kbdlayout[main_kbd][(ev[i].code << 2) | (main_meta << 1) | (main_caps ^ main_sh)], 4);
- if(s[0]) meg4_pushkey(s);
- }
- break;
- }
- meg4_setkey(main_keymap[ev[i].code]);
- }
- }
- }
- break;
- default:
- /* controller events */
- j = ed[n + 1] - PAD;
- if(j < 4 && ev[i].type == EV_KEY) {
- if(ev[i].value == 0) {
- switch(ev[i].code) {
- case BTN_DPAD_DOWN: meg4_clrpad(j, MEG4_BTN_D); break;
- case BTN_DPAD_UP: meg4_clrpad(j, MEG4_BTN_U); break;
- case BTN_DPAD_LEFT: meg4_clrpad(j, MEG4_BTN_L); break;
- case BTN_DPAD_RIGHT:meg4_clrpad(j, MEG4_BTN_R); break;
- case BTN_A: meg4_clrpad(j, MEG4_BTN_A); break;
- case BTN_B: meg4_clrpad(j, MEG4_BTN_B); break;
- case BTN_X: meg4_clrpad(j, MEG4_BTN_X); break;
- case BTN_Y: meg4_clrpad(j, MEG4_BTN_Y); break;
- }
- } else
- if(ev[i].value == 1) {
- switch(ev[i].code) {
- case BTN_DPAD_DOWN: meg4_setpad(j, MEG4_BTN_D); break;
- case BTN_DPAD_UP: meg4_setpad(j, MEG4_BTN_U); break;
- case BTN_DPAD_LEFT: meg4_setpad(j, MEG4_BTN_L); break;
- case BTN_DPAD_RIGHT:meg4_setpad(j, MEG4_BTN_R); break;
- case BTN_A: meg4_setpad(j, MEG4_BTN_A); break;
- case BTN_B: meg4_setpad(j, MEG4_BTN_B); break;
- case BTN_X: meg4_setpad(j, MEG4_BTN_X); break;
- case BTN_Y: meg4_setpad(j, MEG4_BTN_Y); break;
- }
- }
- }
- break;
- }
- }
- /* run the emulator and display screen */
- meg4_run();
- meg4_redraw(scrbuf, 640, 400, 640 * 4);
- if(win_f) main_arb_scaler();
- else main_fix_scaler();
- /* delay to run loop at 60 FPS */
- clock_gettime(CLOCK_MONOTONIC, &ts);
- tickdiff = ((1000000000/60) - (((uint64_t) ts.tv_sec * 1000000000 + (uint64_t) ts.tv_nsec) - ticks)) / 1000000;
- if(tickdiff > 0 && tickdiff < 1000) main_delay(tickdiff);
- }
- main_quit();
- return 0;
- }
|