]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap/server/src/ARCH-x86/serial.cc
update
[l4.git] / l4 / pkg / bootstrap / server / src / ARCH-x86 / serial.cc
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 #include "koptions-def.h"
18
19 static int ser_io_base;
20
21
22 struct bootstrap_termios {
23   unsigned long c_iflag;
24   unsigned long c_oflag;
25   unsigned long c_cflag;
26   unsigned long c_lflag;
27   unsigned char c_cc[20];
28   long          c_ispeed;
29   long          c_ospeed;
30
31 } serial_termios =
32 {
33   0,                    /* input flags */
34   OPOST,                /* output flags */
35   CS8,                  /* control flags */
36   0,                    /* local flags */
37   {     'D'-64,         /* VEOF */
38     _POSIX_VDISABLE,    /* VEOL */
39     0,
40     'H'-64,             /* VERASE */
41     0,
42     'U'-64,             /* VKILL */
43     0,
44     0,
45     'C'-64,             /* VINTR */
46     '\\'-64,            /* VQUIT */
47     'Z'-64,             /* VSUSP */
48     0,
49     'Q'-64,             /* VSTART */
50     'S'-64,             /* VSTOP */
51   },
52   115200,               /* input speed */
53   115200,               /* output speed */
54 };
55
56 void
57 com_cons_putchar(int ch)
58 {
59   base_critical_enter();
60
61   if (ser_io_base == 0)
62     {
63       base_critical_leave();
64       return;
65     }
66
67   if (serial_termios.c_oflag & OPOST)
68     if (ch == '\n')
69       com_cons_putchar('\r');
70
71   /* Wait for the transmit buffer to become available.  */
72   while (!(l4util_in8(ser_io_base + 5) & 0x20));
73
74   l4util_out8(ch, ser_io_base + 0);
75
76   base_critical_leave();
77 }
78
79 int
80 com_cons_char_avail(void)
81 {
82   return !!(l4util_in8(ser_io_base + 5) & 0x01);
83 }
84
85 int
86 com_cons_try_getchar(void)
87 {
88   int ch = -1;
89
90   base_critical_enter();
91
92   if (ser_io_base == 0) 
93     {
94       base_critical_leave();
95       return -1;
96     }
97
98   /* character available?  */
99   if (com_cons_char_avail()) {
100       /* Grab it.  */
101       ch = l4util_in8(ser_io_base + 0);
102   }
103
104   base_critical_leave();
105   return ch;
106 }
107
108 static int
109 have_serial(unsigned port_base)
110 {
111   unsigned char scratch, scratch2, scratch3;
112
113   scratch = l4util_in8(port_base + 1);
114   l4util_out8(0, port_base + 1);
115
116   l4util_iodelay();
117
118   scratch2 = l4util_in8(port_base + 1);
119   l4util_out8(0x0f, port_base + 1);
120
121   l4util_iodelay();
122
123   scratch3 = l4util_in8(port_base + 1);
124   l4util_out8(scratch, port_base + 1);
125
126   if (scratch2 || scratch3 != 0x0f)
127     return 0;
128
129   return 1;
130 }
131
132 int
133 com_cons_init(int com_port_or_base,
134               int com_irq, L4_kernel_options::Uart *kuart,
135               unsigned int *kuart_flags)
136 {
137   unsigned char dfr;
138   unsigned divisor;
139
140   base_critical_enter();
141
142   switch (com_port_or_base)
143     {
144     case 1: com_port_or_base = 0x3f8;
145             if (com_irq == -1)
146               com_irq = 4;
147             break;
148     case 2: com_port_or_base = 0x2f8;
149             if (com_irq == -1)
150               com_irq = 3;
151             break;
152     case 3: com_port_or_base = 0x3e8; break;
153     case 4: com_port_or_base = 0x2e8; break;
154     }
155
156   if (!have_serial(com_port_or_base))
157     {
158       base_critical_leave();
159       return 1;
160     }
161
162   ser_io_base = com_port_or_base;
163
164   kuart->access_type  = L4_kernel_options::Uart_type_ioport;
165   kuart->irqno        = com_irq;
166   kuart->base_address = com_port_or_base;
167   kuart->baud         = 115200;
168   *kuart_flags       |=   L4_kernel_options::F_uart_base
169                         | L4_kernel_options::F_uart_baud;
170   if (com_irq != -1)
171     *kuart_flags |= L4_kernel_options::F_uart_irq;
172
173   /* Determine what to plug in the data format register.  */
174   if (serial_termios.c_cflag & PARENB)
175     if (serial_termios.c_cflag & PARODD)
176       dfr = 0x08;
177     else
178       dfr = 0x18;
179   else
180     dfr = 0x00;
181   if (serial_termios.c_cflag & CSTOPB)
182     dfr |= 0x04;
183   switch (serial_termios.c_cflag & 0x00000300)
184     {
185     case CS5: dfr |= 0x00; break;
186     case CS6: dfr |= 0x01; break;
187     case CS7: dfr |= 0x02; break;
188     case CS8: dfr |= 0x03; break;
189     }
190
191   /* Convert the baud rate into a divisor latch value.  */
192   divisor = 115200 / serial_termios.c_ospeed;
193
194   /* Initialize the serial port.  */
195   l4util_out8(0x80 | dfr,     ser_io_base + 3); /* DLAB = 1 */
196   l4util_out8(divisor & 0xff, ser_io_base + 0);
197   l4util_out8(divisor >> 8,   ser_io_base + 1);
198   l4util_out8(0x03 | dfr,     ser_io_base + 3); /* DLAB = 0, frame = 8N1 */
199   l4util_out8(0x00,           ser_io_base + 1); /* no interrupts enabled */
200   l4util_out8(0x0b,           ser_io_base + 4); /* OUT2, RTS, and DTR enabled */
201
202   l4util_out8(0x41, ser_io_base + 2);  /* 4 byte trigger + on */
203
204   /* Clear all serial interrupts.  */
205   l4util_in8(ser_io_base + 6);  /* ID 0: read RS-232 status register */
206   l4util_in8(ser_io_base + 2);  /* ID 1: read interrupt identification reg */
207   l4util_in8(ser_io_base + 0);  /* ID 2: read receive buffer register */
208   l4util_in8(ser_io_base + 5);  /* ID 3: read serialization status reg */
209
210   base_critical_leave();
211
212   return 0;
213 }