1
/* serial.c - serial device interface */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28
/* An input buffer. */
29
static char input_buf[8];
30
static int npending = 0;
35
static int keep_track = 1;
38
/* Hardware-dependent definitions. */
41
/* The structure for speed vs. divisor. */
48
/* Store the port number of a serial unit. */
49
static unsigned short serial_hw_port = 0;
51
/* The table which lists common configurations. */
52
static struct divisor divisor_tab[] =
63
/* Read a byte from a port. */
64
static inline unsigned char
65
inb (unsigned short port)
69
asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port));
70
asm volatile ("outb %%al, $0x80" : : );
75
/* Write a byte to a port. */
77
outb (unsigned short port, unsigned char value)
79
asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port));
80
asm volatile ("outb %%al, $0x80" : : );
85
serial_hw_fetch (void)
87
if (inb (serial_hw_port + UART_LSR) & UART_DATA_READY)
88
return inb (serial_hw_port + UART_RX);
93
/* Put a chararacter. */
99
/* Wait until the transmitter holding register is empty. */
100
while ((inb (serial_hw_port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
103
/* There is something wrong. But what can I do? */
107
outb (serial_hw_port + UART_TX, c);
111
serial_hw_delay (void)
116
/* Return the port number for the UNITth serial device. */
118
serial_hw_get_port (int unit)
120
/* The BIOS data area. */
121
const unsigned short *addr = (const unsigned short *) 0x0400;
126
/* Initialize a serial device. PORT is the port number for a serial device.
127
SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
128
19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
129
for the device. Likewise, PARITY is the type of the parity and
130
STOP_BIT_LEN is the length of the stop bit. The possible values for
131
WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
134
serial_hw_init (unsigned short port, unsigned int speed,
135
int word_len, int parity, int stop_bit_len)
138
unsigned short div = 0;
139
unsigned char status = 0;
141
/* Turn off the interrupt. */
142
outb (port + UART_IER, 0);
145
outb (port + UART_LCR, UART_DLAB);
147
/* Set the baud rate. */
148
for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
149
if (divisor_tab[i].speed == speed)
151
div = divisor_tab[i].div;
158
outb (port + UART_DLL, div & 0xFF);
159
outb (port + UART_DLH, div >> 8);
161
/* Set the line status. */
162
status |= parity | word_len | stop_bit_len;
163
outb (port + UART_LCR, status);
165
/* Enable the FIFO. */
166
outb (port + UART_FCR, UART_ENABLE_FIFO);
168
/* Turn on DTR, RTS, and OUT2. */
169
outb (port + UART_MCR, UART_ENABLE_MODEM);
171
/* Store the port number. */
172
serial_hw_port = port;
174
/* Drain the input buffer. */
175
while (serial_checkkey () != -1)
176
(void) serial_getkey ();
178
/* Get rid of TERM_NEED_INIT from the serial terminal. */
179
for (i = 0; term_table[i].name; i++)
180
if (grub_strcmp (term_table[i].name, "serial") == 0)
182
term_table[i].flags &= ~TERM_NEED_INIT;
186
/* FIXME: should check if the serial terminal was found. */
190
#endif /* ! GRUB_UTIL */
193
/* Table of Serial Terminal Escape Sequences
194
*=======================================================================
195
* Key ANSI VT100 extension VT220 extension
196
* --------- ------- --------------- ---------------
199
* Right arrow <Esc>[C
206
* F6 <Esc>Ou <Esc>[17~ <Esc>[17~
207
* F7 <Esc>Ov <Esc>[18~ <Esc>[18~
208
* F8 <Esc>Ow <Esc>[19~ <Esc>[19~
209
* F9 <Esc>Ox <Esc>[20~ <Esc>[20~
210
* F10 <Esc>Oy <Esc>[21~ <Esc>[21~
211
* F11 <Esc>Oz <Esc>[23~ <Esc>[23~
212
* F12 <Esc>Oa <Esc>[24~ <Esc>[24~
219
* Shift-Tab <Esc>[Z <Esc>[0Z
222
/* Generic definitions. */
225
serial_translate_key_sequence (void)
230
short /*char*/ ascii;
234
{'A', KEY_UP/*16*/}, /* Up arrow */
235
{'B', KEY_DOWN/*14*/}, /* Down arrow */
236
{'C', KEY_RIGHT/*6*/}, /* Right arrow */
237
{'D', KEY_LEFT/*2*/}, /* Left arrow */
238
{'F', KEY_END/*5*/}, /* End */
239
{'H', KEY_HOME/*1*/}, /* Home */
240
{'4', KEY_DC/*4*/} /* Delete */
246
short /*char*/ ascii;
250
{('1' | ('~' << 8)), KEY_HOME/*1*/}, /* Home */
251
{('3' | ('~' << 8)), KEY_DC/*4*/}, /* Delete */
252
{('5' | ('~' << 8)), KEY_PPAGE/*7*/}, /* Page Up */
253
{('6' | ('~' << 8)), KEY_NPAGE/*3*/}, /* Page Down */
256
/* The buffer must start with ``ESC [''. */
257
if (*((unsigned short *) input_buf) != ('\e' | ('[' << 8)))
265
i < sizeof (three_code_table) / sizeof (three_code_table[0]);
267
if (three_code_table[i].key == input_buf[2])
269
*(short *)input_buf = three_code_table[i].ascii;
270
npending--;//npending -= 2;
271
grub_memmove (input_buf + 2/*1*/, input_buf + 3, npending - 2/*1*/);
279
short key = *((short *) (input_buf + 2));
282
i < sizeof (four_code_table) / sizeof (four_code_table[0]);
284
if (four_code_table[i].key == key)
286
*(short *)input_buf = four_code_table[i].ascii;
288
grub_memmove (input_buf + 2/*1*/, input_buf + 4, npending - 2/*1*/);
295
fill_input_buf (int nowait)
299
for (i = 0; i < 10000 && npending < sizeof (input_buf); i++)
303
c = serial_hw_fetch ();
306
input_buf[npending++] = c;
308
/* Reset the counter to zero, to wait for the same interval. */
316
/* Translate some key sequences. */
317
serial_translate_key_sequence ();
322
/* The serial version of getkey. */
328
while (! fill_input_buf (0))
332
if ((c = input_buf[0]))
333
grub_memmove (input_buf, input_buf + 1, npending);
337
c = *(unsigned short *)input_buf;
338
grub_memmove (input_buf, input_buf + 2, npending);
344
/* The serial version of checkkey. */
346
serial_checkkey (void)
348
if (fill_input_buf (1))
349
return input_buf[0] ? input_buf[0] : *(unsigned short *)input_buf;
354
/* The serial version of grub_putchar. */
356
serial_putchar (int c)
358
/* Keep track of the cursor. */
362
/* The serial terminal doesn't have VGA fonts. */
422
serial_putchar ('\r');
423
serial_putchar ('\n');
436
return (serial_x << 8) | serial_y;
440
serial_gotoxy (int x, int y)
443
ti_cursor_address (x, y);
457
serial_x = serial_y = 0;
461
serial_setcolorstate (color_state state)
464
if (state == COLOR_STATE_HIGHLIGHT)
465
ti_enter_standout_mode ();
467
ti_exit_standout_mode ();
471
#endif /* SUPPORT_SERIAL */