]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/vgpio.cc
update
[l4.git] / l4 / pkg / io / server / src / vgpio.cc
1 /*
2  * (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9
10
11 #include "debug.h"
12 #include "gpio"
13 #include "hw_device.h"
14 #include "vdevice.h"
15 #include "vbus_factory.h"
16 #include "vbus.h"
17 #include "vicu.h"
18
19 #include <vector>
20
21 #include <l4/vbus/vbus_gpio-ops.h>
22
23 #include <cerrno>
24
25
26 namespace Vi {
27 namespace {
28
29 class Gpio : public Device, public Dev_feature
30 {
31 public:
32   int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios);
33
34   explicit Gpio(Hw::Device *d)
35     : _hwd(dynamic_cast<Hw::Gpio_chip*>(d)), _mask(0)
36   {
37     add_feature(this);
38
39     for (unsigned i = 0; i < Max_pins; ++i)
40       _irqs[i] = -1;
41   }
42
43   int add_filter(cxx::String const &tag, cxx::String const &)
44   {
45     if (tag != "pins")
46       return -L4_ENODEV;
47     return -L4_EINVAL;
48   }
49
50   int add_filter(cxx::String const &tag, unsigned long long val)
51   {
52     if (tag != "pins")
53       return -L4_ENODEV;
54     _mask |= (1UL << val);
55     return 0;
56   }
57
58   int add_filter(cxx::String const &tag, unsigned long long s, unsigned long long e)
59   {
60     if (tag != "pins")
61       return -L4_ENODEV;
62     _mask |= ~(~0UL << (e - s + 1)) << s;
63     return 0;
64   }
65
66   void modify_mask(l4_uint32_t enable, l4_uint32_t disable)
67   {
68     _mask = (_mask & ~disable) | enable;
69   }
70
71   char const *hid() const { return "GPIO"; }
72   void set_host(Device *d) { _host = d; }
73   Device *host() const { return _host; }
74
75   bool match_hw_feature(const Hw::Dev_feature*) const
76   { return false; }
77
78 private:
79   enum { Max_pins = 32 };
80   Device *_host;
81   Hw::Gpio_chip *_hwd;
82   l4_uint32_t _mask;
83
84   int _irqs[Max_pins];
85
86   int setup(L4::Ipc::Iostream &ios);
87   int config_pad(L4::Ipc::Iostream &ios);
88   int config_get(L4::Ipc::Iostream &ios);
89   int get(L4::Ipc::Iostream &ios);
90   int set(L4::Ipc::Iostream &ios);
91   int multi_setup(L4::Ipc::Iostream &ios);
92   int multi_config_pad(L4::Ipc::Iostream &ios);
93   int multi_get(L4::Ipc::Iostream &ios);
94   int multi_set(L4::Ipc::Iostream &ios);
95   int to_irq(L4::Ipc::Iostream &ios);
96
97   void check(unsigned pin)
98   {
99     if (pin > 31)
100       throw -L4_ERANGE;
101
102     if (!((1UL << pin) & _mask))
103       throw -L4_ERANGE;
104   }
105
106   void check_mask(unsigned mask)
107   {
108     if (mask & ~_mask)
109       throw -L4_ERANGE;
110   }
111 };
112
113
114
115 int
116 Gpio::setup(L4::Ipc::Iostream &ios)
117 {
118   unsigned pin, mode;
119   int value;
120   ios >> pin >> mode >> value;
121   check(pin);
122   _hwd->setup(pin, mode, value);
123   return 0;
124 }
125
126 int
127 Gpio::config_pad(L4::Ipc::Iostream &ios)
128 {
129   unsigned pin, func, value;
130   ios >> pin >> func >> value;
131   check(pin);
132   _hwd->config_pad(pin, _mask, func, value);
133   return 0;
134 }
135
136 int
137 Gpio::config_get(L4::Ipc::Iostream &ios)
138 {
139   unsigned pin, func, value;
140   ios >> pin >> func;
141   check(pin);
142   _hwd->config_get(pin, _mask, func, &value);
143   ios << value;
144   return 0;
145 }
146
147 int
148 Gpio::get(L4::Ipc::Iostream &ios)
149 {
150   unsigned pin;
151   ios >> pin;
152   check(pin);
153   return _hwd->get(pin);
154 }
155
156 int
157 Gpio::set(L4::Ipc::Iostream &ios)
158 {
159   unsigned pin;
160   int value;
161   ios >> pin >> value;
162   check(pin);
163   _hwd->set(pin, value);
164   return 0;
165 }
166
167 int
168 Gpio::multi_setup(L4::Ipc::Iostream &ios)
169 {
170   unsigned mask, mode, outvalue;
171   ios >> mask >> mode >> outvalue;
172   check_mask(mask);
173   _hwd->multi_setup(mask, mode, outvalue);
174   return 0;
175 }
176
177 int
178 Gpio::multi_config_pad(L4::Ipc::Iostream &ios)
179 {
180   unsigned mask, func, value;
181   ios >> mask >> func >> value;
182   check_mask(mask);
183   _hwd->multi_config_pad(mask, func, value);
184   return 0;
185 }
186
187 int
188 Gpio::multi_get(L4::Ipc::Iostream &ios)
189 {
190   unsigned data = _hwd->multi_get();
191   ios << (unsigned)(data & _mask);
192   return 0;
193 }
194
195 int
196 Gpio::multi_set(L4::Ipc::Iostream &ios)
197 {
198   unsigned mask, data;
199   ios >> mask >> data;
200   check_mask(mask);
201   _hwd->multi_set(mask, data);
202   return 0;
203 }
204
205 int
206 Gpio::to_irq(L4::Ipc::Iostream &ios)
207 {
208   unsigned pin;
209   ios >> pin;
210   check(pin);
211
212   if (_irqs[pin] == -1)
213     {
214       // we have to allocate the IRQ...
215       // if it fails we mark the IRQ as unavailable (-L4_ENODEV)
216       _irqs[pin] = -L4_ENODEV;
217
218       int irqnum = _hwd->get_irq(pin);
219       if (irqnum < 0)
220         return irqnum;
221
222       if (System_bus *sb = dynamic_cast<System_bus *>(get_root()))
223         {
224           int virq = sb->sw_icu()->alloc_irq(Sw_icu::S_allow_set_mode,
225                                              Sw_icu::real_irq(irqnum));
226           if (virq < 0)
227             return virq;
228
229           _irqs[pin] = virq;
230           return virq;
231         }
232       return -L4_ENODEV;
233     }
234   return _irqs[pin];
235 }
236
237 int
238 Gpio::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
239 {
240   try
241     {
242       switch (func)
243         {
244         case L4VBUS_GPIO_OP_SETUP: return setup(ios);
245         case L4VBUS_GPIO_OP_CONFIG_PAD: return config_pad(ios);
246         case L4VBUS_GPIO_OP_CONFIG_GET: return config_get(ios);
247         case L4VBUS_GPIO_OP_GET: return get(ios);
248         case L4VBUS_GPIO_OP_SET: return set(ios);
249         case L4VBUS_GPIO_OP_MULTI_SETUP: return multi_setup(ios);
250         case L4VBUS_GPIO_OP_MULTI_CONFIG_PAD: return multi_config_pad(ios);
251         case L4VBUS_GPIO_OP_MULTI_GET: return multi_get(ios);
252         case L4VBUS_GPIO_OP_MULTI_SET: return multi_set(ios);
253         case L4VBUS_GPIO_OP_TO_IRQ: return to_irq(ios);
254         default: return -L4_ENOSYS;
255         }
256     }
257   catch (int err)
258     {
259       return err;
260     }
261 }
262
263
264 static Dev_factory_t<Gpio, Hw::Gpio_device> __gpio_factory;
265
266 class Gpio_resource : public Resource
267 {
268 public:
269   explicit Gpio_resource(::Gpio_resource *hr)
270   : Resource(hr->flags(), hr->start(), hr->end()), _hwr(hr) {}
271 private:
272   ::Gpio_resource *_hwr;
273 };
274
275 class Root_gpio_rs : public Resource_space
276 {
277 public:
278   explicit Root_gpio_rs(System_bus *bus) : _bus(bus)
279   {}
280
281   bool request(Resource *parent, ::Device *pdev, Resource *child, ::Device *)
282   {
283     Vi::System_bus *vsb = dynamic_cast<Vi::System_bus *>(pdev);
284     if (!vsb || !parent)
285       return false;
286
287     ::Gpio_resource *r = dynamic_cast< ::Gpio_resource*>(child);
288     if (!r)
289       return false;
290
291     Hw::Gpio_device *gpio = r->provider();
292
293     Vi::Device *vbus = vsb;
294
295     for (Hw::Device *bus = system_bus(); bus != gpio; )
296       {
297         Hw::Device *d = gpio;
298         while (d->parent() != bus)
299           d = d->parent();
300
301         bus = d;
302         //printf("BUS: %p:%s\n", bus, bus->name());
303
304         Vi::Device *vd = vbus->find_by_name(bus->name());
305         if (!vd)
306           {
307             if (bus != gpio)
308               vd = new Vi::Device();
309             else
310               vd = new Gpio(gpio);
311
312             vd->name(bus->name());
313             vbus->add_child(vd);
314           }
315         // printf("VDEV=%p:%s\n", vd, vd ? vd->name() : "");
316         vbus = vd;
317       }
318
319     Gpio *vgpio = dynamic_cast<Gpio *>(vbus);
320
321     if (!vgpio)
322       {
323         d_printf(DBG_ERR, "ERROR: device: %s is not a GPIO device\n", vbus->name());
324         return false;
325       }
326
327     d_printf(DBG_DEBUG2, "Add GPIO resource to vbus: ");
328     if (dlevel(DBG_DEBUG2))
329       child->dump();
330
331
332       {
333         unsigned e = r->end() + 1;
334         unsigned s = r->start();
335         if (e > 31) e = 31;
336         if (s > 31) s = 31;
337         l4_uint32_t mask = ((1UL << (e - s)) - 1) << s;
338         vgpio->modify_mask(mask, 0);
339       }
340
341     return true;
342   }
343
344   bool alloc(Resource *parent, ::Device *, Resource *child, ::Device *, bool)
345   {
346     d_printf(DBG_DEBUG2, "Allocate virtual GPIO resource ...\n");
347     if (dlevel(DBG_DEBUG2))
348       child->dump();
349
350     if (!parent)
351       return false;
352     return false;
353   }
354
355
356 private:
357   Root_gpio_rs(Root_gpio_rs const &);
358   void operator = (Root_gpio_rs const &);
359
360   System_bus *_bus;
361   std::vector<Gpio *> _gpios;
362 };
363
364 static System_bus::Root_resource_factory_t<Resource::Gpio_res, Root_gpio_rs> __rf;
365
366 }
367 }