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