]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libio-io/lib/src/io.cc
update
[l4.git] / l4 / pkg / libio-io / lib / src / io.cc
1 /*
2  * (c) 2008-2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
4  *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>,
5  *               Henning Schild <hschild@os.inf.tu-dresden.de>
6  *     economic rights: Technische Universität Dresden (Germany)
7  * This file is part of TUD:OS and distributed under the terms of the
8  * GNU Lesser General Public License 2.1.
9  * Please see the COPYING-LGPL-2.1 file for details.
10  */
11 #include <l4/cxx/exceptions>
12 #include <l4/cxx/iostream>
13 #include <l4/io/io.h>
14 #include <l4/vbus/vbus.h>
15 #include <l4/io/types.h>
16 #include <l4/re/namespace>
17 #include <l4/re/rm>
18 #include <l4/re/env>
19 #include <l4/re/error_helper>
20 #include <l4/re/util/cap_alloc>
21 #include <l4/sys/factory>
22 #include <l4/sys/icu>
23 #include <l4/sys/irq>
24 #include <l4/sys/task>
25 #include <l4/sys/kdebug.h>
26 #include <l4/util/splitlog2.h>
27 #include <l4/crtn/initpriorities.h>
28
29 #include <cstdio>
30 #include <cstdlib>
31 #include <cstring>
32
33 using L4::Cap;
34 using L4Re::Util::Auto_cap;
35
36 namespace {
37
38 /***********************************************************************
39  * Init
40  ***********************************************************************/
41 static Cap<void> &vbus()
42 {
43   static Cap<void> _vbus;
44   return _vbus;
45 }
46
47 static Cap<L4::Icu> &icu()
48 {
49   static Cap<L4::Icu> _icu;
50   return _icu;
51 }
52
53
54
55 extern "C" void __attribute__((__used__))
56 __internal_l4io_init()
57 {
58   try
59     {
60       L4::Cap<L4Re::Rm> rm = L4Re::Env::env()->rm();
61
62       vbus() = L4Re::Env::env()->get_cap<void>("vbus");
63       if (!vbus().is_valid())
64         {
65           printf("libio: Warning: Query of 'vbus' failed!\n");
66           return;
67         }
68
69       l4vbus_device_handle_t handle = 0;
70       int ret = l4vbus_get_device_by_hid(vbus().cap(), 0, &handle, "L40009",
71                                          L4VBUS_MAX_DEPTH, 0);
72       if (ret)
73         {
74           //printf("libio: Warning: Finding 'icu' in system bus failed with '%s'\n",
75           //       l4sys_errtostr(ret));
76           return;
77         }
78
79       icu() = L4Re::chkcap(L4Re::Util::cap_alloc.alloc<L4::Icu>(),
80           "allocating ICU cap");
81
82       ret = l4vbus_vicu_get_cap(vbus().cap(), handle, icu().cap());
83       if (ret)
84         {
85           printf("libio: Warning: Getting 'icu' device failed.\n");
86           L4Re::Util::cap_alloc.free(icu());
87           icu().invalidate();
88         }
89     }
90   catch (L4::Runtime_error const &e)
91     {
92       L4::cerr << e;
93       printf("Libio caught exception\n");
94       return;
95     }
96 }
97
98 L4_DECLARE_CONSTRUCTOR(__internal_l4io_init, INIT_PRIO_LIBIO_INIT);
99 }
100
101 /***********************************************************************
102  * IRQ
103  ***********************************************************************/
104
105 long
106 l4io_request_irq(int irqnum, l4_cap_idx_t irq_cap)
107 {
108   L4::Cap<L4::Irq> irq(irq_cap);
109   long ret = l4_error(L4Re::Env::env()->factory()->create_irq(irq));
110   if (ret < 0) {
111       printf("Create irq failed with %ld\n", ret);
112       return ret;
113   }
114
115   ret = l4_error(icu()->bind(irqnum, irq));
116   if (ret < 0) {
117       printf("Bind irq to icu failed with %ld\n", ret);
118       return ret;
119   }
120
121   return 0;
122 }
123
124 l4_cap_idx_t
125 l4io_request_icu()
126 { return icu().cap(); }
127
128 long
129 l4io_release_irq(int irqnum, l4_cap_idx_t irq_cap)
130 {
131   long ret = l4_error(icu()->unbind(irqnum, L4::Cap<L4::Irq>(irq_cap)));
132   if (ret) {
133       printf("Unbind irq %d from icu failed with %ld\n", irqnum, ret);
134       return -1;
135   }
136
137   l4_task_unmap(L4_BASE_TASK_CAP,
138                 l4_obj_fpage(irq_cap, 0, L4_FPAGE_RWX),
139                 L4_FP_ALL_SPACES);
140
141   return 0;
142 }
143
144 /***********************************************************************
145  * I/O memory
146  ***********************************************************************/
147
148 static long
149 __map_iomem(l4_addr_t phys, l4_addr_t* virt, unsigned long size, int flags)
150 {
151   Cap<L4Re::Dataspace> iomem = L4::cap_cast<L4Re::Dataspace>(vbus());
152   unsigned char align = L4_PAGESHIFT;
153
154   if (size >= L4_SUPERPAGESIZE)
155     align = L4_SUPERPAGESHIFT;
156
157   unsigned long rmflags = 0;
158
159   if (flags & L4IO_MEM_EAGER_MAP)
160     rmflags |= L4Re::Rm::Eager_map;
161
162   if (*virt && (flags & L4IO_MEM_USE_RESERVED_AREA))
163     rmflags |= L4Re::Rm::In_area;
164
165   if (!*virt)
166     rmflags |= L4Re::Rm::Search_addr;
167
168   int res = L4Re::Env::env()->rm()->attach(virt, size, rmflags, iomem, phys, align);
169   if (res)
170     {
171       printf("Cannot attach iomem to virtual address %lx with size %lx: %s(%d).\n",
172              *virt, size, l4sys_errtostr(res), res);
173       return -L4_ENOENT;
174     }
175
176   return 0;
177 }
178
179 long
180 l4io_request_iomem(l4_addr_t phys, unsigned long size,
181                    int flags, l4_addr_t *virt)
182 {
183   *virt = 0;
184   return __map_iomem(phys, virt, size, flags);
185 }
186
187 long
188 l4io_request_iomem_region(l4_addr_t phys, l4_addr_t virt, unsigned long size,
189                           int flags)
190 {
191   if (!virt)
192     return -L4_EADDRNOTAVAIL;
193   return __map_iomem(phys, &virt, size, flags);
194 }
195
196 long
197 l4io_release_iomem(l4_addr_t virt, unsigned long size)
198 {
199   (void)size;
200   return L4Re::Env::env()->rm()->detach(virt, 0);
201 }
202
203 long
204 l4io_search_iomem_region(l4_addr_t phys, l4_addr_t size,
205                          l4_addr_t *rstart, l4_addr_t *rsize)
206 {
207   *rstart = l4_trunc_page(phys);
208   *rsize  = l4_round_page(size + phys - *rstart);
209   return 0;
210 }
211
212 /***********************************************************************
213  * I/O ports
214  ***********************************************************************/
215
216 long
217 l4io_request_ioport(unsigned portnum, unsigned len)
218 {
219   l4vbus_resource_t res;
220   res.type = L4IO_RESOURCE_PORT;
221   res.start = portnum;
222   res.end = portnum + len - 1;
223   return l4vbus_request_resource(vbus().cap(), &res, 0);
224 }
225
226 long
227 l4io_release_ioport(unsigned portnum, unsigned len)
228 {
229   l4vbus_resource_t res;
230   res.type = L4IO_RESOURCE_PORT;
231   res.start = portnum;
232   res.end = portnum + len - 1;
233   return l4vbus_release_resource(vbus().cap(), &res);
234 }
235
236 /***********************************************************************
237  * General
238  ***********************************************************************/
239
240 int
241 l4io_iterate_devices(l4io_device_handle_t *devhandle,
242                      l4io_device_t *dev, l4io_resource_handle_t *reshandle)
243 {
244   if (reshandle)
245     *reshandle = 0;
246
247   return l4vbus_get_next_device(vbus().cap(), L4VBUS_NULL,
248                                 devhandle, L4VBUS_MAX_DEPTH, dev);
249 }
250
251 int
252 l4io_lookup_device(const char *devname,
253                    l4io_device_handle_t *dev_handle, l4io_device_t *dev,
254                    l4io_resource_handle_t *res_handle)
255 {
256   int r;
257   l4io_device_handle_t dh = 0;
258
259   if (!vbus().is_valid())
260     return -L4_ENOENT;
261
262   if ((r = l4vbus_get_device_by_hid(vbus().cap(), 0,
263                                     &dh, devname, L4VBUS_MAX_DEPTH, dev)))
264     return r;
265
266   if (dev_handle)
267     *dev_handle = dh;
268
269   if (res_handle)
270     *res_handle = 0;
271
272   return -L4_EOK;
273 }
274
275 int
276 l4io_lookup_resource(l4io_device_handle_t devhandle,
277                      enum l4io_resource_types_t type,
278                      l4io_resource_handle_t *res_handle,
279                      l4io_resource_t *desc)
280 {
281   l4vbus_resource_t resource;
282   while (!l4vbus_get_resource(vbus().cap(), devhandle, *res_handle, &resource))
283     {
284       ++(*res_handle);
285       // copy device description
286       if (resource.type == type || type == L4IO_RESOURCE_ANY)
287         {
288           *desc = resource;
289           return -L4_EOK;
290         }
291     }
292
293   return -L4_ENOENT;
294 }
295
296 l4_addr_t
297 l4io_request_resource_iomem(l4io_device_handle_t devhandle,
298                             l4io_resource_handle_t *reshandle)
299 {
300   l4io_resource_t res;
301   l4_addr_t v;
302
303   if (l4io_lookup_resource(devhandle, L4IO_RESOURCE_MEM,
304                            reshandle, &res))
305     return 0;
306
307   v = 0;
308   if (l4io_request_iomem(res.start, res.end - res.start + 1,
309                          L4IO_MEM_NONCACHED, &v))
310     return 0;
311
312   return v;
313 }
314
315 static
316 void __l4io_get_all_ports(l4vbus_device_handle_t parent)
317 {
318   l4vbus_device_handle_t next_dev = 0;
319   l4vbus_device_t info;
320
321   while (!l4vbus_get_next_device(vbus().cap(), parent, &next_dev,
322                                  L4VBUS_MAX_DEPTH, &info))
323     {
324       l4vbus_resource_t resource;
325       for (unsigned r = 0; r < info.num_resources; ++r)
326         {
327           l4vbus_get_resource(vbus().cap(), next_dev, r, &resource);
328           if (resource.type == L4IO_RESOURCE_PORT)
329             l4vbus_request_resource(vbus().cap(), &resource, 0);
330         }
331     }
332 }
333
334 void
335 l4io_request_all_ioports(void)
336 {
337   __l4io_get_all_ports(l4io_get_root_device());
338 }
339
340 int
341 l4io_has_resource(enum l4io_resource_types_t type,
342                   l4vbus_paddr_t start, l4vbus_paddr_t end)
343 {
344   l4io_device_handle_t dh = l4io_get_root_device();
345   l4io_device_t dev;
346   l4io_resource_handle_t reshandle;
347
348   while (1)
349     {
350       l4io_resource_t res;
351
352       if (l4io_iterate_devices(&dh, &dev, &reshandle))
353         break;
354
355       if (dev.num_resources)
356         while (!l4io_lookup_resource(dh, type, &reshandle, &res))
357           if (start >= res.start && end <= res.end)
358             return 1;
359     }
360   return 0;
361 }