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