]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/vgpio.cc
53e3a9675c1ee125fd4cda848e54703b0856fa53
[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 "gpio"
12 #include "hw_device.h"
13 #include "vdevice.h"
14 #include "vbus_factory.h"
15 #include "vbus.h"
16 #include "vicu.h"
17
18 #include <l4/vbus/vbus_gpio-ops.h>
19
20 #include <cerrno>
21
22
23 namespace Vi {
24 namespace {
25
26 class Gpio : public Device, public Dev_feature
27 {
28 public:
29   int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios);
30
31   explicit Gpio(Hw::Device *d, Tagged_parameter *filter)
32     : _hwd(dynamic_cast<Hw::Gpio_chip*>(d)), _mask(0)
33   {
34     add_feature(this);
35
36     for (unsigned i = 0; i < Max_pins; ++i)
37       _irqs[i] = -1;
38
39     if (!filter)
40       return;
41
42     for (Expression *x = filter->get("pins"); x; x = x->next())
43       {
44         Value v = x->eval();
45         switch (v.type)
46           {
47           case Value::Num:
48             _mask |= (1UL << v.val.num);
49             break;
50           case Value::Range:
51             _mask |= ~(~0UL << (v.val.range.e - v.val.range.s + 1)) << v.val.range.s;
52             break;
53           default:
54             d_printf(DBG_ERR, "ERROR: GPIO: Invalid value for 'pins' statement in config, ignored.\n");
55             break;
56           }
57       }
58   }
59
60   char const *hid() const { return "GPIO"; }
61   void set_host(Device *d) { _host = d; }
62   Device *host() const { return _host; }
63
64   bool match_hw_feature(const Hw::Dev_feature*) const
65   { return false; }
66
67 private:
68   enum { Max_pins = 32 };
69   Device *_host;
70   Hw::Gpio_chip *_hwd;
71   l4_uint32_t _mask;
72
73   int _irqs[Max_pins];
74
75   int setup(L4::Ipc::Iostream &ios);
76   int config_pad(L4::Ipc::Iostream &ios);
77   int get(L4::Ipc::Iostream &ios);
78   int set(L4::Ipc::Iostream &ios);
79   int multi_setup(L4::Ipc::Iostream &ios);
80   int multi_config_pad(L4::Ipc::Iostream &ios);
81   int multi_get(L4::Ipc::Iostream &ios);
82   int multi_set(L4::Ipc::Iostream &ios);
83   int to_irq(L4::Ipc::Iostream &ios);
84
85   void check(unsigned pin)
86   {
87     if (pin > 31)
88       throw -ERANGE;
89
90     if (!((1UL << pin) & _mask))
91       throw -ERANGE;
92   }
93
94   void check_mask(unsigned mask)
95   {
96     if (mask & ~_mask)
97       throw -ERANGE;
98   }
99 };
100
101
102
103 int
104 Gpio::setup(L4::Ipc::Iostream &ios)
105 {
106   unsigned pin, mode;
107   int value;
108   ios >> pin >> mode >> value;
109   check(pin);
110   _hwd->setup(pin, mode, value);
111   return 0;
112 }
113
114 int
115 Gpio::config_pad(L4::Ipc::Iostream &ios)
116 {
117   unsigned pin, func, value;
118   ios >> pin >> func >> value;
119   check(pin);
120   _hwd->config_pad(pin, _mask, func, value);
121   return 0;
122 }
123
124 int
125 Gpio::get(L4::Ipc::Iostream &ios)
126 {
127   unsigned pin;
128   ios >> pin;
129   check(pin);
130   return _hwd->get(pin);
131 }
132
133 int
134 Gpio::set(L4::Ipc::Iostream &ios)
135 {
136   unsigned pin;
137   int value;
138   ios >> pin >> value;
139   check(pin);
140   _hwd->set(pin, value);
141   return 0;
142 }
143
144 int
145 Gpio::multi_setup(L4::Ipc::Iostream &ios)
146 {
147   unsigned mask, mode, outvalue;
148   ios >> mask >> mode >> outvalue;
149   check_mask(mask);
150   _hwd->multi_setup(mask, mode, outvalue);
151   return 0;
152 }
153
154 int
155 Gpio::multi_config_pad(L4::Ipc::Iostream &ios)
156 {
157   unsigned mask, func, value;
158   ios >> mask >> func >> value;
159   check_mask(mask);
160   _hwd->multi_config_pad(mask, func, value);
161   return 0;
162 }
163
164 int
165 Gpio::multi_get(L4::Ipc::Iostream &ios)
166 {
167   unsigned data = _hwd->multi_get();
168   ios << (unsigned)(data & _mask);
169   return 0;
170 }
171
172 int
173 Gpio::multi_set(L4::Ipc::Iostream &ios)
174 {
175   unsigned mask, data;
176   ios >> mask >> data;
177   check_mask(mask);
178   _hwd->multi_set(mask, data);
179   return 0;
180 }
181
182 int
183 Gpio::to_irq(L4::Ipc::Iostream &ios)
184 {
185   unsigned pin;
186   ios >> pin;
187   check(pin);
188
189   if (_irqs[pin] == -1)
190     {
191       // we have to allocate the IRQ...
192       // if it fails we mark the IRQ as unavailable (-L4_ENODEV)
193       _irqs[pin] = -L4_ENODEV;
194
195       int irqnum = _hwd->get_irq(pin);
196       if (irqnum < 0)
197         return irqnum;
198
199       if (System_bus *sb = dynamic_cast<System_bus *>(get_root()))
200         {
201           int virq = sb->sw_icu()->alloc_irq(Sw_icu::S_allow_set_mode,
202                                              Sw_icu::real_irq(irqnum));
203           if (virq < 0)
204             return virq;
205
206           _irqs[pin] = virq;
207           return virq;
208         }
209       return -L4_ENODEV;
210     }
211   return _irqs[pin];
212 }
213
214 int
215 Gpio::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
216 {
217   try
218     {
219       switch (func)
220         {
221         case L4VBUS_GPIO_OP_SETUP: return setup(ios);
222         case L4VBUS_GPIO_OP_CONFIG_PAD: return config_pad(ios);
223         case L4VBUS_GPIO_OP_GET: return get(ios);
224         case L4VBUS_GPIO_OP_SET: return set(ios);
225         case L4VBUS_GPIO_OP_MULTI_SETUP: return multi_setup(ios);
226         case L4VBUS_GPIO_OP_MULTI_CONFIG_PAD: return multi_config_pad(ios);
227         case L4VBUS_GPIO_OP_MULTI_GET: return multi_get(ios);
228         case L4VBUS_GPIO_OP_MULTI_SET: return multi_set(ios);
229         case L4VBUS_GPIO_OP_TO_IRQ: return to_irq(ios);
230         default: return -L4_ENOSYS;
231         }
232     }
233   catch (int err)
234     {
235       return err;
236     }
237 }
238
239
240 static Dev_factory_t<Gpio, Hw::Gpio_device> __gpio_factory;
241
242
243 }
244 }