1// vi:set ft=cpp: -*- Mode: C++ -*- 2/* 3 * (c) 2009-2014 Alexander Warg <alexander.warg@kernkonzept.com> 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 * As a special exception, you may use this file as part of a free software 10 * library without restriction. Specifically, if other files instantiate 11 * templates or use macros or inline functions from this file, or you compile 12 * this file and link it with other files to produce an executable, this 13 * file does not by itself cause the resulting executable to be covered by 14 * the GNU General Public License. This exception does not however 15 * invalidate any other reasons why the executable file might be covered by 16 * the GNU General Public License. 17 */ 18 19#pragma once 20 21 22#include <l4/sys/types.h> 23 24#include <l4/sys/icu> 25#include <l4/sys/task> 26#include <l4/re/env> 27#include <l4/re/util/cap_alloc> 28#include <l4/sys/cxx/ipc_legacy> 29 30namespace L4Re { namespace Util { 31 32template< typename ICU > 33class Icu_svr 34{ 35private: 36 ICU const *this_icu() const { return static_cast<ICU const *>(this); } 37 ICU *this_icu() { return static_cast<ICU*>(this); } 38 39public: 40 L4_RPC_LEGACY_DISPATCH(L4::Icu); 41 42 int op_bind(L4::Icu::Rights, l4_umword_t irqnum, 43 L4::Ipc::Snd_fpage irq_fp); 44 int op_unbind(L4::Icu::Rights, l4_umword_t irqnum, 45 L4::Ipc::Snd_fpage irq_fp); 46 int op_info(L4::Icu::Rights, L4::Icu::_Info &info); 47 int op_msi_info(L4::Icu::Rights, l4_umword_t irqnum, 48 l4_uint64_t source, l4_icu_msi_info_t &info); 49 int op_mask(L4::Icu::Rights, l4_umword_t irqnum); 50 int op_unmask(L4::Icu::Rights, l4_umword_t irqnum); 51 int op_set_mode(L4::Icu::Rights, l4_umword_t, l4_umword_t) 52 { return 0; } 53}; 54 55template<typename ICU> inline 56int 57Icu_svr<ICU>::op_bind(L4::Icu::Rights, l4_umword_t irqnum, 58 L4::Ipc::Snd_fpage irq_fp) 59{ 60 typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum); 61 if (!irq) 62 return -L4_EINVAL; 63 64 return irq->bind(this_icu(), irq_fp); 65} 66 67template<typename ICU> inline 68int 69Icu_svr<ICU>::op_unbind(L4::Icu::Rights, l4_umword_t irqnum, 70 L4::Ipc::Snd_fpage irq_fp) 71{ 72 typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum); 73 if (!irq) 74 return -L4_EINVAL; 75 76 return irq->unbind(this_icu(), irq_fp); 77} 78 79template<typename ICU> inline 80int 81Icu_svr<ICU>::op_info(L4::Icu::Rights, L4::Icu::_Info &info) 82{ 83 l4_icu_info_t i; 84 this_icu()->icu_get_info(&i); 85 info.features = i.features; 86 info.nr_irqs = i.nr_irqs; 87 info.nr_msis = i.nr_msis; 88 return 0; 89} 90 91template<typename ICU> inline 92int 93Icu_svr<ICU>::op_msi_info(L4::Icu::Rights, l4_umword_t irqnum, 94 l4_uint64_t source, l4_icu_msi_info_t &info) 95{ 96 typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum); 97 if (!irq) 98 return -L4_EINVAL; 99 return irq->msi_info(source, &info); 100} 101 102template<typename ICU> inline 103int 104Icu_svr<ICU>::op_mask(L4::Icu::Rights, l4_umword_t irqnum) 105{ 106 typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum); 107 if (irq) 108 irq->mask(true); 109 return -L4_ENOREPLY; 110} 111 112template<typename ICU> inline 113int 114Icu_svr<ICU>::op_unmask(L4::Icu::Rights, l4_umword_t irqnum) 115{ 116 typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum); 117 if (irq) 118 irq->mask(false); 119 return -L4_ENOREPLY; 120} 121 122 123template< typename ICU > 124class Icu_cap_array_svr : public Icu_svr<ICU> 125{ 126protected: 127 static void free_irq_cap(L4::Cap<L4::Irq> &cap) 128 { 129 if (cap) 130 { 131 L4Re::Util::cap_alloc.free(cap); 132 cap.invalidate(); 133 } 134 } 135 136public: 137 class Irq 138 { 139 public: 140 Irq() {} 141 ~Irq() { ICU::free_irq_cap(_cap); } 142 143 void trigger() const 144 { if (_cap) _cap->trigger(); } 145 146 int bind(ICU *, L4::Ipc::Snd_fpage const &irq_fp); 147 int unbind(ICU *, L4::Ipc::Snd_fpage const &irq_fp); 148 void mask(bool mask) const 149 { (void)mask; } 150 151 int msi_info(l4_uint64_t, l4_icu_msi_info_t *) const 152 { return -L4_EINVAL; } 153 154 L4::Cap<L4::Irq> cap() const { return _cap; } 155 156 private: 157 L4::Cap<L4::Irq> _cap; 158 }; 159 160private: 161 Irq *_irqs; 162 unsigned _nr_irqs; 163 164public: 165 166 Icu_cap_array_svr(unsigned nr_irqs, Irq *irqs) 167 : _irqs(irqs), _nr_irqs(nr_irqs) 168 {} 169 170 Irq *icu_get_irq(l4_umword_t irqnum) 171 { 172 if (irqnum >= _nr_irqs) 173 return 0; 174 175 return _irqs + irqnum; 176 } 177 178 void icu_get_info(l4_icu_info_t *inf) 179 { 180 inf->features = 0; 181 inf->nr_irqs = _nr_irqs; 182 inf->nr_msis = 0; 183 } 184}; 185 186template< typename ICU > 187int 188Icu_cap_array_svr<ICU>::Irq::bind(ICU *cfb, L4::Ipc::Snd_fpage const &irq_fp) 189{ 190 if (!irq_fp.cap_received()) 191 return -L4_EINVAL; 192 193 L4::Cap<L4::Irq> irq = cfb->server_iface()->template rcv_cap<L4::Irq>(0); 194 if (!irq) 195 return -L4_EINVAL; 196 197 int r = cfb->server_iface()->realloc_rcv_cap(0); 198 if (r < 0) 199 return r; 200 201 ICU::free_irq_cap(_cap); 202 _cap = irq; 203 return 0; 204} 205 206template< typename ICU > 207int 208Icu_cap_array_svr<ICU>::Irq::unbind(ICU *, L4::Ipc::Snd_fpage const &/*irq_fp*/) 209{ 210 ICU::free_irq_cap(_cap); 211 _cap = L4::Cap<L4::Irq>::Invalid; 212 return 0; 213} 214 215 216}} 217