#include "LinuxFbLocal.h" #define LLOG(x) //LOG(x) NAMESPACE_UPP //video int fbfd = -1; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; long int screensize = 0; char *fbp = 0; //mouse int mouse_fd = -1; bool mouse_imps2 = false; Point mousep; dword mouseb = 0; //keyb int keyb_fd = -1; int cvt = -1; // int oldvt; struct termios oldtermios; int oldmode; int entervt() { struct termios kt; if(cvt > 0) { struct vt_stat vtst; if(ioctl(keyb_fd, VT_GETSTATE, &vtst) == 0) oldvt = vtst.v_active; if(ioctl(keyb_fd, VT_ACTIVATE, cvt) == 0) ioctl(keyb_fd, VT_WAITACTIVE, cvt); } if(tcgetattr(keyb_fd, &oldtermios) < 0) { fprintf(stderr, "Error: saving terminal attributes"); return -1; } if(ioctl(keyb_fd, KDGKBMODE, &oldmode) < 0) { fprintf(stderr, "Error: saving keyboard mode"); return -1; } kt = oldtermios; kt.c_lflag &= ~(ICANON | ECHO | ISIG); kt.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); kt.c_cc[VMIN] = 0; kt.c_cc[VTIME] = 0; if(tcsetattr(keyb_fd, TCSAFLUSH, &kt) < 0) { fprintf(stderr, "Error: setting new terminal attributes"); return -1; } if(ioctl(keyb_fd, KDSKBMODE, K_MEDIUMRAW) < 0) { fprintf(stderr, "Error: setting keyboard in mediumraw mode"); return -1; } if(ioctl(keyb_fd, KDSETMODE, KD_GRAPHICS) < 0) { fprintf(stderr, "Error: setting keyboard in graphics mode"); return -1; } ioctl(keyb_fd, VT_LOCKSWITCH, 1); return 0; } void switchvt_pre() { ioctl(keyb_fd, KDSETMODE, KD_TEXT); ioctl(keyb_fd, VT_UNLOCKSWITCH, 1); } void switchvt_post() { ioctl(keyb_fd, VT_LOCKSWITCH, 1); ioctl(keyb_fd, KDSETMODE, KD_GRAPHICS); } int switched_away = 0; void switchvt(int ii) { struct vt_stat vtst; /* Figure out whether or not we're switching to a new console */ if(ioctl(keyb_fd, VT_GETSTATE, &vtst) < 0) { fprintf(stderr, "Error: could not read tty state"); return; } if(ii == vtst.v_active) return; LLOG("trying to switch to VT " << ii); GuiLock __; switchvt_pre(); if(ioctl(keyb_fd, VT_ACTIVATE, ii) == 0) { ioctl(keyb_fd, VT_WAITACTIVE, ii); switched_away = 1; return; } switchvt_post(); } void leavevt() { if(oldmode < 0) return; if(ioctl(keyb_fd, KDSETMODE, KD_TEXT) < 0) fprintf(stderr, "Error: setting keyboard in text mode"); if(ioctl(keyb_fd, KDSKBMODE, oldmode) < 0) fprintf(stderr, "Error: restoring keyboard mode"); if(tcsetattr(keyb_fd, TCSAFLUSH, &oldtermios) < 0) fprintf(stderr, "Error: setting new terminal attributes"); oldmode = -1; ioctl(keyb_fd, VT_UNLOCKSWITCH, 1); if(oldvt > 0) ioctl(keyb_fd, VT_ACTIVATE, oldvt); } int pend = 0; //returns 0 if timeout, 1 for mouse, 2 for keyboard //common for waitforevents and sleep int readevents(int ms) { fd_set fdset; int max_fd; static struct timeval to; to.tv_sec = ms / 1000; to.tv_usec = ms % 1000 * 1000; if(switched_away) { struct vt_stat vtst; GuiLock __; if((ioctl(keyb_fd, VT_GETSTATE, &vtst) == 0) && vtst.v_active == cvt) { switched_away = 0; switchvt_post(); } } FD_ZERO(&fdset); max_fd = 0; if(mouse_fd >= 0) { FD_SET(mouse_fd, &fdset); if(max_fd < mouse_fd) max_fd = mouse_fd; } if(keyb_fd >= 0) { FD_SET(keyb_fd, &fdset); if(max_fd < keyb_fd) max_fd = keyb_fd; } if(select(max_fd+1, &fdset, NULL, NULL, &to) > 0) { if(mouse_fd >= 0) { if(FD_ISSET(mouse_fd, &fdset)) return 1; } if(keyb_fd >= 0) { if(FD_ISSET(keyb_fd, &fdset)) return 2; } } return 0; } // void FBQuitSession() { Ctrl::EndSession(); } bool FBIsWaitingEvent() { pend = readevents(0); return pend > 0; } bool FBProcessEvent(bool *quit) { if(pend) { if(pend & 1) handle_mouse(); if(pend & 2) handle_keyboard(); pend = 0; //need to reset, since with repeated call is not updated here, would stuck return true; } return false; } void FBSleep(int ms) { pend = readevents(ms); //interruptable sleep //keep queue busy, see SDLFb/Win.cpp for why //this indicates that some stuff is pending, returning true in FBProcessEvent //while nothing is actually processed pend |= 4; } void FBInitUpdate() { } void FBUpdate(const Rect& inv) { if(switched_away) return; //backdraw //FIXME accelerate const ImageBuffer& framebuffer = Ctrl::GetFrameBuffer(); memcpy(fbp, ~framebuffer, framebuffer.GetLength() * sizeof(RGBA)); } void FBFlush() { } void FBInit(const String& fbdevice) { Ctrl::InitFB(); fbfd = open(fbdevice, O_RDWR); if (!fbfd) { fprintf(stderr, "Error: cannot open framebuffer device.\n"); exit(-1); } LLOG("The framebuffer device was opened successfully.\n"); if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { fprintf(stderr, "Error reading fixed information.\n"); exit(-2); } if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { fprintf(stderr, "Error reading variable information.\n"); exit(-3); } RLOG("Framebuffer opened: " << fbdevice << ": " << vinfo.xres << "x" << vinfo.yres << " @ " << vinfo.bits_per_pixel); screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; //bytes fbp = (char*)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if((intptr_t)fbp == -1) { fprintf(stderr, "Error: failed to map framebuffer device to memory.\n"); exit(-4); } LLOG("The framebuffer device was mapped to memory successfully.\n"); Size fbsz(vinfo.xres, vinfo.yres); Ctrl::SetFramebufferSize(fbsz); //mouse //mousep = fbsz / 2; mousep.Clear(); static const char *mice[] = { "/dev/input/mice" , "/dev/usbmouse" , "/dev/psaux" , NULL }; for(int i=0; (mouse_fd < 0) && mice[i]; ++i) { mouse_fd = open(mice[i], O_RDWR, 0); if(mouse_fd < 0) mouse_fd = open(mice[i], O_RDONLY, 0); if(mouse_fd >= 0) { set_imps2(mouse_fd, 1); if(mouse_imps2 = has_imps2(mouse_fd)) { LLOG("IMPS2 mouse enabled: " << mice[i]); } else RLOG("no IMPS2 mouse present"); } else fprintf(stderr, "Error: failed to open %s.\n", mice[i]); } //keyb static const char* const tty0[] = { "/dev/tty0" , "/dev/vc/0" , NULL }; static const char* const vcs[] = { "/dev/vc/" , "/dev/tty" , NULL }; int tfd = -1; for(int i=0; tty0[i] && (tfd < 0); ++i) tfd = open(tty0[i], O_WRONLY, 0); if(tfd < 0) tfd = dup(0); ASSERT(tfd>=0); ioctl(tfd, VT_OPENQRY, &cvt); close(tfd); LLOG("probable new VT: " << cvt); if(geteuid() != 0) { fprintf(stderr, "Error: not running as ROOT, mouse handling pobably unavailable\n"); } else if(cvt > 0) { LLOG("try to open the NEW assigned VT: " << cvt); for(int i=0; vcs[i] && (keyb_fd < 0); ++i) { char path[32]; snprintf(path, 32, "%s%d", vcs[i], cvt); keyb_fd = open(path, O_RDWR, 0); if(keyb_fd < 0) continue; LLOG("TTY path opened: " << path); tfd = open("/dev/tty", O_RDWR, 0); if(tfd >= 0) { LLOG("detaching from local stdin/out/err"); ioctl(tfd, TIOCNOTTY, 0); close(tfd); } else fprintf(stderr, "Error: detaching from local stdin/out/err\n"); } } if(keyb_fd < 0) { LLOG("Using already assigned VT, must not detach"); struct vt_stat vtst; keyb_fd = open("/dev/tty", O_RDWR); if(ioctl(keyb_fd, VT_GETSTATE, &vtst) < 0) { cvt = 0; } else { cvt = vtst.v_active; } } if(cvt>0) fprintf(stdout, "started on VT %d\n", cvt); ASSERT(keyb_fd>=0); oldmode = -1; { int d; if(ioctl(keyb_fd, KDGKBMODE, &d) < 0) { close(keyb_fd); keyb_fd = -1; fprintf(stderr, "Error: opening a console terminal"); exit(5); } } LLOG("tty opened: " << keyb_fd); dupkmap(keyb_fd); entervt(); pend = 4; //fake video expose event to cause first paint } void FBDeInit() { Ctrl::ExitFB(); munmap(fbp, screensize); close(fbfd); leavevt(); close(mouse_fd); } END_UPP_NAMESPACE