📄 serial.c
字号:
/* serial.c - serial device interface *//* * GRUB -- GRand Unified Bootloader * Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. * * 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 2 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. */#ifdef SUPPORT_SERIAL#include <shared.h>#include <serial.h>#include <term.h>#include <terminfo.h>/* An input buffer. */static char input_buf[8];static int npending = 0;static int serial_x;static int serial_y;static int keep_track = 1;/* Hardware-dependent definitions. */#ifndef GRUB_UTIL/* The structure for speed vs. divisor. */struct divisor{ int speed; unsigned short div;};/* Store the port number of a serial unit. */static unsigned short serial_hw_port = 0;/* The table which lists common configurations. */static struct divisor divisor_tab[] = { { 2400, 0x0030 }, { 4800, 0x0018 }, { 9600, 0x000C }, { 19200, 0x0006 }, { 38400, 0x0003 }, { 57600, 0x0002 }, { 115200, 0x0001 } };/* Read a byte from a port. */static inline unsigned charinb (unsigned short port){ unsigned char value; asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port)); asm volatile ("outb %%al, $0x80" : : ); return value;}/* Write a byte to a port. */static inline voidoutb (unsigned short port, unsigned char value){ asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port)); asm volatile ("outb %%al, $0x80" : : );}/* Fetch a key. */intserial_hw_fetch (void){ if (inb (serial_hw_port + UART_LSR) & UART_DATA_READY) return inb (serial_hw_port + UART_RX); return -1;}/* Put a chararacter. */voidserial_hw_put (int c){ int timeout = 100000; /* Wait until the transmitter holding register is empty. */ while ((inb (serial_hw_port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0) { if (--timeout == 0) /* There is something wrong. But what can I do? */ return; } outb (serial_hw_port + UART_TX, c);}voidserial_hw_delay (void){ outb (0x80, 0);}/* Return the port number for the UNITth serial device. */unsigned shortserial_hw_get_port (int unit){ /* The BIOS data area. */ const unsigned short *addr = (const unsigned short *) 0x0400; return addr[unit];}/* Initialize a serial device. PORT is the port number for a serial device. SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600, 19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used for the device. Likewise, PARITY is the type of the parity and STOP_BIT_LEN is the length of the stop bit. The possible values for WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as macros. */intserial_hw_init (unsigned short port, unsigned int speed, int word_len, int parity, int stop_bit_len){ int i; unsigned short div = 0; unsigned char status = 0; /* Turn off the interrupt. */ outb (port + UART_IER, 0); /* Set DLAB. */ outb (port + UART_LCR, UART_DLAB); /* Set the baud rate. */ for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++) if (divisor_tab[i].speed == speed) { div = divisor_tab[i].div; break; } if (div == 0) return 0; outb (port + UART_DLL, div & 0xFF); outb (port + UART_DLH, div >> 8); /* Set the line status. */ status |= parity | word_len | stop_bit_len; outb (port + UART_LCR, status); /* Enable the FIFO. */ outb (port + UART_FCR, UART_ENABLE_FIFO); /* Turn on DTR, RTS, and OUT2. */ outb (port + UART_MCR, UART_ENABLE_MODEM); /* Store the port number. */ serial_hw_port = port; /* Drain the input buffer. */ while (serial_checkkey () != -1) (void) serial_getkey (); /* Get rid of TERM_NEED_INIT from the serial terminal. */ for (i = 0; term_table[i].name; i++) if (grub_strcmp (term_table[i].name, "serial") == 0) { term_table[i].flags &= ~TERM_NEED_INIT; break; } /* FIXME: should check if the serial terminal was found. */ return 1;}#endif /* ! GRUB_UTIL *//* Table of Serial Terminal Escape Sequences *======================================================================= * Key ANSI VT100 extension VT220 extension * --------- ------- --------------- --------------- * Up arrow <Esc>[A * Down arrow <Esc>[B * Right arrow <Esc>[C * Left arrow <Esc>[D * F1 <Esc>Op * F2 <Esc>Oq * F3 <Esc>Or * F4 <Esc>Os * F5 <Esc>Ot * F6 <Esc>Ou <Esc>[17~ <Esc>[17~ * F7 <Esc>Ov <Esc>[18~ <Esc>[18~ * F8 <Esc>Ow <Esc>[19~ <Esc>[19~ * F9 <Esc>Ox <Esc>[20~ <Esc>[20~ * F10 <Esc>Oy <Esc>[21~ <Esc>[21~ * F11 <Esc>Oz <Esc>[23~ <Esc>[23~ * F12 <Esc>Oa <Esc>[24~ <Esc>[24~ * Home <Esc>[1~ * End <Esc>[4~ * Insert <Esc>[2~ * Delete <Esc>[3~ * Page Up <Esc>[5~ * Page Down <Esc>[6~ * Shift-Tab <Esc>[Z <Esc>[0Z *//* Generic definitions. */static voidserial_translate_key_sequence (void){ const struct { short /*char*/ key; short /*char*/ ascii; } three_code_table[] = { {'A', KEY_UP/*16*/}, /* Up arrow */ {'B', KEY_DOWN/*14*/}, /* Down arrow */ {'C', KEY_RIGHT/*6*/}, /* Right arrow */ {'D', KEY_LEFT/*2*/}, /* Left arrow */ {'F', KEY_END/*5*/}, /* End */ {'H', KEY_HOME/*1*/}, /* Home */ {'4', KEY_DC/*4*/} /* Delete */ }; const struct { short key; short /*char*/ ascii; } four_code_table[] = { {('1' | ('~' << 8)), KEY_HOME/*1*/}, /* Home */ {('3' | ('~' << 8)), KEY_DC/*4*/}, /* Delete */ {('5' | ('~' << 8)), KEY_PPAGE/*7*/}, /* Page Up */ {('6' | ('~' << 8)), KEY_NPAGE/*3*/}, /* Page Down */ }; /* The buffer must start with ``ESC [''. */ if (*((unsigned short *) input_buf) != ('\e' | ('[' << 8))) return; if (npending >= 3) { int i; for (i = 0; i < sizeof (three_code_table) / sizeof (three_code_table[0]); i++) if (three_code_table[i].key == input_buf[2]) { *(short *)input_buf = three_code_table[i].ascii; npending--;//npending -= 2; grub_memmove (input_buf + 2/*1*/, input_buf + 3, npending - 2/*1*/); return; } } if (npending >= 4) { int i; short key = *((short *) (input_buf + 2)); for (i = 0; i < sizeof (four_code_table) / sizeof (four_code_table[0]); i++) if (four_code_table[i].key == key) { *(short *)input_buf = four_code_table[i].ascii; npending -= 2/*3*/; grub_memmove (input_buf + 2/*1*/, input_buf + 4, npending - 2/*1*/); return; } }} static intfill_input_buf (int nowait){ int i; for (i = 0; i < 10000 && npending < sizeof (input_buf); i++) { int c; c = serial_hw_fetch (); if (c >= 0) { input_buf[npending++] = c; /* Reset the counter to zero, to wait for the same interval. */ i = 0; } if (nowait) break; } /* Translate some key sequences. */ serial_translate_key_sequence (); return npending;}/* The serial version of getkey. */intserial_getkey (void){ int c; while (! fill_input_buf (0)) ; npending--; if ((c = input_buf[0])) grub_memmove (input_buf, input_buf + 1, npending); else { npending--; c = *(unsigned short *)input_buf; grub_memmove (input_buf, input_buf + 2, npending); } return c;}/* The serial version of checkkey. */intserial_checkkey (void){ if (fill_input_buf (1)) return input_buf[0] ? input_buf[0] : *(unsigned short *)input_buf; return -1;}/* The serial version of grub_putchar. */voidserial_putchar (int c){ /* Keep track of the cursor. */ if (keep_track) {#if 0 /* The serial terminal doesn't have VGA fonts. */ switch (c) { case DISP_UL: c = ACS_ULCORNER; break; case DISP_UR: c = ACS_URCORNER; break; case DISP_LL: c = ACS_LLCORNER; break; case DISP_LR: c = ACS_LRCORNER; break; case DISP_HORIZ: c = ACS_HLINE; break; case DISP_VERT: c = ACS_VLINE; break; case DISP_LEFT: c = ACS_LARROW; break; case DISP_RIGHT: c = ACS_RARROW; break; case DISP_UP: c = ACS_UARROW; break; case DISP_DOWN: c = ACS_DARROW; break; default: break; }#endif switch (c) { case '\r': serial_x = 0; break; case '\n': serial_y++; break; case '\b': case 127: if (serial_x > 0) serial_x--; break; case '\a': break; default: if (serial_x >= 79) { serial_putchar ('\r'); serial_putchar ('\n'); } serial_x++; break; } } serial_hw_put (c);}intserial_getxy (void){ return (serial_x << 8) | serial_y;}voidserial_gotoxy (int x, int y){ keep_track = 0; ti_cursor_address (x, y); keep_track = 1; serial_x = x; serial_y = y;}voidserial_cls (void){ keep_track = 0; ti_clear_screen (); keep_track = 1; serial_x = serial_y = 0;}voidserial_setcolorstate (color_state state){ keep_track = 0; if (state == COLOR_STATE_HIGHLIGHT) ti_enter_standout_mode (); else ti_exit_standout_mode (); keep_track = 1;}#endif /* SUPPORT_SERIAL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -