]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap/server/src/ARCH-x86/serial.c
2bdb82992aed895f6f8143b84c16e70a04a3809a
[l4.git] / l4 / pkg / bootstrap / server / src / ARCH-x86 / serial.c
1 /*
2  * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *          Alexander Warg <warg@os.inf.tu-dresden.de>,
4  *          Frank Mehnert <fm3@os.inf.tu-dresden.de>
5  *     economic rights: Technische Universität Dresden (Germany)
6  *
7  * This file is part of TUD:OS and distributed under the terms of the
8  * GNU General Public License 2.
9  * Please see the COPYING-GPL-2 file for details.
10  */
11
12 #include <termios.h>
13 #include <unistd.h>
14 #include <l4/util/port_io.h>
15 #include "base_critical.h"
16 #include "serial.h"
17
18 static int ser_io_base;
19
20
21 struct bootstrap_termios {
22   unsigned long c_iflag;
23   unsigned long c_oflag;
24   unsigned long c_cflag;
25   unsigned long c_lflag;
26   unsigned char c_cc[20];
27   long          c_ispeed;
28   long          c_ospeed;
29
30 } serial_termios =
31 {
32   0,                    /* input flags */
33   OPOST,                /* output flags */
34   CS8,                  /* control flags */
35   0,                    /* local flags */
36   {     'D'-64,         /* VEOF */
37     _POSIX_VDISABLE,    /* VEOL */
38     0,
39     'H'-64,             /* VERASE */
40     0,
41     'U'-64,             /* VKILL */
42     0,
43     0,
44     'C'-64,             /* VINTR */
45     '\\'-64,            /* VQUIT */
46     'Z'-64,             /* VSUSP */
47     0,
48     'Q'-64,             /* VSTART */
49     'S'-64,             /* VSTOP */
50   },
51   115200,               /* input speed */
52   115200,               /* output speed */
53 };
54
55 void
56 com_cons_putchar(int ch)
57 {
58   base_critical_enter();
59
60   if (ser_io_base == 0) 
61     {
62       base_critical_leave();
63       return;
64     }
65
66   if (serial_termios.c_oflag & OPOST)
67     if (ch == '\n')
68       com_cons_putchar('\r');
69
70   /* Wait for the transmit buffer to become available.  */
71   while (!(l4util_in8(ser_io_base + 5) & 0x20));
72
73   l4util_out8(ch, ser_io_base + 0);
74
75   base_critical_leave();
76 }
77
78 int
79 com_cons_char_avail(void)
80 {
81   return !!(l4util_in8(ser_io_base + 5) & 0x01);
82 }
83
84 int
85 com_cons_try_getchar(void)
86 {
87   int ch = -1;
88
89   base_critical_enter();
90
91   if (ser_io_base == 0) 
92     {
93       base_critical_leave();
94       return -1;
95     }
96
97   /* character available?  */
98   if (com_cons_char_avail()) {
99       /* Grab it.  */
100       ch = l4util_in8(ser_io_base + 0);
101   }
102
103   base_critical_leave();
104   return ch;
105 }
106
107 static int
108 have_serial(unsigned port_base)
109 {
110   unsigned char scratch, scratch2, scratch3;
111
112   scratch = l4util_in8(port_base + 1);
113   l4util_out8(0, port_base + 1);
114
115   l4util_iodelay();
116
117   scratch2 = l4util_in8(port_base + 1);
118   l4util_out8(0x0f, port_base + 1);
119
120   l4util_iodelay();
121
122   scratch3 = l4util_in8(port_base + 1);
123   l4util_out8(scratch, port_base + 1);
124
125   if (scratch2 || scratch3 != 0x0f)
126     return 0;
127
128   return 1;
129 }
130
131 int
132 com_cons_init(int com_port_or_base)
133 {
134   unsigned char dfr;
135   unsigned divisor;
136
137   base_critical_enter();
138
139   switch (com_port_or_base)
140     {
141     case 1: com_port_or_base = 0x3f8; break;
142     case 2: com_port_or_base = 0x2f8; break;
143     case 3: com_port_or_base = 0x3e8; break;
144     case 4: com_port_or_base = 0x2e8; break;
145     }
146
147   /* Silently fail if serial port is not available */
148   if (!have_serial(com_port_or_base))
149     {
150       base_critical_leave();
151       return 1;
152     }
153
154   ser_io_base = com_port_or_base;
155
156   /* Determine what to plug in the data format register.  */
157   if (serial_termios.c_cflag & PARENB)
158     if (serial_termios.c_cflag & PARODD)
159       dfr = 0x08;
160     else
161       dfr = 0x18;
162   else
163     dfr = 0x00;
164   if (serial_termios.c_cflag & CSTOPB)
165     dfr |= 0x04;
166   switch (serial_termios.c_cflag & 0x00000300)
167     {
168     case CS5: dfr |= 0x00; break;
169     case CS6: dfr |= 0x01; break;
170     case CS7: dfr |= 0x02; break;
171     case CS8: dfr |= 0x03; break;
172     }
173
174   /* Convert the baud rate into a divisor latch value.  */
175   divisor = 115200 / serial_termios.c_ospeed;
176
177   /* Initialize the serial port.  */
178   l4util_out8(0x80 | dfr,     ser_io_base + 3); /* DLAB = 1 */
179   l4util_out8(divisor & 0xff, ser_io_base + 0);
180   l4util_out8(divisor >> 8,   ser_io_base + 1);
181   l4util_out8(0x03 | dfr,     ser_io_base + 3); /* DLAB = 0, frame = 8N1 */
182   l4util_out8(0x00,           ser_io_base + 1); /* no interrupts enabled */
183   l4util_out8(0x0b,           ser_io_base + 4); /* OUT2, RTS, and DTR enabled */
184
185   l4util_out8(0x41, ser_io_base + 2);  /* 4 byte trigger + on */
186
187   /* Clear all serial interrupts.  */
188   l4util_in8(ser_io_base + 6);  /* ID 0: read RS-232 status register */
189   l4util_in8(ser_io_base + 2);  /* ID 1: read interrupt identification reg */
190   l4util_in8(ser_io_base + 0);  /* ID 2: read receive buffer register */
191   l4util_in8(ser_io_base + 5);  /* ID 3: read serialization status reg */
192
193   base_critical_leave();
194
195   return 0;
196 }