]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/gdb_stub/serial_connection.cc
update
[l4.git] / l4 / pkg / plr / server / src / gdb_stub / serial_connection.cc
1 /*
2  * gdb_stub/serial_connection.cc --
3  *
4  *     Connectivity through serial interface
5  *
6  * (c) 2011-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
7  *     economic rights: Technische Universität Dresden (Germany)
8  * This file is part of TUD:OS and distributed under the terms of the
9  * GNU General Public License 2.
10  * Please see the COPYING-GPL-2 file for details.
11  */
12
13 #include "../log"
14 #include "gdbserver"
15 #include "connection"
16
17 #define MSG() DEBUGf(Romain::Log::Gdb)
18
19 #include <cstdio>
20 #include <cassert>
21 #include <termios.h>
22 #include <cstring>
23 #include <unistd.h>
24
25 #include <l4/sys/kdebug.h>
26 #include <l4/re/c/namespace.h>
27
28 #include <l4/vbus/vbus.h>
29 #include <l4/vbus/vbus_types.h>
30 #include <l4/vbus/vbus_pci.h>
31
32 #include <l4/util/port_io.h>
33 #include <l4/util/util.h>
34
35 /* guess where i stole that... */
36 static struct bootstrap_termios {
37         unsigned long c_iflag;
38         unsigned long c_oflag;
39         unsigned long c_cflag;
40         unsigned long c_lflag;
41         unsigned char c_cc[20];
42         long          c_ispeed;
43         long          c_ospeed;
44
45 } serial_termios =
46 {
47         0,            /* input flags */
48         OPOST,        /* output flags */
49         CS8,          /* control flags */
50         0,            /* local flags */
51         { 'D'-64,     /* VEOF */
52                 _POSIX_VDISABLE,    /* VEOL */
53                 0,  
54                 'H'-64,     /* VERASE */
55                 0,  
56                 'U'-64,     /* VKILL */
57                 0,  
58                 0,  
59                 'C'-64,     /* VINTR */
60                 '\\'-64,        /* VQUIT */
61                 'Z'-64,     /* VSUSP */
62                 0,  
63                 'Q'-64,     /* VSTART */
64                 'S'-64,     /* VSTOP */
65         },  
66         115200,       /* input speed */
67         115200,       /* output speed */
68 };
69
70
71 Uart_x86::Uart_x86()
72 : _base(~0UL)
73 {
74 }
75
76 bool Uart_x86::startup(unsigned long base)
77 {
78         unsigned char dfr;
79         unsigned divisor;
80
81         /* Determine what to plug in the data format register.  */
82         if (serial_termios.c_cflag & PARENB)
83                 if (serial_termios.c_cflag & PARODD)
84                         dfr = 0x08;
85                 else
86                         dfr = 0x18;
87         else
88                 dfr = 0x00;
89         if (serial_termios.c_cflag & CSTOPB)
90                 dfr |= 0x04;
91         switch (serial_termios.c_cflag & 0x00000300)
92         {
93                 case CS5: dfr |= 0x00; break;
94                 case CS6: dfr |= 0x01; break;
95                 case CS7: dfr |= 0x02; break;
96                 case CS8: dfr |= 0x03; break;
97         }
98
99         /* Convert the baud rate into a divisor latch value.  */
100         divisor = 115200 / serial_termios.c_ospeed;
101
102         /* Initialize the serial port.  */
103         l4util_out8(0x80 | dfr,     _base + 3); /* DLAB = 1 */
104         l4util_out8(divisor & 0xff, _base + 0);
105         l4util_out8(divisor >> 8,   _base + 1);
106         l4util_out8(0x03 | dfr,     _base + 3); /* DLAB = 0, frame = 8N1 */
107         l4util_out8(0x00,           _base + 1); /* no interrupts enabled */
108         l4util_out8(0x0b,           _base + 4); /* OUT2, RTS, and DTR enabled */
109
110         l4util_out8(0x41, _base + 2);  /* 4 byte trigger + on */
111
112         /* Clear all serial interrupts.  */
113         l4util_in8(_base + 6);  /* ID 0: read RS-232 status register */
114         l4util_in8(_base + 2);  /* ID 1: read interrupt identification reg */
115         l4util_in8(_base + 0);  /* ID 2: read receive buffer register */
116         l4util_in8(_base + 5);  /* ID 3: read serialization status reg */
117
118         _base = base;
119
120         write_uart("hello\n", 6);
121
122         return true;
123 }
124
125 void Uart_x86::shutdown_uart() { }
126
127 int Uart_x86::get_char(bool blocking) const
128 {
129         int c = -1;
130
131         if (!_base) { // base == 0 -> not started up yet
132                 enter_kdebug("!!");
133                 return c;
134         }
135
136         if (!blocking)
137                 enter_kdebug("!blocking");
138
139         if (blocking) {
140                 while (!char_avail()) {
141                         l4_sleep(10);
142                 }
143                 c = l4util_in8(_base);
144         } else {
145                 if (char_avail()) {
146                         c = l4util_in8(_base);
147                 }
148         }
149
150         return c;
151 }
152
153
154 int Uart_x86::char_avail() const
155 {
156         return !!(l4util_in8(_base + 5) & 0x01);
157 }
158
159 void Uart_x86::out_char(char c) const
160 {
161         if (!_base) { // base == 0 -> not started up yet
162                 enter_kdebug("!!");
163                 return;
164         }
165
166         // poll until last char sent
167         while (!(l4util_in8(_base + 5) & 0x20))
168                 ;
169
170         l4util_out8(c, _base);
171 }
172
173 int Uart_x86::write_uart(char const *s, unsigned long count) const
174 {
175         unsigned long c = count;
176
177         while (c) 
178         {   
179                 if (*s == 10) 
180                         out_char(13);
181                 out_char(*s++);
182                 --c;
183         }   
184         return count;
185 }
186
187
188 void Romain::SerialConnection::get_vbus_resources()
189 {
190         l4vbus_device_handle_t dev     = 0;
191         l4vbus_device_t        devinfo;
192         l4_cap_idx_t           vbus    = l4re_env_get_cap("vbus");
193         l4vbus_resource_t      res;
194         int                    err;
195
196         err = l4vbus_get_device_by_hid(vbus, 0, &dev, "PNP0600", 0, &devinfo);
197         assert(err == 0);
198         assert(devinfo.num_resources == 1);
199
200         err = l4vbus_get_resource(vbus, dev, 0, &res);
201         assert(err == 0);
202
203         err = l4vbus_request_resource(vbus, &res, 0);
204         assert(err == 0);
205
206         if (res.type == L4VBUS_RESOURCE_PORT) {
207                 _uart.startup(res.start);
208         } else {
209                 enter_kdebug("resource not a port!?");
210         }
211 }
212
213
214
215 void Romain::SerialConnection::setup_and_wait()
216 {
217         // wait until we see the first character on the serial line
218         while (!_uart.char_avail())
219                 ;
220 }
221
222 void Romain::SerialConnection::disconnect()
223 {
224 }
225
226
227 int Romain::SerialConnection::wait_for_cmd(char * const buf, unsigned bufsize)
228 {
229         buf[0] = _uart.get_char();
230         //MSG() << "next packet start: " << buf[0] << "(" << std::hex << (unsigned)buf[0] << ")";
231         switch(buf[0]) {
232                 case GDBInterrupt:
233                 case GDBAck:
234                 case GDBRetry:
235                         return 1;
236
237                 case GDBCmdStart:
238                         break;
239
240                 default:
241                         ERROR() << "Unknown cmd start? '" << buf[0] << "'";
242                         break;
243         }
244
245         unsigned idx = 1;
246         while (idx < bufsize-2) {
247                 buf[idx] = _uart.get_char();
248                 //MSG() << buf[idx];
249                 if (buf[idx] == '#') {
250                         buf[idx+1] = _uart.get_char();
251                         buf[idx+2] = _uart.get_char();
252                         break;
253                 }
254                 ++idx;
255                 //l4_sleep(1); // XXX sleep synchronization is evil. why does this not work without?
256         }
257
258         if (idx >= bufsize) {
259                 ERROR() << "Overflow in cmd buffer: " << buf;
260                 return -1;
261         }
262
263         //Romain::dump_mem(buf, 40);
264         return bufsize;
265 }
266
267 int Romain::SerialConnection::senddata(char const * const buf, unsigned bufsize)
268 {
269         MSG() << buf;
270         return _uart.write_uart(buf, bufsize);
271 }