]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/serial-drv/server/src/main.cc
c8fc346540688fc47204e7298c21787483d5c379
[l4.git] / l4 / pkg / serial-drv / server / src / main.cc
1 /*
2  * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>,
3  *          Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #include <l4/drivers/uart_pl011.h>
11 #include <l4/drivers/uart_omap35x.h>
12 #include <l4/io/io.h>
13 #include <l4/re/env>
14 #include <l4/re/error_helper>
15 #include <l4/re/namespace>
16 #include <l4/re/util/cap_alloc>
17 #include <l4/re/util/object_registry>
18 #include <l4/re/util/icu_svr>
19 #include <l4/re/util/vcon_svr>
20 #include <l4/sys/irq>
21 #include <l4/util/util.h>
22
23 #include <cstdlib>
24 #include <cstdio>
25
26
27 static L4::Cap<void> srv_rcv_cap;
28
29 class Loop_hooks :
30   public L4::Ipc_svr::Ignore_errors,
31   public L4::Ipc_svr::Default_timeout,
32   public L4::Ipc_svr::Compound_reply
33 {
34 public:
35   void setup_wait(L4::Ipc_istream &istr, bool)
36   {
37     istr.reset();
38     istr << L4::Small_buf(srv_rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
39     l4_utcb_br_u(istr.utcb())->bdr = 0;
40   }
41 };
42
43 using L4Re::Env;
44 using L4Re::Util::Registry_server;
45
46 static Registry_server<Loop_hooks> server(l4_utcb(),
47                                           Env::env()->main_thread(),
48                                           Env::env()->factory());
49
50 using L4Re::Util::Vcon_svr;
51 using L4Re::Util::Icu_cap_array_svr;
52
53 class Serial_drv :
54   public Vcon_svr<Serial_drv>,
55   public Icu_cap_array_svr<Serial_drv>,
56   public L4::Server_object
57 {
58 public:
59   Serial_drv();
60   virtual ~Serial_drv() throw() {}
61   
62   bool running() const { return _running; }
63
64   int vcon_write(const char *buffer, unsigned size);
65   int vcon_read(char *buffer, unsigned size);
66   bool vcon_end();
67   
68   L4::Cap<void> rcv_cap() { return srv_rcv_cap; }
69
70   int handle_irq();
71   
72   bool init();
73   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
74
75 private:
76   bool _running;
77   L4::Uart *_uart;
78   L4::Cap<L4::Irq> _uart_irq;
79   Icu_cap_array_svr<Serial_drv>::Irq _irq;
80 };
81
82 Serial_drv::Serial_drv()
83   : Icu_cap_array_svr<Serial_drv>(1, &_irq),
84     _running(false), _uart(0), _uart_irq(L4_INVALID_CAP),
85     _irq()
86 {
87   if (init())
88     _running = true;
89 }
90
91 int
92 Serial_drv::vcon_write(const char *buffer, unsigned size)
93 {
94   _uart->write(buffer, size);
95   return L4_EOK;
96 }
97
98 int
99 Serial_drv::vcon_read(char *buffer, unsigned size)
100 {
101   int i = 0;
102   while (_uart->char_avail() && size)
103     {
104       int c = _uart->get_char(false);
105       if (c >= 0)
106         {
107           buffer[i++] = (char)c;
108           size--;
109         }
110       else
111         break;
112     }
113   // if there still some data available send this info to the client
114   if (_uart->char_avail())
115     i++;
116   else
117     _uart_irq->unmask();
118   return i;
119 }
120
121 bool
122 Serial_drv::vcon_end()
123 {
124   return !_uart->char_avail();
125 }
126
127
128 int
129 Serial_drv::handle_irq()
130 {
131   if (_irq.cap().is_valid())
132     _irq.cap()->trigger();
133
134   //_uart_irq->unmask();
135
136   return L4_EOK;
137 }
138
139 bool
140 Serial_drv::init()
141 {
142   int irq_num = 37;
143   l4_addr_t phys_base = 0x1000a000;
144 #if 0
145   int irq_num = 74;
146   l4_addr_t phys_base = 0x49020000;
147 #endif
148   l4_addr_t virt_base = 0;
149
150   if (l4io_request_iomem(phys_base, 0x1000, L4IO_MEM_NONCACHED, &virt_base))
151     {
152       printf("serial-drv: request io-memory from l4io failed.\n");
153       return false;
154     }
155   printf("serial-drv: virtual base at:%lx\n", virt_base);
156
157   _uart = new (malloc(sizeof(L4::Uart_pl011))) L4::Uart_pl011(irq_num, irq_num);
158   //_uart = new (malloc(sizeof(L4::Uart_omap35x))) L4::Uart_omap35x(irq_num, irq_num);
159   _uart->startup(virt_base);
160
161   _uart_irq = L4Re::Util::cap_alloc.alloc<L4::Irq>();
162   if (!_uart_irq.is_valid())
163     {
164       printf("serial-drv: Alloc capability for uart-irq failed.\n");
165       return false;
166     }
167
168   if (l4io_request_irq(irq_num, _uart_irq.cap()))
169     {
170       printf("serial-drv: request uart-irq from l4io failed\n");
171       return false;
172     }
173
174   /* setting IRQ type to L4_IRQ_F_POS_EDGE seems to be wrong place */
175   if (l4_error(_uart_irq->attach((l4_umword_t)static_cast<L4::Server_object *>(this),
176           L4Re::Env::env()->main_thread())))
177     {
178       printf("serial-drv: attach to uart-irq failed.\n");
179       return false;
180     }
181
182   if ((l4_ipc_error(_uart_irq->unmask(), l4_utcb())))
183     {
184       printf("serial-drv: unmask uart-irq failed.\n");
185       return false;
186     }
187   _uart->enable_rx_irq(true);
188
189   srv_rcv_cap = L4Re::Util::cap_alloc.alloc<void>();
190   if (!srv_rcv_cap.is_valid())
191     {
192       printf("serial-drv: Alloc capability for rcv-cap failed.\\n");
193       return false;
194     }
195   
196   return true;
197 }
198
199 int
200 Serial_drv::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
201 {
202   l4_msgtag_t tag;
203   ios >> tag;
204   switch (tag.label())
205     {
206     case L4_PROTO_IRQ:
207       if (!L4Re::Util::Icu_svr<Serial_drv>::dispatch(obj, ios))
208         return handle_irq();
209     case L4_PROTO_LOG:
210       return L4Re::Util::Vcon_svr<Serial_drv>::dispatch(obj, ios);
211     default:
212       return -L4_EBADPROTO;
213     }
214 }
215
216 int main()
217 {
218   Serial_drv serial_drv;
219
220   if (!server.registry()->register_obj(&serial_drv, "vcon"))
221     {
222       printf("Failed to register serial driver; Aborting.\n");
223       return 1;
224     }
225
226   if (!serial_drv.running())
227     {
228       printf("Failed to initialize serial driver; Aborting.\n");
229       return 1;
230     }
231
232   printf("Starting server loop\n");
233   server.loop();
234
235   return 0;
236 }