/* GSPLUS - Advanced Apple IIGS Emulator Environment Based on the KEGS emulator written by Kent Dickey See COPYRIGHT.txt for Copyright information See LICENSE.txt for license (GPL v2) */ /* * fbdriver - Linux fullscreen framebuffer graphics driver */ #include #include #include #include #include #include #include #include #include #include #include "defc.h" void quitEmulator(); extern int g_screen_depth; extern word32 g_palette_8to1624[256]; extern word32 g_a2palette_8to1624[256]; extern word32 g_a2_screen_buffer_changed; extern word32 g_c025_val; #define SHIFT_DOWN ( (g_c025_val & 0x01) ) #define CTRL_DOWN ( (g_c025_val & 0x02) ) #define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) #define OPTION_DOWN ( (g_c025_val & 0x40) ) #define CMD_DOWN ( (g_c025_val & 0x80) ) extern int g_video_act_margin_left; extern int g_video_act_margin_right; extern int g_video_act_margin_top; extern int g_video_act_margin_bottom; extern int g_lores_colors[]; extern int g_cur_a2_stat; extern int g_a2vid_palette; extern int g_installed_full_superhires_colormap; extern int g_mouse_raw_x; extern int g_mouse_raw_y; extern word32 g_red_mask; extern word32 g_green_mask; extern word32 g_blue_mask; extern int g_red_left_shift; extern int g_green_left_shift; extern int g_blue_left_shift; extern int g_red_right_shift; extern int g_green_right_shift; extern int g_blue_right_shift; extern Kimage g_mainwin_kimage; int keycode_to_a2code[128] = { -1, // KEY_RESERVED 0x35, // KEY_ESC 0x12, // KEY_1 0x13, // KEY_2 0x14, // KEY_3 0x15, // KEY_4 0x17, // KEY_5 0x16, // KEY_6 0x1A, // KEY_7 0x1C, // KEY_8 0x19, // KEY_9 0x1D, // KEY_0 0x1B, // KEY_MINUS 0x18, // KEY_EQUAL 0x3B, // KEY_BACKSPACE0 0x30, // KEY_TAB 0x0C, // KEY_Q 0x0D, // KEY_W 0x0E, // KEY_E 0x0F, // KEY_R 0x11, // KEY_T 0x10, // KEY_Y 0x20, // KEY_U 0x22, // KEY_I 0x1F, // KEY_O 0x23, // KEY_P 0x21, // KEY_LEFTBRACE 0x1E, // KEY_RIGHTBRACE 0x24, // KEY_ENTER 0x36, // KEY_LEFTCTRL 0x00, // KEY_A 0x01, // KEY_S 0x02, // KEY_D 0x03, // KEY_F 0x05, // KEY_G 0x04, // KEY_H 0x26, // KEY_J 0x28, // KEY_K 0x25, // KEY_L 0x29, // KEY_SEMICOLON 0x27, // KEY_APOSTROPHE 0x32, // KEY_GRAVE 0x38, // KEY_LEFTSHIFT 0x2A, // KEY_BACKSLASH 0x06, // KEY_Z 0x07, // KEY_X 0x08, // KEY_C 0x09, // KEY_V 0x0B, // KEY_B 0x2D, // KEY_N 0x2E, // KEY_M 0x2B, // KEY_COMMA 0x2F, // KEY_DOT 0x2C, // KEY_SLASH 0x38, // KEY_RIGHTSHIFT 0x43, // KEY_KPASTERISK 0x37, // KEY_LEFTALT 0x31, // KEY_SPACE 0x39, // KEY_CAPSLOCK 0x7A, // KEY_F1 0x78, // KEY_F2 0x63, // KEY_F3 0x76, // KEY_F4 0x60, // KEY_F5 0x61, // KEY_F6 0x62, // KEY_F7 0x64, // KEY_F8 0x65, // KEY_F9 0x6D, // KEY_F10 0x47, // KEY_NUMLOCK 0x37, // KEY_SCROLLLOCK 0x59, // KEY_KP7 0x5B, // KEY_KP8 0x5C, // KEY_KP9 0x4E, // KEY_KPMINUS 0x56, // KEY_KP4 0x57, // KEY_KP5 0x58, // KEY_KP6 0x45, // KEY_KPPLUS 0x53, // KEY_KP1 0x54, // KEY_KP2 0x55, // KEY_KP3 0x52, // KEY_KP0 0x41, // KEY_KPDOT -1, -1, // KEY_ZENKAKUHANKAKU -1, // KEY_102ND 0x67, // KEY_F11 0x6F, // KEY_F12 -1, // KEY_RO -1, // KEY_KATAKANA -1, // KEY_HIRAGANA -1, // KEY_HENKAN -1, // KEY_KATAKANAHIRAGANA -1, // KEY_MUHENKAN -1, // KEY_KPJPCOMMA 0x4C, // KEY_KPENTER 0x36, // KEY_RIGHTCTRL 0x4B, // KEY_KPSLASH 0x7F, // KEY_SYSRQ 0x37, // KEY_RIGHTALT 0x6E, // KEY_LINEFEED 0x73, // KEY_HOME 0x3E, // KEY_UP 0x74, // KEY_PAGEUP 0x3B, // KEY_LEFT 0x3C, // KEY_RIGHT 0x77, // KEY_END 0x3D, // KEY_DOWN 0x79, // KEY_PAGEDOWN 0x72, // KEY_INSERT 0x33, // KEY_DELETE -1, // KEY_MACRO -1, // KEY_MUTE -1, // KEY_VOLUMEDOWN -1, // KEY_VOLUMEUP 0x7F, // KEY_POWER /* SC System Power Down */ 0x51, // KEY_KPEQUAL 0x4E, // KEY_KPPLUSMINUS -1, // KEY_PAUSE -1, // KEY_SCALE /* AL Compiz Scale (Expose) */ 0x2B, // KEY_KPCOMMA -1, // KEY_HANGEUL -1, // KEY_HANJA -1, // KEY_YEN 0x3A, // KEY_LEFTMETA 0x3A, // KEY_RIGHTMETA -1 // KEY_COMPOSE }; struct termios org_tio; struct fb_var_screeninfo orig_vinfo; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; int pix_size, g_screen_mdepth, g_use_shmem = 1; #define MOUSE_LBTN_DOWN 0x01 #define MOUSE_MBTN_DOWN 0x02 #define MOUSE_RBTN_DOWN 0x04 #define MOUSE_LBTN_UP 0x00 #define MOUSE_MBTN_UP 0x00 #define MOUSE_RBTN_UP 0x00 #define MOUSE_BTN_ACTIVE 0x07 #define UPDATE_INPUT_MOUSE 0x10 #define MAX_EVDEV 8 char *fb_ptr, g_inputstate = 0; int evfd[MAX_EVDEV], evdevs, termfd, fbfd = 0; /* * Clean up */ void xdriver_end(void) { char c; static char xexit = 0; if (!xexit) { // cleanup munmap(fb_ptr, finfo.smem_len); ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo); close(fbfd); if (termfd > 0) { // Flush input while (read(termfd, &c, 1) == 1); ioctl(termfd, KDSETMODE, KD_TEXT); tcsetattr(termfd, TCSANOW, &org_tio); close(termfd); } fclose(stdout); fclose(stderr); while (evdevs--) close(evfd[evdevs]); xexit = 1; } } /* * Init framebuffer and input */ void dev_video_init(void) { int i; char evdevname[20]; struct termios termio; // Set graphics mode on console if ((termfd = open("/dev/tty", O_RDWR)) < 0) { fprintf(stderr, "Error opening tty device.\n"); exit(-1); } // Save input settings. tcgetattr(termfd, &termio); /* save current port settings */ memcpy(&org_tio, &termio, sizeof(struct termios)); ioctl(termfd, KDSETMODE, KD_GRAPHICS); // Open the file for reading and writing if ((fbfd = open("/dev/fb0", O_RDWR)) < 0) { fprintf(stderr, "Error opening framebuffer device.\n"); ioctl(termfd, KDSETMODE, KD_TEXT); exit(-1); } // Get variable screen information if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { fprintf(stderr, "Error reading variable screen information.\n"); ioctl(termfd, KDSETMODE, KD_TEXT); exit(-1); } // Store for reset(copy vinfo to vinfo_orig) memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo)); // Change variable info //vinfo.bits_per_pixel = 8; // Change resolution vinfo.xres = 640; vinfo.yres = 400; if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) { fprintf(stderr, "Error setting variable screen information (640x400x8).\n"); ioctl(termfd, KDSETMODE, KD_TEXT); exit(-1); } // Get fixed screen information if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { fprintf(stderr, "Error reading fixed screen information.\n"); ioctl(termfd, KDSETMODE, KD_TEXT); exit(-1); } // map fb to user mem fb_ptr = (char*)mmap(0, finfo.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, 0); if ((int)fb_ptr == -1) { printf("Failed to mmap framebuffer.\n"); ioctl(termfd, KDSETMODE, KD_TEXT); exit (-1); } g_screen_depth = vinfo.bits_per_pixel; g_screen_mdepth = g_screen_depth; if (g_screen_depth > 8) g_screen_mdepth = 16; if (g_screen_depth > 16) g_screen_mdepth = 32; pix_size = g_screen_mdepth / 8; if (vinfo.bits_per_pixel > 8) { g_red_mask = (1 << vinfo.red.length) - 1; g_green_mask = (1 << vinfo.green.length) - 1; g_blue_mask = (1 << vinfo.blue.length) - 1; g_red_left_shift = vinfo.red.offset; g_green_left_shift = vinfo.green.offset; g_blue_left_shift = vinfo.blue.offset; g_red_right_shift = 8 - vinfo.red.length; g_green_right_shift = 8 - vinfo.green.length; g_blue_right_shift = 8 - vinfo.blue.length; } video_get_kimages(); if (g_screen_depth > 8) video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth); for (i = 0; i < 256; i++) { video_update_color_raw(i, g_lores_colors[i & 0xf]); g_a2palette_8to1624[i] = g_palette_8to1624[i]; } fclose(stdin); freopen("gsport.log", "w+", stdout); freopen("gsport.err", "w+", stderr); termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD; termio.c_iflag = IGNPAR; termio.c_oflag = 0; termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */ termio.c_cc[VTIME] = 0; /* inter-character timer unused */ termio.c_cc[VMIN] = 0; /* non-blocking read */ tcsetattr(termfd, TCSANOW, &termio); // Open input event devices for (evdevs = 0; evdevs < MAX_EVDEV; evdevs++) { sprintf(evdevname, "/dev/input/event%c", evdevs + '0'); if ((evfd[evdevs] = open(evdevname, O_RDONLY|O_NONBLOCK)) < 0) break; } g_video_act_margin_left = 0; g_video_act_margin_right = 1; g_video_act_margin_top = 0; g_video_act_margin_bottom = 0; } /* * Colormap */ __u16 cmapred[256], cmapgreen[256], cmapblue[256]; int cmapstart, cmaplen, cmapdirty = 0; void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { cmapred[col_num] = red | (red << 8); cmapgreen[col_num] = green | (green << 8); cmapblue[col_num] = blue | (blue << 8); if (cmapdirty == 0) { cmapstart = col_num; cmaplen = 1; cmapdirty = 1; } else { if (col_num < cmapstart) { cmaplen += cmapstart - col_num; cmapstart = col_num; } else if (col_num > cmapstart + cmaplen) cmaplen = col_num - cmapstart + 1; } } void x_update_physical_colormap(void) { struct fb_cmap fbcol; if (cmapdirty) { cmapdirty = 0; fbcol.start = cmapstart; fbcol.len = cmaplen; fbcol.red = cmapred; fbcol.green = cmapgreen; fbcol.blue = cmapblue; fbcol.transp = NULL; ioctl(fbfd, FBIOPUTCMAP, &fbcol); } } void show_xcolor_array(void) { } /* * Screen update */ void x_get_kimage(Kimage *kimage_ptr) { kimage_ptr->data_ptr = (byte *)malloc(kimage_ptr->width_req * kimage_ptr->height * kimage_ptr->mdepth / 8); } void x_release_kimage(Kimage* kimage_ptr) { if (kimage_ptr->data_ptr) if (kimage_ptr->width_req != 640 || kimage_ptr->height != 400) free(kimage_ptr->data_ptr); kimage_ptr->data_ptr = NULL; } void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) { byte *src_ptr, *dst_ptr; // Copy sub-image to framebuffer dst_ptr = (byte *)fb_ptr + desty * finfo.line_length + destx * pix_size; src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pix_size; width *= pix_size; while (height--) { memcpy(dst_ptr, src_ptr, width); dst_ptr += finfo.line_length; src_ptr += kimage_ptr->width_act * pix_size; } } void x_push_done(void) { } /* * NOP routines */ void x_dialog_create_gsport_conf(const char *str) { // Just write the config file already... config_write_config_gsplus_file(); } int x_show_alert(int is_fatal, const char *str) { // Not implemented yet adb_all_keys_up(); clear_fatal_logs(); return 0; } void x_toggle_status_lines(void) { } void x_redraw_status_lines(void) { } void x_hide_pointer(int do_hide) { } void x_auto_repeat_on(int must) { } void x_full_screen(int do_full) { } int x_calc_ratio(float x, float y) { return 1; } void clipboard_paste(void) { } int clipboard_get_char(void) { return 0; } /* * Input handling */ void check_input_events(void) { struct input_event ev; int i; for (i = 0; i < evdevs; i++) // Check input events while (read(evfd[i], &ev, sizeof(struct input_event)) == sizeof(struct input_event)) { if (ev.type == EV_REL) { if (ev.code == REL_X) { g_mouse_raw_x += ev.value; if (g_mouse_raw_x < 0) g_mouse_raw_x = 0; if (g_mouse_raw_x > 639) g_mouse_raw_x = 639; } else // REL_Y { g_mouse_raw_y += ev.value; if (g_mouse_raw_y < 0) g_mouse_raw_y = 0; if (g_mouse_raw_y > 399) g_mouse_raw_y = 399; } g_inputstate |= UPDATE_INPUT_MOUSE; } else if (ev.type == EV_KEY) { if (ev.code < 128) { #if 0 if ((ev.code == KEY_F10) && SHIFT_DOWN) { //quitEmulator(); iwm_shut(); xdriver_end(); my_exit(1); } #endif if (keycode_to_a2code[ev.code] >= 0) adb_physical_key_update(keycode_to_a2code[ev.code], !ev.value); } else if (ev.code == BTN_LEFT) { g_inputstate = ev.value ? UPDATE_INPUT_MOUSE | MOUSE_LBTN_DOWN : UPDATE_INPUT_MOUSE | MOUSE_LBTN_UP; } } else if (ev.type == EV_SYN) { if (g_inputstate & UPDATE_INPUT_MOUSE) update_mouse(g_mouse_raw_x, g_mouse_raw_y, g_inputstate & MOUSE_BTN_ACTIVE, MOUSE_BTN_ACTIVE); g_inputstate &= ~UPDATE_INPUT_MOUSE; } } } static void sig_bye(int signo) { xdriver_end(); exit (-1); } /* * Application entrypoint */ int main(int argc,char *argv[]) { if (signal(SIGINT, sig_bye) == SIG_ERR) exit(-1); if (signal(SIGHUP, sig_bye) == SIG_ERR) exit(-1); gsplusmain(argc, argv); xdriver_end(); return 0; }