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"
18 #include <l4/re/util/cap_alloc>
19 #include <l4/re/namespace>
21 #include <l4/re/error_helper>
24 #include <l4/sys/debugger.h>
25 #include <l4/sys/kdebug.h>
32 using L4Re::Util::Auto_cap;
38 typedef std::map<unsigned, Kernel_irq_pin *> Irq_map;
39 static Irq_map _real_irqs;
44 Sw_icu::real_irq(unsigned n)
46 Irq_map::const_iterator f = _real_irqs.find(n);
48 if (f == _real_irqs.end() || !(*f).second)
49 _real_irqs[n] = r = new Kernel_irq_pin(n);
60 registry->register_obj(this);
65 registry->unregister_obj(this);
69 Sw_icu::bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Ipc::Snd_fpage const &/*irqc*/)
74 d_printf(DBG_ALL, "%s[%p]: bind_irq(%d, ...)\n", name(), this, irqn);
76 Irq_set::Iterator i = _irqs.find(irqn);
80 int err = i->bind(rcv_cap);
82 d_printf(DBG_ERR, "ERROR: binding irq %d, result is %d (%s)\n", irqn, err, l4sys_errtostr(err));
88 Sw_icu::unbind_irq(l4_msgtag_t tag, unsigned irqn, L4::Ipc::Snd_fpage const &/*irqc*/)
93 d_printf(DBG_ALL, "%s[%p]: unbind_irq(%d, ...)\n", name(), this, irqn);
95 Irq_set::Iterator i = _irqs.find(irqn);
99 // could check the validity of the cap too, however we just don't care
104 Sw_icu::set_mode(l4_msgtag_t /*tag*/, unsigned irqn, l4_umword_t mode)
106 Irq_set::Iterator i = _irqs.find(irqn);
107 if (i == _irqs.end())
110 return i->set_mode(mode);
114 Sw_icu::unmask_irq(l4_msgtag_t /*tag*/, unsigned irqn)
116 Irq_set::Iterator i = _irqs.find(irqn);
117 if (i == _irqs.end())
120 if (!i->unmask_via_icu())
128 Sw_icu::irqs_allocated(Adr_resource const *r)
130 for (unsigned n = r->_data().start(); n <= r->_data().end(); ++n)
132 if (_irqs.find(n) == _irqs.end())
140 Sw_icu::add_irqs(Adr_resource const *r)
142 for (unsigned n = r->_data().start(); n <= r->_data().end(); ++n)
144 if (_irqs.find(n) != _irqs.end())
147 Kernel_irq_pin *ri = real_irq(n);
150 d_printf(DBG_ERR, "ERROR: No IRQ%d available.\n", n);
153 Sw_irq_pin *irq = new Sw_irq_pin(ri, n, r->flags());
160 Sw_icu::add_irq(unsigned n, unsigned flags, Io_irq_pin *be)
162 if (_irqs.find(n) == _irqs.end())
165 Sw_irq_pin *irq = new Sw_irq_pin(be, n, flags);
171 Sw_icu::alloc_irq(unsigned flags, Io_irq_pin *be)
174 for (i = 1; i < 1000; ++i)
175 if (_irqs.find(i) == _irqs.end())
181 Sw_irq_pin *irq = new Sw_irq_pin(be, i, flags);
188 Sw_icu::dispatch(l4_umword_t /*obj*/, L4::Ipc::Iostream &ios)
190 l4_umword_t op, irqn;
191 L4::Ipc::Snd_fpage irqc;
193 ios >> tag >> op >> irqn;
195 if (tag.label() != L4_PROTO_IRQ)
196 return -L4_EBADPROTO;
202 return bind_irq(tag, irqn, irqc);
204 case L4_ICU_OP_UNBIND:
206 return unbind_irq(tag, irqn, irqc);
208 case L4_ICU_OP_UNMASK:
209 unmask_irq(tag, irqn);
212 case L4_ICU_OP_SET_MODE:
216 return set_mode(tag, irqn, mode);
219 default: return -L4_ENOSYS;
224 Sw_icu::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
226 if (func != L4vbus_vicu_get_cap)
233 //static VBus_factory<Sw_icu> __vicu_factory("Vicu");
236 Sw_icu::Sw_irq_pin::trigger() const
238 return l4_error(_irq->trigger());
243 Sw_icu::Sw_irq_pin::l4_type() const
246 unsigned r = (m & S_irq_type_mask) / Adr_resource::Irq_info_factor;
251 Sw_icu::Sw_irq_pin::set_mode(l4_umword_t mode)
253 if (!(_state & S_allow_set_mode)
254 && (l4_type() != (mode & (L4_IRQ_F_MASK & ~1))))
256 d_printf(DBG_WARN, "WARNING: Changing type of IRQ %d from %x to %lx prohibited\n",
257 _irqn, l4_type(), mode);
261 return _master->set_mode(mode);
265 Sw_icu::Sw_irq_pin::allocate_master_irq()
267 assert (_master->shared());
268 Auto_cap<L4::Irq>::Cap lirq = chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(),
269 "allocating IRQ capability");
270 // printf("IRQ mode = %x -> %x\n", type(), l4_type());
271 chksys(L4Re::Env::env()->factory()->create(lirq.get(), L4_PROTO_IRQ) << l4_umword_t(1), "allocating IRQ");
272 chksys(_master->bind(lirq.get(), l4_type()), "binding IRQ");
273 _master->irq(lirq.release());
274 _master->set_chained(true);
279 Sw_icu::Sw_irq_pin::bind(L4::Cap<void> rc)
283 if (_irq.get().validate(L4Re::This_task).label() > 0)
292 Auto_cap<L4::Irq>::Cap irq =
293 chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(), "allocating IRQ capability");
295 irq.get().move(L4::cap_cast<L4::Irq>(rc));
297 if (_master->shared() && !_master->chained() && _master->sw_irqs() == 0)
299 allocate_master_irq();
300 assert (_master->chained());
303 if (!_master->chained())
305 // the first irq shall be attached to a hw irq
306 d_printf(DBG_DEBUG2, "IRQ %d -> client\nIRQ mode = %x -> %x\n",
307 irqn(), type(), l4_type());
308 int err = _master->bind(irq.get(), l4_type());
313 _master->irq(_irq.get());
314 _master->inc_sw_irqs();
317 _state |= S_unmask_via_icu;
319 d_printf(DBG_DEBUG2, " bound irq %u -> err=%d\n", irqn(), err);
323 d_printf(DBG_DEBUG2, "IRQ %d -> proxy -> %d clients\n", irqn(), _master->sw_irqs() + 1);
324 L4Re::chksys(_master->irq()->chain(l4_umword_t(_master), irq.get()), "attach");
326 _master->inc_sw_irqs();
332 Sw_icu::Sw_irq_pin::_unbind()
335 _master->dec_sw_irqs();
336 if (_master->sw_irqs() == 0)
338 if (_master->chained())
339 L4Re::Util::cap_alloc.free(_master->irq());
341 _master->irq(L4::Cap<L4::Irq>::Invalid);
342 _master->set_chained(false);
345 _irq = L4::Cap<L4::Irq>::Invalid;
352 Sw_icu::Sw_irq_pin::unbind()
357 if (!_master->sw_irqs())