]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/lua_glue.swg
update
[l4.git] / l4 / pkg / io / server / src / lua_glue.swg
1 %module Io
2
3 %include <typemaps.i>
4 %include <lua_typemap.i>
5 %include "std_string.i"
6 %include "lua_typeinfo.i"
7
8 %{
9
10 #include "virt/vdevice.h"
11 #include "virt/vbus_factory.h"
12 #include "hw_device.h"
13 #include "gpio"
14
15 static int is_lua_propval(lua_State *L, int idx)
16 {
17   if (lua_isnumber(L, idx))
18     return 1;
19   if (lua_isstring(L, idx))
20     return 1;
21   return 0;
22 }
23
24 static Hw::Device::Prop_val to_lua_propval(lua_State *L, int idx)
25 {
26   if (lua_isnumber(L, idx))
27     return Hw::Device::Prop_val(lua_tointeger(L, idx));
28   else if (lua_isstring(L, idx))
29     return Hw::Device::Prop_val(lua_tostring(L, idx));
30   return 0;
31 }
32
33 int luaopen_Io(lua_State *);
34 int add_vbus(Vi::Device *dev);
35 void dump_devs(Device *d);
36
37 %}
38
39 %apply SWIG_BIGUINT { Resource::Addr }
40 %apply SWIG_BIGINT { Resource::Size }
41
42 %typemap(in,checkfn="is_lua_propval") Hw::Device::Prop_val
43 %{$1 = to_lua_propval(L, $input); %}
44
45 %typemap(in, checkfn="is_lua_propval") Hw::Device::Prop_val const & (Hw::Device::Prop_val tmp)
46 %{tmp = to_lua_propval(L, $input); $1 = &tmp; %}
47
48 %ignore Resource_space;
49 %ignore Resource_list;
50 %ignore Resource_provider;
51 %ignore Root_resource;
52 %ignore Vi::Dev_feature;
53 %ignore Hw::Dev_feature;
54
55 %include "resource.h"
56
57 %apply SWIGTYPE *DISOWN { Hw::Device *disown };
58 %apply SWIGTYPE *DISOWN { Vi::Device *disown };
59 %apply SWIGTYPE *DISOWN { Resource *disown };
60
61 %nodefaultctor;
62 %rename(Vi_dev_factory) Vi::Dev_factory;
63 %rename(Vi_device) Vi::Device;
64 %rename(Hw_dev_factory) Hw::Device_factory;
65 %rename(Hw_device) Hw::Device;
66
67 %nodefaultdtor Vi::Dev_factory;
68 %nodefaultdtor Hw::Device_factory;
69
70 class Device
71 {};
72
73 class Generic_device : public Device
74 {
75 public:
76   void add_resource(Resource *disown);
77 };
78
79 %extend Generic_device
80 {
81   int nresources() const
82   {
83     return self->resources()->size();
84   }
85
86   Resource *resource(int idx) const
87   {
88     return self->resources()->at(idx);
89   }
90 };
91
92 namespace Vi {
93
94 class Device : public Generic_device
95 {
96 public:
97   void add_child(Device *disown);
98   void name(char const *);
99   char const *name() const;
100   Device *parent() const;
101   Device *children() const;
102   Device *next() const;
103   int depth() const;
104   int add_filter(cxx::String const &, cxx::String const &);
105   int add_filter(cxx::String const &, unsigned long long);
106   int add_filter(cxx::String const &, unsigned long long, unsigned long long);
107
108   void dump(int) const;
109 };
110
111 class Dev_factory
112 {
113 public:
114   virtual Device *vcreate() = 0;
115   virtual Device *do_match(Hw::Device *f) = 0;
116
117   static Device *create(std::string const &_class);
118   static Device *create(Hw::Device *f);
119 };
120 }
121
122 %extend Vi::Device
123 {
124   void set_name(char const *name) { self->name(name); }
125 };
126
127 namespace Hw {
128 class Device : public Generic_device
129 {
130 public:
131   struct Prop_val;
132   int set_property(char const *prop, Prop_val const &val);
133   void add_child(Device *disown);
134   void add_cid(char const *);
135   void set_name(char const *);
136   char const *name() const;
137   bool match_cid(char const *cid) const;
138   Device *parent() const;
139   Device *children() const;
140   Device *next() const;
141   int depth() const;
142   void plugin();
143
144   void dump(int) const;
145 };
146
147 class Device_factory
148 {
149 public:
150   virtual Device *create() = 0;
151   static Device *create(char const *name);
152 };
153
154 }
155
156 %extend Hw::Device
157 {
158   Hw::Device *find_by_name(std::string const &name) const
159   {
160     for (Hw::Device::iterator c = self->begin(0);
161          c != self->end(); ++c)
162       if (name == (*c)->name())
163         return *c;
164
165     return 0;
166   }
167
168   Hw::Device *__getitem(std::string const &name) const
169   {
170     for (Hw::Device::iterator c = self->begin(0);
171          c != self->end(); ++c)
172       if (name == (*c)->name())
173         return *c;
174
175     return 0;
176   }
177
178   void __setitem(std::string const &name, Hw::Device *dev)
179   {
180     dev->set_name(name);
181     self->add_child(dev);
182     if (self->parent() || self == system_bus())
183       dev->plugin();
184   }
185 };
186
187 Hw::Device *system_bus();
188 void dump_devs(Device *d);
189 int add_vbus(Vi::Device *dev);
190
191
192 class Gpio_resource : public Resource
193 {
194 public:
195   explicit Gpio_resource(Hw::Device *dev, unsigned start, unsigned end)
196     throw(char const *);
197 };
198
199 %luacode {
200
201 local function check_device(dev, depth, err)
202   if not Io.swig_instance_of(dev, "Generic_device *") then
203     local e = err or "expected device, got: " .. tostring(dev);
204     error(e, depth + 1);
205   end
206   return dev
207 end
208
209 Io.Res = {}
210
211 function Io.Res.io(start, _end, flags)
212   local f = flags or 0
213   return Io.Resource(Io.Resource_Io_res, f, start, _end or start)
214 end
215
216 function Io.Res.mmio(start, _end, flags)
217   local f = flags or 0
218   return Io.Resource(Io.Resource_Mmio_res, f, start, _end or start)
219 end
220
221 function Io.Res.irq(start, flags)
222   local f = flags or 0
223   local s, e
224   if type(start) == "table" then
225     s = start[1]
226     e = start[2]
227   else
228     s = start
229     e = start
230   end
231   return Io.Resource(Io.Resource_Irq_res, f, s, e)
232 end
233
234 Io.Dt = {}
235
236 function Io.Dt.add_child(parent, name, dev, idx)
237   parent:add_child(dev)
238   if dev.plugin and (parent:parent() or swig_equals(parent, Io.system_bus())) then
239     dev:plugin()
240   end
241   if type(name) == "string" then
242     if idx ~= nil then
243       name = name .. '[' .. idx ..']'
244     end
245     dev:set_name(name)
246   end
247 end
248
249 function Io.Dt.add_children(parent, bus_func)
250   check_device(parent, 2);
251   if type(bus_func) == "function" then
252     local d = {}
253     local my_env = getfenv(1)
254     local old_ENV = my_env._ENV;
255     my_env._ENV = d;
256     setmetatable(d, { __index = my_env })
257     setfenv(bus_func, d)
258     bus_func()
259     my_env._ENV = old_ENV;
260     Io.Dt.add_device_data(parent, d)
261   end
262   return parent;
263 end
264
265 function Io.Dt.iterator(dev, max_depth)
266   local max_d = (max_depth or 0) + dev:depth()
267   local current = dev
268   local start = dev
269   return function ()
270     local c = current
271     if c == nil then
272       return nil
273     end
274
275     local cd = c:depth()
276     local cc = c:children()
277     if max_d > cd and cc then
278       current = cc
279       return c
280     elseif c:next() then
281       current = c:next()
282       return c
283     else
284       local p = c
285       while (true) do
286         p = p:parent()
287         if (not p) or swig_equals(p, start) then
288           current = nil
289           return c
290         elseif p:next() then
291           current = p:next()
292           return c
293         end
294       end
295     end
296   end
297 end
298
299 function Io.Dt.match_cids(self, ...)
300   local r = {}
301   for _, v in ipairs{...} do
302     if self:match_cid(v) then
303       return true
304     end
305   end
306   return false
307 end
308
309 Io.Dt.PCI_cc =
310 {
311   storage = "CC_01",
312   network = "CC_02",
313   display = "CC_03",
314   media   = "CC_04",
315   bridge  = "CC_06",
316   com     = "CC_07",
317   usb     = "CC_0c",
318   wlan    = "CC_0d",
319 }
320
321 Io.Dt.MAX_DEPTH = 1000
322
323 function Io.Dt.Range(start, stop)
324   return { range = true, start, stop }
325 end
326
327 function Io.Dt.match(self, ...)
328   local cids = {...}
329   for t,v in pairs(Io.Dt.PCI_cc) do
330     for i, cid in ipairs(cids) do
331       cids[i] = cid:gsub("(PCI/"..t..")", "PCI/" .. v)
332     end
333   end
334
335   local devs = {}
336   for d in self:devices(Io.Dt.MAX_DEPTH) do
337     if d:match_cids(unpack(cids)) then
338       devs[#devs+1] = d
339     end
340   end
341   return devs
342 end
343
344 function Io.Dt.device(self, path)
345   for i in string.gmatch(path, "([^%./]+)%.*") do
346     self = self:find_by_name(i)
347     if self == nil then
348       return nil
349     end
350   end
351   return self
352 end
353
354 function Io.Dt.resources(self)
355   local n = self:nresources()
356   local c = 0
357   return function ()
358     if c >= n then return nil end
359     c = c + 1
360     return self:resource(c - 1)
361   end
362 end
363
364 local hwfn = Io.swig_class("Hw_device")[".fn"]
365 local vifn = Io.swig_class("Vi_device")[".fn"]
366
367 local dev_fns =
368 {
369   resources = Io.Dt.resources,
370   devices = Io.Dt.iterator,
371   match_cids = Io.Dt.match_cids,
372   match = Io.Dt.match,
373   device = Io.Dt.device
374 }
375
376 for name, func in pairs(dev_fns) do
377   hwfn[name] = func
378   vifn[name] = func
379 end
380
381 function vifn:add_filter_val(tag, value)
382   if type(value) == "table" and value.range then
383     return self:add_filter(tag, value[1], value[2])
384   elseif type(value) == "table" then
385     for _, v in ipairs(value) do
386       local res = self:add_filter_val(tag, v)
387       if res < 0 then
388         return res
389       end
390     end
391     return 0
392   else
393     return self:add_filter(tag, value)
394   end
395 end
396
397 local add_child = Io.Dt.add_child
398
399 local function handle_device_member(dev, val, name)
400   if name == "compatible" then
401     if type(val) == "table" then
402       for k, v in ipairs(val) do
403         dev:add_cid(v)
404       end
405     elseif type(val) == "string" then
406       dev:add_cid(val)
407     end
408     return
409   elseif type(val) == "table" then
410     for i, v in pairs(val) do
411       handle_device_member(dev, v, name .. '[' .. i .. ']')
412     end
413     return
414   elseif Io.swig_instance_of(val, "Resource *") then
415     val:set_id(name)
416     dev:add_resource(val)
417     return
418   elseif Io.swig_instance_of(val, "Generic_device *") then
419     add_child(dev, name, val)
420     return
421   else
422     local sp = dev.set_property
423     if type(sp) == "function" then
424       sp(dev, name, val)
425       return
426     end
427   end
428   print("ERROR: cannot handle device member: " .. tostring(name) .. ": " .. tostring(val))
429 end
430
431 function Io.Dt.add_resource(dev, res)
432   if not Io.swig_instance_of(dev, "Generic_device *") then
433     error("expected a device got: " .. tostring(dev), 2)
434   end
435   if not Io.swig_instance_of(res, "Resource *") then
436     error("expected a resource got: " .. tostring(res), 2)
437   end
438   dev:add_resource(res)
439 end
440
441 function Io.Dt.add_device_data(dev, data)
442   local maxi = 0
443   for i, v in ipairs(data) do
444     handle_device_member(dev, v, i)
445     maxi = i
446   end
447   for k, v in pairs(data) do
448     if (type(k) ~= "number") or (k > maxi) then
449       handle_device_member(dev, v, k)
450     end
451   end
452 end
453
454 local set_dev_data = Io.Dt.add_device_data
455 local add_children = Io.Dt.add_children
456
457 Io.Hw = {}
458
459 setmetatable(Io.Hw, { __index = function (self, t)
460   return function (data)
461     local b = check_device(Io.Hw_dev_factory_create(t), 3, "could not create device: " .. t)
462     if type(data) == "function" then
463       add_children(b, data)
464     elseif type(data) == "table" then
465       set_dev_data(b, data)
466     end
467     return b
468   end
469 end})
470
471 function Io.hw_add_devices(data)
472   local sb = Io.system_bus()
473   local dtype = type(data)
474   if dtype == 'function' then
475     Io.Dt.add_children(sb, data)
476   elseif dtype == 'table' then
477     for n, dev in pairs(data) do
478       if type(n) == "string" then
479         dev:set_property("name", n)
480       end
481       sb:add_child(dev)
482       dev:plugin()
483     end
484   end
485   return data
486 end
487
488 Io.Vi = {}
489
490 setmetatable(Io.Vi, { __index = function (self, t)
491   return function (data)
492     local b = Io.Vi_dev_factory_create(t)
493     if type(data) == "function" then
494       add_children(b, data)
495     elseif type(data) == "table" then
496       set_dev_data(b, data)
497     end
498     return b
499   end
500 end})
501
502 function wrap(devs_, filter)
503   local devs = devs_
504   if type(devs_) ~= "table" then
505     devs = { devs_ }
506   end
507   local v = {}
508   for _, d in ipairs(devs) do
509     local vd = Io.Vi_dev_factory_create(d)
510     if vd then
511       if type(filter) == "table" then
512         for tag, val in pairs(filter) do
513           local res = vd:add_filter_val(tag, val)
514           if res < 0 then
515             print("ERROR: applying filter expression: "..tag.."=...", debug.traceback(2))
516           end
517         end
518       end
519       v[#v + 1] = vd
520     end
521   end
522   if #v == 1 then
523     return v[1]
524   else
525     return v
526   end
527 end
528
529 local add_vbus = Io.add_vbus
530
531 function Io.add_vbus(name, bus)
532   bus:set_name(name)
533   add_vbus(bus)
534 end
535
536 function Io.add_vbusses(busses)
537   for name, bus in pairs(busses) do
538     Io.add_vbus(name, bus)
539   end
540   return busses
541 end
542
543 }