17c478bd9Sstevel@tonic-gate /* serial.c - serial device interface */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
47c478bd9Sstevel@tonic-gate  *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate  */
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate #include <shared.h>
247c478bd9Sstevel@tonic-gate #include <serial.h>
257c478bd9Sstevel@tonic-gate #include <term.h>
267c478bd9Sstevel@tonic-gate #include <terminfo.h>
277c478bd9Sstevel@tonic-gate 
28a5602e1bSKeith M Wesolowski #define	COMP_BS_SERIAL	0x01
29a5602e1bSKeith M Wesolowski #define	COMP_BS_BIOS	0x02
30a5602e1bSKeith M Wesolowski 
317c478bd9Sstevel@tonic-gate /* An input buffer.  */
327c478bd9Sstevel@tonic-gate static char input_buf[8];
337c478bd9Sstevel@tonic-gate static int npending = 0;
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate static int serial_x;
367c478bd9Sstevel@tonic-gate static int serial_y;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static int keep_track = 1;
39a5602e1bSKeith M Wesolowski static int composite_bitset = COMP_BS_SERIAL | COMP_BS_BIOS;
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /* Hardware-dependent definitions.  */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #ifndef GRUB_UTIL
457c478bd9Sstevel@tonic-gate /* The structure for speed vs. divisor.  */
467c478bd9Sstevel@tonic-gate struct divisor
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate   int speed;
497c478bd9Sstevel@tonic-gate   unsigned short div;
507c478bd9Sstevel@tonic-gate };
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /* Store the port number of a serial unit.  */
537c478bd9Sstevel@tonic-gate static unsigned short serial_hw_port = 0;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /* The table which lists common configurations.  */
567c478bd9Sstevel@tonic-gate static struct divisor divisor_tab[] =
577c478bd9Sstevel@tonic-gate   {
587c478bd9Sstevel@tonic-gate     { 2400,   0x0030 },
597c478bd9Sstevel@tonic-gate     { 4800,   0x0018 },
607c478bd9Sstevel@tonic-gate     { 9600,   0x000C },
617c478bd9Sstevel@tonic-gate     { 19200,  0x0006 },
627c478bd9Sstevel@tonic-gate     { 38400,  0x0003 },
637c478bd9Sstevel@tonic-gate     { 57600,  0x0002 },
647c478bd9Sstevel@tonic-gate     { 115200, 0x0001 }
657c478bd9Sstevel@tonic-gate   };
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /* Read a byte from a port.  */
687c478bd9Sstevel@tonic-gate static inline unsigned char
inb(unsigned short port)697c478bd9Sstevel@tonic-gate inb (unsigned short port)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate   unsigned char value;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate   asm volatile ("inb	%w1, %0" : "=a" (value) : "Nd" (port));
747c478bd9Sstevel@tonic-gate   asm volatile ("outb	%%al, $0x80" : : );
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate   return value;
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /* Write a byte to a port.  */
807c478bd9Sstevel@tonic-gate static inline void
outb(unsigned short port,unsigned char value)817c478bd9Sstevel@tonic-gate outb (unsigned short port, unsigned char value)
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate   asm volatile ("outb	%b0, %w1" : : "a" (value), "Nd" (port));
847c478bd9Sstevel@tonic-gate   asm volatile ("outb	%%al, $0x80" : : );
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* Fetch a key.  */
887c478bd9Sstevel@tonic-gate int
serial_hw_fetch(void)897c478bd9Sstevel@tonic-gate serial_hw_fetch (void)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate   if (inb (serial_hw_port + UART_LSR) & UART_DATA_READY)
927c478bd9Sstevel@tonic-gate     return inb (serial_hw_port + UART_RX);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate   return -1;
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /* Put a chararacter.  */
987c478bd9Sstevel@tonic-gate void
serial_hw_put(int c)997c478bd9Sstevel@tonic-gate serial_hw_put (int c)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate   int timeout = 100000;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate   /* Wait until the transmitter holding register is empty.  */
1047c478bd9Sstevel@tonic-gate   while ((inb (serial_hw_port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
1057c478bd9Sstevel@tonic-gate     {
1067c478bd9Sstevel@tonic-gate       if (--timeout == 0)
1077c478bd9Sstevel@tonic-gate 	/* There is something wrong. But what can I do?  */
1087c478bd9Sstevel@tonic-gate 	return;
1097c478bd9Sstevel@tonic-gate     }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate   outb (serial_hw_port + UART_TX, c);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate void
serial_hw_delay(void)1157c478bd9Sstevel@tonic-gate serial_hw_delay (void)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate   outb (0x80, 0);
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /* Return the port number for the UNITth serial device.  */
1217c478bd9Sstevel@tonic-gate unsigned short
serial_hw_get_port(int unit)1227c478bd9Sstevel@tonic-gate serial_hw_get_port (int unit)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate   /* The BIOS data area.  */
1257c478bd9Sstevel@tonic-gate   const unsigned short *addr = (const unsigned short *) 0x0400;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate   return addr[unit];
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /* Initialize a serial device. PORT is the port number for a serial device.
1317c478bd9Sstevel@tonic-gate    SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
1327c478bd9Sstevel@tonic-gate    19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
1337c478bd9Sstevel@tonic-gate    for the device. Likewise, PARITY is the type of the parity and
1347c478bd9Sstevel@tonic-gate    STOP_BIT_LEN is the length of the stop bit. The possible values for
1357c478bd9Sstevel@tonic-gate    WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
1367c478bd9Sstevel@tonic-gate    macros.  */
1377c478bd9Sstevel@tonic-gate int
serial_hw_init(unsigned short port,unsigned int speed,int word_len,int parity,int stop_bit_len)1387c478bd9Sstevel@tonic-gate serial_hw_init (unsigned short port, unsigned int speed,
1397c478bd9Sstevel@tonic-gate 		int word_len, int parity, int stop_bit_len)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate   int i;
1427c478bd9Sstevel@tonic-gate   unsigned short div = 0;
1437c478bd9Sstevel@tonic-gate   unsigned char status = 0;
144*5626beecSKeith M Wesolowski 
145*5626beecSKeith M Wesolowski   if (port == 0)
146*5626beecSKeith M Wesolowski     return 0;
147*5626beecSKeith M Wesolowski 
148*5626beecSKeith M Wesolowski   /* Make sure the port actually exists. */
149*5626beecSKeith M Wesolowski   outb (port + UART_SR, UART_SR_TEST);
150*5626beecSKeith M Wesolowski   outb (port + UART_FCR, 0);
151*5626beecSKeith M Wesolowski   status = inb (port + UART_SR);
152*5626beecSKeith M Wesolowski   if (status != UART_SR_TEST)
153*5626beecSKeith M Wesolowski     return 0;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate   /* Turn off the interrupt.  */
1567c478bd9Sstevel@tonic-gate   outb (port + UART_IER, 0);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate   /* Set DLAB.  */
1597c478bd9Sstevel@tonic-gate   outb (port + UART_LCR, UART_DLAB);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate   /* Set the baud rate.  */
1627c478bd9Sstevel@tonic-gate   for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
1637c478bd9Sstevel@tonic-gate     if (divisor_tab[i].speed == speed)
1647c478bd9Sstevel@tonic-gate       {
1657c478bd9Sstevel@tonic-gate 	div = divisor_tab[i].div;
1667c478bd9Sstevel@tonic-gate 	break;
1677c478bd9Sstevel@tonic-gate       }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate   if (div == 0)
1707c478bd9Sstevel@tonic-gate     return 0;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate   outb (port + UART_DLL, div & 0xFF);
1737c478bd9Sstevel@tonic-gate   outb (port + UART_DLH, div >> 8);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate   /* Set the line status.  */
176*5626beecSKeith M Wesolowski   status = parity | word_len | stop_bit_len;
1777c478bd9Sstevel@tonic-gate   outb (port + UART_LCR, status);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate   /* Enable the FIFO.  */
1807c478bd9Sstevel@tonic-gate   outb (port + UART_FCR, UART_ENABLE_FIFO);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate   /* Turn on DTR, RTS, and OUT2.  */
1837c478bd9Sstevel@tonic-gate   outb (port + UART_MCR, UART_ENABLE_MODEM);
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate   /* Store the port number.  */
1867c478bd9Sstevel@tonic-gate   serial_hw_port = port;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate   /* Drain the input buffer.  */
1897c478bd9Sstevel@tonic-gate   while (serial_checkkey () != -1)
1907c478bd9Sstevel@tonic-gate     (void) serial_getkey ();
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate   /* Get rid of TERM_NEED_INIT from the serial terminal.  */
1937c478bd9Sstevel@tonic-gate   for (i = 0; term_table[i].name; i++)
194a5602e1bSKeith M Wesolowski     if (grub_strcmp (term_table[i].name, "serial") == 0 ||
195a5602e1bSKeith M Wesolowski 	grub_strcmp (term_table[i].name, "composite") == 0)
1967c478bd9Sstevel@tonic-gate       {
1977c478bd9Sstevel@tonic-gate 	term_table[i].flags &= ~TERM_NEED_INIT;
1987c478bd9Sstevel@tonic-gate       }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate   return 1;
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /* Generic definitions.  */
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static void
serial_translate_key_sequence(void)2087c478bd9Sstevel@tonic-gate serial_translate_key_sequence (void)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate   const struct
2117c478bd9Sstevel@tonic-gate   {
2127c478bd9Sstevel@tonic-gate     char key;
2137c478bd9Sstevel@tonic-gate     char ascii;
2147c478bd9Sstevel@tonic-gate   }
2157c478bd9Sstevel@tonic-gate   three_code_table[] =
2167c478bd9Sstevel@tonic-gate     {
2177c478bd9Sstevel@tonic-gate       {'A', 16},
2187c478bd9Sstevel@tonic-gate       {'B', 14},
2197c478bd9Sstevel@tonic-gate       {'C', 6},
2207c478bd9Sstevel@tonic-gate       {'D', 2},
2217c478bd9Sstevel@tonic-gate       {'F', 5},
2227c478bd9Sstevel@tonic-gate       {'H', 1},
2237c478bd9Sstevel@tonic-gate       {'4', 4}
2247c478bd9Sstevel@tonic-gate     };
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate   const struct
2277c478bd9Sstevel@tonic-gate   {
2287c478bd9Sstevel@tonic-gate     short key;
2297c478bd9Sstevel@tonic-gate     char ascii;
2307c478bd9Sstevel@tonic-gate   }
2317c478bd9Sstevel@tonic-gate   four_code_table[] =
2327c478bd9Sstevel@tonic-gate     {
2337c478bd9Sstevel@tonic-gate       {('1' | ('~' << 8)), 1},
2347c478bd9Sstevel@tonic-gate       {('3' | ('~' << 8)), 4},
2357c478bd9Sstevel@tonic-gate       {('5' | ('~' << 8)), 7},
2367c478bd9Sstevel@tonic-gate       {('6' | ('~' << 8)), 3},
2377c478bd9Sstevel@tonic-gate     };
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate   /* The buffer must start with ``ESC [''.  */
2407c478bd9Sstevel@tonic-gate   if (*((unsigned short *) input_buf) != ('\e' | ('[' << 8)))
2417c478bd9Sstevel@tonic-gate     return;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate   if (npending >= 3)
2447c478bd9Sstevel@tonic-gate     {
2457c478bd9Sstevel@tonic-gate       int i;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate       for (i = 0;
2487c478bd9Sstevel@tonic-gate 	   i < sizeof (three_code_table) / sizeof (three_code_table[0]);
2497c478bd9Sstevel@tonic-gate 	   i++)
2507c478bd9Sstevel@tonic-gate 	if (three_code_table[i].key == input_buf[2])
2517c478bd9Sstevel@tonic-gate 	  {
2527c478bd9Sstevel@tonic-gate 	    input_buf[0] = three_code_table[i].ascii;
2537c478bd9Sstevel@tonic-gate 	    npending -= 2;
2547c478bd9Sstevel@tonic-gate 	    grub_memmove (input_buf + 1, input_buf + 3, npending - 1);
2557c478bd9Sstevel@tonic-gate 	    return;
2567c478bd9Sstevel@tonic-gate 	  }
2577c478bd9Sstevel@tonic-gate     }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate   if (npending >= 4)
2607c478bd9Sstevel@tonic-gate     {
2617c478bd9Sstevel@tonic-gate       int i;
2627c478bd9Sstevel@tonic-gate       short key = *((short *) (input_buf + 2));
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate       for (i = 0;
2657c478bd9Sstevel@tonic-gate 	   i < sizeof (four_code_table) / sizeof (four_code_table[0]);
2667c478bd9Sstevel@tonic-gate 	   i++)
2677c478bd9Sstevel@tonic-gate 	if (four_code_table[i].key == key)
2687c478bd9Sstevel@tonic-gate 	  {
2697c478bd9Sstevel@tonic-gate 	    input_buf[0] = four_code_table[i].ascii;
2707c478bd9Sstevel@tonic-gate 	    npending -= 3;
2717c478bd9Sstevel@tonic-gate 	    grub_memmove (input_buf + 1, input_buf + 4, npending - 1);
2727c478bd9Sstevel@tonic-gate 	    return;
2737c478bd9Sstevel@tonic-gate 	  }
2747c478bd9Sstevel@tonic-gate     }
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate static
fill_input_buf(int nowait)2787c478bd9Sstevel@tonic-gate int fill_input_buf (int nowait)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate   int i;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate   for (i = 0; i < 10000 && npending < sizeof (input_buf); i++)
2837c478bd9Sstevel@tonic-gate     {
2847c478bd9Sstevel@tonic-gate       int c;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate       c = serial_hw_fetch ();
2877c478bd9Sstevel@tonic-gate       if (c >= 0)
2887c478bd9Sstevel@tonic-gate 	{
2897c478bd9Sstevel@tonic-gate 	  input_buf[npending++] = c;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	  /* Reset the counter to zero, to wait for the same interval.  */
2927c478bd9Sstevel@tonic-gate 	  i = 0;
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate       if (nowait)
2967c478bd9Sstevel@tonic-gate 	break;
2977c478bd9Sstevel@tonic-gate     }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate   /* Translate some key sequences.  */
3007c478bd9Sstevel@tonic-gate   serial_translate_key_sequence ();
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate   return npending;
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /* The serial version of getkey.  */
3067c478bd9Sstevel@tonic-gate int
serial_getkey(void)3077c478bd9Sstevel@tonic-gate serial_getkey (void)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate   int c;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate   while (! fill_input_buf (0))
3127c478bd9Sstevel@tonic-gate     ;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate   c = input_buf[0];
3157c478bd9Sstevel@tonic-gate   npending--;
3167c478bd9Sstevel@tonic-gate   grub_memmove (input_buf, input_buf + 1, npending);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate   return c;
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /* The serial version of checkkey.  */
3227c478bd9Sstevel@tonic-gate int
serial_checkkey(void)3237c478bd9Sstevel@tonic-gate serial_checkkey (void)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate   if (fill_input_buf (1))
3267c478bd9Sstevel@tonic-gate     return input_buf[0];
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate   return -1;
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate /* The serial version of grub_putchar.  */
3327c478bd9Sstevel@tonic-gate void
serial_putchar(int c)3337c478bd9Sstevel@tonic-gate serial_putchar (int c)
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate   /* Keep track of the cursor.  */
3367c478bd9Sstevel@tonic-gate   if (keep_track)
3377c478bd9Sstevel@tonic-gate     {
3387c478bd9Sstevel@tonic-gate       /* The serial terminal doesn't have VGA fonts.  */
3397c478bd9Sstevel@tonic-gate       switch (c)
3407c478bd9Sstevel@tonic-gate 	{
3417c478bd9Sstevel@tonic-gate 	case DISP_UL:
3427c478bd9Sstevel@tonic-gate 	  c = ACS_ULCORNER;
3437c478bd9Sstevel@tonic-gate 	  break;
3447c478bd9Sstevel@tonic-gate 	case DISP_UR:
3457c478bd9Sstevel@tonic-gate 	  c = ACS_URCORNER;
3467c478bd9Sstevel@tonic-gate 	  break;
3477c478bd9Sstevel@tonic-gate 	case DISP_LL:
3487c478bd9Sstevel@tonic-gate 	  c = ACS_LLCORNER;
3497c478bd9Sstevel@tonic-gate 	  break;
3507c478bd9Sstevel@tonic-gate 	case DISP_LR:
3517c478bd9Sstevel@tonic-gate 	  c = ACS_LRCORNER;
3527c478bd9Sstevel@tonic-gate 	  break;
3537c478bd9Sstevel@tonic-gate 	case DISP_HORIZ:
3547c478bd9Sstevel@tonic-gate 	  c = ACS_HLINE;
3557c478bd9Sstevel@tonic-gate 	  break;
3567c478bd9Sstevel@tonic-gate 	case DISP_VERT:
3577c478bd9Sstevel@tonic-gate 	  c = ACS_VLINE;
3587c478bd9Sstevel@tonic-gate 	  break;
3597c478bd9Sstevel@tonic-gate 	case DISP_LEFT:
3607c478bd9Sstevel@tonic-gate 	  c = ACS_LARROW;
3617c478bd9Sstevel@tonic-gate 	  break;
3627c478bd9Sstevel@tonic-gate 	case DISP_RIGHT:
3637c478bd9Sstevel@tonic-gate 	  c = ACS_RARROW;
3647c478bd9Sstevel@tonic-gate 	  break;
3657c478bd9Sstevel@tonic-gate 	case DISP_UP:
3667c478bd9Sstevel@tonic-gate 	  c = ACS_UARROW;
3677c478bd9Sstevel@tonic-gate 	  break;
3687c478bd9Sstevel@tonic-gate 	case DISP_DOWN:
3697c478bd9Sstevel@tonic-gate 	  c = ACS_DARROW;
3707c478bd9Sstevel@tonic-gate 	  break;
3717c478bd9Sstevel@tonic-gate 	default:
3727c478bd9Sstevel@tonic-gate 	  break;
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate       switch (c)
3767c478bd9Sstevel@tonic-gate 	{
3777c478bd9Sstevel@tonic-gate 	case '\r':
3787c478bd9Sstevel@tonic-gate 	  serial_x = 0;
3797c478bd9Sstevel@tonic-gate 	  break;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	case '\n':
3827c478bd9Sstevel@tonic-gate 	  serial_y++;
3837c478bd9Sstevel@tonic-gate 	  break;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	case '\b':
3867c478bd9Sstevel@tonic-gate 	case 127:
3877c478bd9Sstevel@tonic-gate 	  if (serial_x > 0)
3887c478bd9Sstevel@tonic-gate 	    serial_x--;
3897c478bd9Sstevel@tonic-gate 	  break;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	case '\a':
3927c478bd9Sstevel@tonic-gate 	  break;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	default:
3957c478bd9Sstevel@tonic-gate 	  if (serial_x >= 79)
3967c478bd9Sstevel@tonic-gate 	    {
3977c478bd9Sstevel@tonic-gate 	      serial_putchar ('\r');
3987c478bd9Sstevel@tonic-gate 	      serial_putchar ('\n');
3997c478bd9Sstevel@tonic-gate 	    }
4007c478bd9Sstevel@tonic-gate 	  serial_x++;
4017c478bd9Sstevel@tonic-gate 	  break;
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate     }
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate   serial_hw_put (c);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate int
serial_getxy(void)4097c478bd9Sstevel@tonic-gate serial_getxy (void)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate   return (serial_x << 8) | serial_y;
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate void
serial_gotoxy(int x,int y)4157c478bd9Sstevel@tonic-gate serial_gotoxy (int x, int y)
4167c478bd9Sstevel@tonic-gate {
417a5602e1bSKeith M Wesolowski   int saved_cbs = composite_bitset;
418a5602e1bSKeith M Wesolowski 
4197c478bd9Sstevel@tonic-gate   keep_track = 0;
420a5602e1bSKeith M Wesolowski   composite_bitset &= ~COMP_BS_BIOS;
4217c478bd9Sstevel@tonic-gate   ti_cursor_address (x, y);
422a5602e1bSKeith M Wesolowski   composite_bitset = saved_cbs;
4237c478bd9Sstevel@tonic-gate   keep_track = 1;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate   serial_x = x;
4267c478bd9Sstevel@tonic-gate   serial_y = y;
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate void
serial_cls(void)4307c478bd9Sstevel@tonic-gate serial_cls (void)
4317c478bd9Sstevel@tonic-gate {
432a5602e1bSKeith M Wesolowski   int saved_cbs = composite_bitset;
433a5602e1bSKeith M Wesolowski 
4347c478bd9Sstevel@tonic-gate   keep_track = 0;
435a5602e1bSKeith M Wesolowski   composite_bitset &= ~COMP_BS_BIOS;
4367c478bd9Sstevel@tonic-gate   ti_clear_screen ();
437a5602e1bSKeith M Wesolowski   composite_bitset = saved_cbs;
4387c478bd9Sstevel@tonic-gate   keep_track = 1;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate   serial_x = serial_y = 0;
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate void
serial_setcolorstate(color_state state)4447c478bd9Sstevel@tonic-gate serial_setcolorstate (color_state state)
4457c478bd9Sstevel@tonic-gate {
446a5602e1bSKeith M Wesolowski   int saved_cbs = composite_bitset;
447a5602e1bSKeith M Wesolowski 
4487c478bd9Sstevel@tonic-gate   keep_track = 0;
449a5602e1bSKeith M Wesolowski   composite_bitset &= ~COMP_BS_BIOS;
4507c478bd9Sstevel@tonic-gate   if (state == COLOR_STATE_HIGHLIGHT)
4517c478bd9Sstevel@tonic-gate     ti_enter_standout_mode ();
4527c478bd9Sstevel@tonic-gate   else
4537c478bd9Sstevel@tonic-gate     ti_exit_standout_mode ();
454a5602e1bSKeith M Wesolowski   composite_bitset = saved_cbs;
4557c478bd9Sstevel@tonic-gate   keep_track = 1;
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
458a5602e1bSKeith M Wesolowski void
composite_putchar(int c)459a5602e1bSKeith M Wesolowski composite_putchar (int c)
460a5602e1bSKeith M Wesolowski {
461a5602e1bSKeith M Wesolowski   if (composite_bitset & COMP_BS_SERIAL)
462a5602e1bSKeith M Wesolowski     serial_putchar (c);
463a5602e1bSKeith M Wesolowski   if (composite_bitset & COMP_BS_BIOS)
464a5602e1bSKeith M Wesolowski     console_putchar (c);
465a5602e1bSKeith M Wesolowski }
466a5602e1bSKeith M Wesolowski 
467a5602e1bSKeith M Wesolowski int
composite_getkey(void)468a5602e1bSKeith M Wesolowski composite_getkey (void)
469a5602e1bSKeith M Wesolowski {
470a5602e1bSKeith M Wesolowski   for (;;) {
471a5602e1bSKeith M Wesolowski     if (serial_checkkey () != -1)
472a5602e1bSKeith M Wesolowski       return (serial_getkey ());
473a5602e1bSKeith M Wesolowski     if (console_checkkey () != -1)
474a5602e1bSKeith M Wesolowski       return (console_getkey ());
475a5602e1bSKeith M Wesolowski   }
476a5602e1bSKeith M Wesolowski }
477a5602e1bSKeith M Wesolowski 
478a5602e1bSKeith M Wesolowski int
composite_checkkey(void)479a5602e1bSKeith M Wesolowski composite_checkkey (void)
480a5602e1bSKeith M Wesolowski {
481a5602e1bSKeith M Wesolowski   int ch;
482a5602e1bSKeith M Wesolowski 
483a5602e1bSKeith M Wesolowski   if ((ch = serial_checkkey ()) != -1)
484a5602e1bSKeith M Wesolowski     return (ch);
485a5602e1bSKeith M Wesolowski   return (console_checkkey ());
486a5602e1bSKeith M Wesolowski }
487a5602e1bSKeith M Wesolowski 
488a5602e1bSKeith M Wesolowski void
composite_gotoxy(int x,int y)489a5602e1bSKeith M Wesolowski composite_gotoxy (int x, int y)
490a5602e1bSKeith M Wesolowski {
491a5602e1bSKeith M Wesolowski   serial_gotoxy (x, y);
492a5602e1bSKeith M Wesolowski   console_gotoxy (x, y);
493a5602e1bSKeith M Wesolowski }
494a5602e1bSKeith M Wesolowski 
495a5602e1bSKeith M Wesolowski void
composite_cls(void)496a5602e1bSKeith M Wesolowski composite_cls (void)
497a5602e1bSKeith M Wesolowski {
498a5602e1bSKeith M Wesolowski   serial_cls();
499a5602e1bSKeith M Wesolowski   console_cls();
500a5602e1bSKeith M Wesolowski }
501a5602e1bSKeith M Wesolowski 
502a5602e1bSKeith M Wesolowski void
composite_setcolorstate(color_state state)503a5602e1bSKeith M Wesolowski composite_setcolorstate (color_state state)
504a5602e1bSKeith M Wesolowski {
505a5602e1bSKeith M Wesolowski   serial_setcolorstate (state);
506a5602e1bSKeith M Wesolowski   console_setcolorstate (state);
507a5602e1bSKeith M Wesolowski }
508a5602e1bSKeith M Wesolowski 
5097c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
510