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 #define COMP_BS_SERIAL 0x01
29 #define COMP_BS_BIOS 0x02
31 /* An input buffer. */
32 static char input_buf
[8];
33 static int npending
= 0;
38 static int keep_track
= 1;
39 static int composite_bitset
= COMP_BS_SERIAL
| COMP_BS_BIOS
;
42 /* Hardware-dependent definitions. */
45 /* The structure for speed vs. divisor. */
52 /* Store the port number of a serial unit. */
53 static unsigned short serial_hw_port
= 0;
55 /* The table which lists common configurations. */
56 static struct divisor divisor_tab
[] =
67 /* Read a byte from a port. */
68 static inline unsigned char
69 inb (unsigned short port
)
73 asm volatile ("inb %w1, %0" : "=a" (value
) : "Nd" (port
));
74 asm volatile ("outb %%al, $0x80" : : );
79 /* Write a byte to a port. */
81 outb (unsigned short port
, unsigned char value
)
83 asm volatile ("outb %b0, %w1" : : "a" (value
), "Nd" (port
));
84 asm volatile ("outb %%al, $0x80" : : );
89 serial_hw_fetch (void)
91 if (inb (serial_hw_port
+ UART_LSR
) & UART_DATA_READY
)
92 return inb (serial_hw_port
+ UART_RX
);
97 /* Put a chararacter. */
101 int timeout
= 100000;
103 /* Wait until the transmitter holding register is empty. */
104 while ((inb (serial_hw_port
+ UART_LSR
) & UART_EMPTY_TRANSMITTER
) == 0)
107 /* There is something wrong. But what can I do? */
111 outb (serial_hw_port
+ UART_TX
, c
);
115 serial_hw_delay (void)
120 /* Return the port number for the UNITth serial device. */
122 serial_hw_get_port (int unit
)
124 /* The BIOS data area. */
125 const unsigned short *addr
= (const unsigned short *) 0x0400;
130 /* Initialize a serial device. PORT is the port number for a serial device.
131 SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
132 19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
133 for the device. Likewise, PARITY is the type of the parity and
134 STOP_BIT_LEN is the length of the stop bit. The possible values for
135 WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
138 serial_hw_init (unsigned short port
, unsigned int speed
,
139 int word_len
, int parity
, int stop_bit_len
)
142 unsigned short div
= 0;
143 unsigned char status
= 0;
148 /* Make sure the port actually exists. */
149 outb (port
+ UART_SR
, UART_SR_TEST
);
150 outb (port
+ UART_FCR
, 0);
151 status
= inb (port
+ UART_SR
);
152 if (status
!= UART_SR_TEST
)
155 /* Turn off the interrupt. */
156 outb (port
+ UART_IER
, 0);
159 outb (port
+ UART_LCR
, UART_DLAB
);
161 /* Set the baud rate. */
162 for (i
= 0; i
< sizeof (divisor_tab
) / sizeof (divisor_tab
[0]); i
++)
163 if (divisor_tab
[i
].speed
== speed
)
165 div
= divisor_tab
[i
].div
;
172 outb (port
+ UART_DLL
, div
& 0xFF);
173 outb (port
+ UART_DLH
, div
>> 8);
175 /* Set the line status. */
176 status
= parity
| word_len
| stop_bit_len
;
177 outb (port
+ UART_LCR
, status
);
179 /* Enable the FIFO. */
180 outb (port
+ UART_FCR
, UART_ENABLE_FIFO
);
182 /* Turn on DTR, RTS, and OUT2. */
183 outb (port
+ UART_MCR
, UART_ENABLE_MODEM
);
185 /* Store the port number. */
186 serial_hw_port
= port
;
188 /* Drain the input buffer. */
189 while (serial_checkkey () != -1)
190 (void) serial_getkey ();
192 /* Get rid of TERM_NEED_INIT from the serial terminal. */
193 for (i
= 0; term_table
[i
].name
; i
++)
194 if (grub_strcmp (term_table
[i
].name
, "serial") == 0 ||
195 grub_strcmp (term_table
[i
].name
, "composite") == 0)
197 term_table
[i
].flags
&= ~TERM_NEED_INIT
;
202 #endif /* ! GRUB_UTIL */
205 /* Generic definitions. */
208 serial_translate_key_sequence (void)
233 {('1' | ('~' << 8)), 1},
234 {('3' | ('~' << 8)), 4},
235 {('5' | ('~' << 8)), 7},
236 {('6' | ('~' << 8)), 3},
239 /* The buffer must start with ``ESC [''. */
240 if (*((unsigned short *) input_buf
) != ('\e' | ('[' << 8)))
248 i
< sizeof (three_code_table
) / sizeof (three_code_table
[0]);
250 if (three_code_table
[i
].key
== input_buf
[2])
252 input_buf
[0] = three_code_table
[i
].ascii
;
254 grub_memmove (input_buf
+ 1, input_buf
+ 3, npending
- 1);
262 short key
= *((short *) (input_buf
+ 2));
265 i
< sizeof (four_code_table
) / sizeof (four_code_table
[0]);
267 if (four_code_table
[i
].key
== key
)
269 input_buf
[0] = four_code_table
[i
].ascii
;
271 grub_memmove (input_buf
+ 1, input_buf
+ 4, npending
- 1);
278 int fill_input_buf (int nowait
)
282 for (i
= 0; i
< 10000 && npending
< sizeof (input_buf
); i
++)
286 c
= serial_hw_fetch ();
289 input_buf
[npending
++] = c
;
291 /* Reset the counter to zero, to wait for the same interval. */
299 /* Translate some key sequences. */
300 serial_translate_key_sequence ();
305 /* The serial version of getkey. */
311 while (! fill_input_buf (0))
316 grub_memmove (input_buf
, input_buf
+ 1, npending
);
321 /* The serial version of checkkey. */
323 serial_checkkey (void)
325 if (fill_input_buf (1))
331 /* The serial version of grub_putchar. */
333 serial_putchar (int c
)
335 /* Keep track of the cursor. */
338 /* The serial terminal doesn't have VGA fonts. */
397 serial_putchar ('\r');
398 serial_putchar ('\n');
411 return (serial_x
<< 8) | serial_y
;
415 serial_gotoxy (int x
, int y
)
417 int saved_cbs
= composite_bitset
;
420 composite_bitset
&= ~COMP_BS_BIOS
;
421 ti_cursor_address (x
, y
);
422 composite_bitset
= saved_cbs
;
432 int saved_cbs
= composite_bitset
;
435 composite_bitset
&= ~COMP_BS_BIOS
;
437 composite_bitset
= saved_cbs
;
440 serial_x
= serial_y
= 0;
444 serial_setcolorstate (color_state state
)
446 int saved_cbs
= composite_bitset
;
449 composite_bitset
&= ~COMP_BS_BIOS
;
450 if (state
== COLOR_STATE_HIGHLIGHT
)
451 ti_enter_standout_mode ();
453 ti_exit_standout_mode ();
454 composite_bitset
= saved_cbs
;
459 composite_putchar (int c
)
461 if (composite_bitset
& COMP_BS_SERIAL
)
463 if (composite_bitset
& COMP_BS_BIOS
)
468 composite_getkey (void)
471 if (serial_checkkey () != -1)
472 return (serial_getkey ());
473 if (console_checkkey () != -1)
474 return (console_getkey ());
479 composite_checkkey (void)
483 if ((ch
= serial_checkkey ()) != -1)
485 return (console_checkkey ());
489 composite_gotoxy (int x
, int y
)
491 serial_gotoxy (x
, y
);
492 console_gotoxy (x
, y
);
503 composite_setcolorstate (color_state state
)
505 serial_setcolorstate (state
);
506 console_setcolorstate (state
);
509 #endif /* SUPPORT_SERIAL */