2 * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
3 * economic rights: Technische Universität Dresden (Germany)
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.
10 #include <l4/vbus/vdevice-ops.h>
13 #include "vbus_factory.h"
17 #include <l4/re/util/cap_alloc>
18 #include <l4/re/namespace>
20 #include <l4/re/error_helper>
23 #include <l4/sys/debugger.h>
24 #include <l4/sys/kdebug.h>
28 #include <pthread-l4.h>
32 using L4Re::Util::Auto_cap;
37 Sw_icu::Real_irq_pin Sw_icu::_real_irqs[256];
39 Sw_icu::Real_irq_pin *
40 Sw_icu::real_irq(unsigned n)
42 if (n >= sizeof(_real_irqs)/sizeof(_real_irqs[0]))
45 return &_real_irqs[n];
52 registry->register_obj(this);
57 registry->unregister_obj(this);
61 Sw_icu::bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &/*irqc*/)
67 // printf("%s[%p]: bind_irq(%d, ...)\n", name(), this, irqn);
69 Irq_set::iterator i = _irqs.find(irqn);
73 int err = i->bind(rcv_cap);
75 printf("ERROR: binding irq %d, result is %d (%s)\n", irqn, err, l4sys_errtostr(err));
81 Sw_icu::unbind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &/*irqc*/)
85 // printf("%s[%p]: unbind_irq(%d, ...)\n", name(), this, irqn);
87 Irq_set::iterator i = _irqs.find(irqn);
91 // could check the validity of the cap too, however we just don't care
96 Sw_icu::set_mode(l4_msgtag_t /*tag*/, unsigned irqn, l4_umword_t mode)
98 Irq_set::iterator i = _irqs.find(irqn);
102 if (i->l4_type() != (mode & 0x6))
104 printf("Changing type of IRQ %d from %x to %lx prohibited\n",
105 irqn, i->l4_type(), mode);
112 Sw_icu::unmask_irq(l4_msgtag_t /*tag*/, unsigned irqn)
114 Irq_set::iterator i = _irqs.find(irqn);
115 if (i == _irqs.end())
118 if (!i->unmask_via_icu())
126 Sw_icu::irqs_allocated(Adr_resource const *r)
128 for (unsigned n = r->_data().start(); n <= r->_data().end(); ++n)
130 if (_irqs.find(n) == _irqs.end())
138 Sw_icu::add_irqs(Adr_resource const *r)
140 for (unsigned n = r->_data().start(); n <= r->_data().end(); ++n)
142 if (_irqs.find(n) != _irqs.end())
145 Sw_irq_pin *irq = new Sw_irq_pin(real_irq(n), n, r->flags());
153 Sw_icu::dispatch(l4_umword_t /*obj*/, L4::Ipc_iostream &ios)
155 l4_umword_t op, irqn;
158 ios >> tag >> op >> irqn;
160 if (tag.label() != L4_PROTO_IRQ)
161 return -L4_EBADPROTO;
167 return bind_irq(tag, irqn, irqc);
169 case L4_ICU_OP_UNBIND:
171 return unbind_irq(tag, irqn, irqc);
173 case L4_ICU_OP_UNMASK:
174 unmask_irq(tag, irqn);
177 case L4_ICU_OP_SET_MODE:
181 return set_mode(tag, irqn, mode);
184 default: return -L4_ENOSYS;
189 Sw_icu::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
191 if (func != L4vbus_vicu_get_cap)
198 //static VBus_factory<Sw_icu> __vicu_factory("Vicu");
201 Sw_icu::Sw_irq_pin::trigger() const
203 return l4_error(_irq->trigger());
207 Sw_icu::Real_irq_pin::unbind()
209 unsigned n = this - real_irq(0);
211 n = (n - 0x80) | L4::Icu::F_msi;
213 int err = l4_error(system_icu()->icu->unbind(n, irq()));
214 set_shareable(false);
219 Sw_icu::Real_irq_pin::bind(L4::Cap<L4::Irq> irq, unsigned mode)
221 unsigned n = this - real_irq(0);
223 n = (n - 0x80) | L4::Icu::F_msi;
225 int err = l4_error(system_icu()->icu->bind(n, irq));
227 // allow sharing if IRQ must be acknowledged via the IRQ object
234 // printf(" IRQ[%x]: mode=%x ... ", n, mode);
235 err = l4_error(system_icu()->icu->set_mode(n, mode));
236 // printf("result=%d\n", err);
242 Sw_icu::Real_irq_pin::unmask()
244 unsigned n = this - real_irq(0);
246 n = (n - 0x80) | L4::Icu::F_msi;
248 system_icu()->icu->unmask(n);
253 Sw_icu::Sw_irq_pin::l4_type() const
256 unsigned r = (m & S_irq_type_mask) / Adr_resource::Irq_info_factor;
261 Sw_icu::Sw_irq_pin::allocate_master_irq()
263 assert (_master->shared());
264 Auto_cap<L4::Irq>::Cap lirq = chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(),
265 "allocating IRQ capability");
266 // printf("IRQ mode = %x -> %x\n", type(), l4_type());
267 chksys(L4Re::Env::env()->factory()->create(lirq.get(), L4_PROTO_IRQ) << l4_umword_t(1), "allocating IRQ");
268 chksys(_master->bind(lirq.get(), l4_type()), "binding IRQ");
269 _master->_irq = lirq.release();
270 _master->set_chained(true);
275 Sw_icu::Sw_irq_pin::share(Auto_cap<L4::Irq>::Cap const &irq)
277 if (!_master->shareable())
279 printf("WARNING: IRQ %d cannot be shared\n", irqn());
285 // the second irq shall be attached to a single hw irq
286 printf("IRQ %d -> proxy -> 2 clients\n", irqn());
287 Auto_cap<L4::Irq>::Cap lirq(L4Re::Util::cap_alloc.alloc<L4::Irq>());
288 if (!lirq.get().is_valid())
291 int err = l4_error(L4Re::Env::env()->factory()->create_irq(lirq.get()));
296 //enter_kdebug("XX");
297 // XXX: level low is a hack
298 L4Re::chksys(lirq->chain(l4_umword_t(_master), L4::Irq::F_level_low, _master->_irq));
299 L4Re::chksys(lirq->chain(l4_umword_t(_master), L4::Irq::F_level_low, irq.get()));
300 L4Re::chksys(lirq->set_mode(L4::Irq::F_level_low), "set mode");
301 L4Re::chksys(err = _master->bind(lirq.get()));
302 //enter_kdebug("XX");
304 // do the internal list enqueuing and resource management
306 _master->_irq = lirq.release();
308 _master->set_chained(true);
312 catch (L4::Runtime_error const &e)
314 _master->bind(_master->_irq);
321 Sw_icu::Sw_irq_pin::bind(L4::Cap<void> rc)
325 if (_irq.get().validate(L4Re::This_task).label() > 0)
333 if (!(ri = real_irq(irqn())))
339 Auto_cap<L4::Irq>::Cap irq =
340 chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(), "allocating IRQ capability");
342 irq.get().move(L4::cap_cast<L4::Irq>(rc));
344 if (_master->shared() && !_master->chained() && _master->_sw_irqs == 0)
346 allocate_master_irq();
347 assert (_master->chained());
350 if (!_master->chained())
352 // the first irq shall be attached to a hw irq
353 // printf("IRQ %d -> client\n", irqn());
354 // printf("IRQ mode = %x -> %x\n", type(), l4_type());
355 int err = _master->bind(irq.get(), l4_type());
360 _master->_irq = _irq.get();
364 _state |= S_unmask_via_icu;
366 // printf(" bound irq %u -> err=%d\n", irqn(), err);
370 // printf("IRQ %d -> proxy -> %d clients\n", irqn(), _master->_sw_irqs + 1);
371 L4Re::chksys(_master->_irq->chain(l4_umword_t(_master), irq.get()), "attach");
379 Sw_icu::Sw_irq_pin::_unbind()
382 --(_master->_sw_irqs);
383 if (_master->_sw_irqs == 0)
385 if (_master->chained())
386 L4Re::Util::cap_alloc.free(_master->_irq);
388 _master->_irq = L4::Cap<L4::Irq>::Invalid;
389 _master->set_chained(false);
392 _irq = L4::Cap<L4::Irq>::Invalid;
399 Sw_icu::Sw_irq_pin::unbind()
404 if (!_master->_sw_irqs)