pm.c

来自「适合KS8695X」· C语言 代码 · 共 1,810 行 · 第 1/4 页

C
1,810
字号
	    ioctl(_PM_console_fd, KDSKBMODE, mode.kb_mode);
	    ioctl(_PM_console_fd, KDSETLED, mode.leds);
	    tcsetattr(_PM_console_fd, TCSAFLUSH, &mode.termios);
	    fcntl(_PM_console_fd,F_SETFL,mode.flags);
	    }
	fclose(kbmode);
	unlink(path);
	in_raw_mode = false;
	}
}

/****************************************************************************
REMARKS:
Safely abort the event module upon catching a fatal error.
****************************************************************************/
void _PM_abort(
    int signo)
{
    char    buf[80];

    sprintf(buf,"Terminating on signal %d",signo);
    _PM_restore_kb_mode();
    PM_fatalError(buf);
}

/****************************************************************************
REMARKS:
Put the keyboard into raw mode
****************************************************************************/
void _PM_keyboard_rawmode(void)
{
    struct termios conf;
    FILE            *kbmode;
    keyboard_mode   mode;
    char            path[PM_MAX_PATH];
    int             i;
    static int sig_list[] = {
	SIGHUP,
	SIGINT,
	SIGQUIT,
	SIGILL,
	SIGTRAP,
	SIGABRT,
	SIGIOT,
	SIGBUS,
	SIGFPE,
	SIGKILL,
	SIGSEGV,
	SIGTERM,
	};

    if ((kbmode = open_kb_mode("rb",path)) == NULL) {
	if ((kbmode = open_kb_mode("wb",path)) == NULL)
	    PM_fatalError("Unable to open kbmode.dat file for writing!");
	if (ioctl(_PM_console_fd, KDGKBMODE, &mode.kb_mode))
	    perror("KDGKBMODE");
	ioctl(_PM_console_fd, KDGETLED, &mode.leds);
	_PM_leds = mode.leds & 0xF;
	_PM_modifiers = 0;
	tcgetattr(_PM_console_fd, &mode.termios);
	conf = mode.termios;
	conf.c_lflag &= ~(ICANON | ECHO | ISIG);
	conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
	conf.c_iflag  |= (IGNBRK | IGNPAR);
	conf.c_cc[VMIN] = 1;
	conf.c_cc[VTIME] = 0;
	conf.c_cc[VSUSP] = 0;
	tcsetattr(_PM_console_fd, TCSAFLUSH, &conf);
	mode.flags = fcntl(_PM_console_fd,F_GETFL);
	if (ioctl(_PM_console_fd, KDSKBMODE, K_MEDIUMRAW))
	    perror("KDSKBMODE");
	atexit(_PM_restore_kb_mode);
	for (i = 0; i < sizeof(sig_list)/sizeof(sig_list[0]); i++)
	    signal(sig_list[i], _PM_abort);
	mode.startup_vc = startup_vc;
	if (fwrite(&mode,1,sizeof(mode),kbmode) != sizeof(mode))
	    PM_fatalError("Error writing kbmode.dat!");
	fclose(kbmode);
	in_raw_mode = true;
	}
}

int PMAPI PM_kbhit(void)
{
    fd_set s;
    struct timeval tv = { 0, 0 };

    if (console_count == 0)
	PM_fatalError("You *must* open a console before using PM_kbhit!");
    if (!in_raw_mode)
	_PM_keyboard_rawmode();
    FD_ZERO(&s);
    FD_SET(_PM_console_fd, &s);
    return select(_PM_console_fd+1, &s, NULL, NULL, &tv) > 0;
}

int PMAPI PM_getch(void)
{
    static uchar    c;
    int release;
    static struct kbentry ke;

    if (console_count == 0)
	PM_fatalError("You *must* open a console before using PM_getch!");
    if (!in_raw_mode)
	_PM_keyboard_rawmode();
    while (read(_PM_console_fd, &c, 1) > 0) {
	release = c & 0x80;
	c &= 0x7F;
	if (release) {
	    switch(c){
		case 42: case 54: /* Shift */
		    _PM_modifiers &= ~KB_SHIFT;
		    break;
		case 29: case 97: /* Control */
		    _PM_modifiers &= ~KB_CONTROL;
		    break;
		case 56: case 100: /* Alt / AltGr */
		    _PM_modifiers &= ~KB_ALT;
		    break;
		}
	    continue;
	    }
	switch (c) {
	    case 42: case 54: /* Shift */
		_PM_modifiers |= KB_SHIFT;
		 break;
	    case 29: case 97: /* Control */
		_PM_modifiers |= KB_CONTROL;
		break;
	    case 56: case 100: /* Alt / AltGr */
		_PM_modifiers |= KB_ALT;
		break;
	    case 58: /* Caps Lock */
		_PM_modifiers ^= KB_CAPS;
		ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
		break;
	    case 69: /* Num Lock */
		_PM_modifiers ^= KB_NUMLOCK;
		ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
		break;
	    case 70: /* Scroll Lock */
		_PM_modifiers ^= KB_SCROLL;
		ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
		break;
	    case 28:
		return 0x1C;
	    default:
		ke.kb_index = c;
		ke.kb_table = 0;
		if ((_PM_modifiers & KB_SHIFT) || (_PM_modifiers & KB_CAPS))
		    ke.kb_table |= K_SHIFTTAB;
		if (_PM_modifiers & KB_ALT)
		    ke.kb_table |= K_ALTTAB;
		ioctl(_PM_console_fd, KDGKBENT, (ulong)&ke);
		c = ke.kb_value & 0xFF;
		return c;
	    }
	}
    return 0;
}

/****************************************************************************
REMARKS:
Sleep until the virtual terminal is active
****************************************************************************/
static void wait_vt_active(
    int _PM_console_fd)
{
    while (ioctl(_PM_console_fd, VT_WAITACTIVE, tty_vc) < 0) {
	if ((errno != EAGAIN) && (errno != EINTR)) {
	    perror("ioctl(VT_WAITACTIVE)");
	    exit(1);
	    }
	usleep(150000);
	}
}

/****************************************************************************
REMARKS:
Checks the owner of the specified virtual console.
****************************************************************************/
static int check_owner(
    int vc)
{
    struct stat sbuf;
    char fname[30];

    sprintf(fname, "/dev/tty%d", vc);
    if ((stat(fname, &sbuf) >= 0) && (getuid() == sbuf.st_uid))
	return 1;
    printf("You must be the owner of the current console to use this program.\n");
    return 0;
}

/****************************************************************************
REMARKS:
Checks if the console is currently in graphics mode, and if so we forcibly
restore it back to text mode again. This handles the case when a Nucleus or
MGL program crashes and leaves the console in graphics mode. Running the
textmode utility (or any other Nucleus/MGL program) via a telnet session
into the machine will restore it back to normal.
****************************************************************************/
static void restore_text_console(
    int console_id)
{
    if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
	LOGWARN("ioctl(KDSETMODE) failed");
    _PM_restore_kb_mode();
}

/****************************************************************************
REMARKS:
Opens up the console device for output by finding an appropriate virutal
console that we can run on.
****************************************************************************/
PM_HWND PMAPI PM_openConsole(
    PM_HWND hwndUser,
    int device,
    int xRes,
    int yRes,
    int bpp,
    ibool fullScreen)
{
    struct vt_mode  vtm;
    struct vt_stat  vts;
    struct stat     sbuf;
    char            fname[30];

    /* Check if we have already opened the console */
    if (console_count++)
	return _PM_console_fd;

    /* Now, it would be great if we could use /dev/tty and see what it is
     * connected to. Alas, we cannot find out reliably what VC /dev/tty is
     * bound to. Thus we parse stdin through stderr for a reliable VC.
     */
    startup_vc = 0;
    for (_PM_console_fd = 0; _PM_console_fd < 3; _PM_console_fd++) {
	if (fstat(_PM_console_fd, &sbuf) < 0)
	    continue;
	if (ioctl(_PM_console_fd, VT_GETMODE, &vtm) < 0)
	    continue;
	if ((sbuf.st_rdev & 0xFF00) != 0x400)
	    continue;
	if (!(sbuf.st_rdev & 0xFF))
	    continue;
	tty_vc = sbuf.st_rdev & 0xFF;
	restore_text_console(_PM_console_fd);
	return _PM_console_fd;
	}
    if ((_PM_console_fd = open("/dev/console", O_RDWR)) < 0) {
	printf("open_dev_console: can't open /dev/console \n");
	exit(1);
	}
    if (ioctl(_PM_console_fd, VT_OPENQRY, &tty_vc) < 0)
	goto Error;
    if (tty_vc <= 0)
	goto Error;
    sprintf(fname, "/dev/tty%d", tty_vc);
    close(_PM_console_fd);

    /* Change our control terminal */
    setsid();

    /* We must use RDWR to allow for output... */
    if (((_PM_console_fd = open(fname, O_RDWR)) >= 0) &&
	    (ioctl(_PM_console_fd, VT_GETSTATE, &vts) >= 0)) {
	if (!check_owner(vts.v_active))
	    goto Error;
	restore_text_console(_PM_console_fd);

	/* Success, redirect all stdios */
	fflush(stdin);
	fflush(stdout);
	fflush(stderr);
	close(0);
	close(1);
	close(2);
	dup(_PM_console_fd);
	dup(_PM_console_fd);
	dup(_PM_console_fd);

	/* clear screen and switch to it */
	fwrite("\e[H\e[J", 6, 1, stderr);
	fflush(stderr);
	if (tty_vc != vts.v_active) {
	    startup_vc = vts.v_active;
	    ioctl(_PM_console_fd, VT_ACTIVATE, tty_vc);
	    wait_vt_active(_PM_console_fd);
	    }
	}
    return _PM_console_fd;

Error:
    if (_PM_console_fd > 2)
	close(_PM_console_fd);
    console_count = 0;
    PM_fatalError(
	"Not running in a graphics capable console,\n"
	"and unable to find one.\n");
    return -1;
}

#define FONT_C  0x10000     /* 64KB for font data                       */

/****************************************************************************
REMARKS:
Returns the size of the console state buffer.
****************************************************************************/
int PMAPI PM_getConsoleStateSize(void)
{
    if (!inited)
	PM_init();
    return PM_getVGAStateSize() + FONT_C*2;
}

/****************************************************************************
REMARKS:
Save the state of the Linux console.
****************************************************************************/
void PMAPI PM_saveConsoleState(void *stateBuf,int console_id)
{
    uchar   *regs = stateBuf;

    /* Save the current console font */
    if (ioctl(console_id,GIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
	perror("ioctl(GIO_FONT)");

    /* Inform the Linux console that we are going into graphics mode */
    if (ioctl(console_id, KDSETMODE, KD_GRAPHICS) < 0)
	perror("ioctl(KDSETMODE)");

    /* Save state of VGA registers */
    PM_saveVGAState(stateBuf);
}

void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
{
    /* TODO: Implement support for allowing console switching! */
}

/****************************************************************************
REMARKS:
Restore the state of the Linux console.
****************************************************************************/
void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND console_id)
{
    const uchar *regs = stateBuf;

    /* Restore the state of the VGA compatible registers */
    PM_restoreVGAState(stateBuf);

    /* Inform the Linux console that we are back from graphics modes */
    if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
	LOGWARN("ioctl(KDSETMODE) failed");

    /* Restore the old console font */
    if (ioctl(console_id,PIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
	LOGWARN("ioctl(KDSETMODE) failed");

    /* Coming back from graphics mode on Linux also restored the previous
     * text mode console contents, so we need to clear the screen to get
     * around this since the cursor does not get homed by our code.
     */
    fflush(stdout);
    fflush(stderr);
    printf("\033[H\033[J");
    fflush(stdout);
}

/****************************************************************************
REMARKS:
Close the Linux console and put it back to normal.
****************************************************************************/
void PMAPI PM_closeConsole(PM_HWND _PM_console_fd)
{
    /* Restore console to normal operation */
    if (--console_count == 0) {
	/* Re-activate the original virtual console */
	if (startup_vc > 0)
	    ioctl(_PM_console_fd, VT_ACTIVATE, startup_vc);

	/* Close the console file descriptor */
	if (_PM_console_fd > 2)
	    close(_PM_console_fd);
	_PM_console_fd = -1;
	}
}

void PM_setOSCursorLocation(int x,int y)
{
    /* Nothing to do in here */
}

/****************************************************************************
REMARKS:
Set the screen width and height for the Linux console.
****************************************************************************/
void PM_setOSScreenWidth(int width,int height)
{
    struct winsize  ws;
    struct vt_sizes vs;

    /* Resize the software terminal */
    ws.ws_col = width;
    ws.ws_row = height;
    ioctl(_PM_console_fd, TIOCSWINSZ, &ws);

    /* And the hardware */
    vs.v_rows = height;
    vs.v_cols = width;
    vs.v_scrollsize = 0;
    ioctl(_PM_console_fd, VT_RESIZE, &vs);
}

ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency)
{
    /* TODO: Implement this for Linux */
    return false;
}

void PMAPI PM_setRealTimeClockFrequency(int frequency)
{
    /* TODO: Implement this for Linux */
}

void PMAPI PM_restoreRealTimeClockHandler(void)
{
    /* TODO: Implement this for Linux */
}

char * PMAPI PM_getCurrentPath(
    char *path,
    int maxLen)
{
    return getcwd(path,maxLen);
}

char PMAPI PM_getBootDrive(void)
{ return '/'; }

const char * PMAPI PM_getVBEAFPath(void)
{ return PM_getNucleusConfigPath(); }

const char * PMAPI PM_getNucleusPath(void)
{
    char *env = getenv("NUCLEUS_PATH");
    return env ? env : "/usr/lib/nucleus";
}

const char * PMAPI PM_getNucleusConfigPath(void)
{

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?