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