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