L4Re - L4 Runtime Environment
vbus
1 // vi:ft=cpp
2 /*
3  * (c) 2011 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
4  * economic rights: Technische Universit├Ąt Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #pragma once
11 
12 #include <l4/vbus/vbus.h>
13 #include <l4/vbus/vbus_pm.h>
14 #include <l4/sys/icu>
15 
16 #include <l4/re/dataspace>
17 #include <l4/re/event>
18 #include <l4/re/inhibitor>
19 
20 /**
21  * C++ interface of the Vbus API.
22  *
23  * The virtual bus (Vbus) is a hierarchical (tree) structure of device nodes
24  * where each device has a set of resources attached to it. Each virtual bus
25  * provides an Icu (\ref l4_icu_api) for interrupt handling.
26  *
27  * The Vbus interface allows a client to find and query devices present on his
28  * virtual bus. After obtaining a device handle for a specific device the
29  * client can enumerate its resources.
30  *
31  * \includefile{l4/vbus/vbus}
32  *
33  * Refer to \ref l4vbus_module for the C API.
34  */
35 namespace L4vbus {
36 
37 class Vbus;
38 
39 /**
40  * Power-management API mixin.
41  */
42 template<typename DEC>
43 class Pm
44 {
45 private:
46  DEC const *self() const { return static_cast<DEC const *>(this); }
47  DEC *self() { return static_cast<DEC *>(this); }
48 public:
49  /**
50  * Suspend the module.
51  */
52  int pm_suspend() const
53  { return l4vbus_pm_suspend(self()->bus_cap().cap(), self()->dev_handle()); }
54 
55  /**
56  * Resume the module.
57  */
58  int pm_resume() const
59  { return l4vbus_pm_resume(self()->bus_cap().cap(), self()->dev_handle()); }
60 };
61 
62 
63 /**
64  * Device on a virtual bus (V-BUS)
65  */
66 class Device : public Pm<Device>
67 {
68 public:
69  Device() : _dev(L4VBUS_NULL) {}
70 
71  Device(L4::Cap<Vbus> bus, l4vbus_device_handle_t dev)
72  : _bus(bus), _dev(dev) {}
73 
74  /**
75  * Access the V-BUS capability of the underlying virtual bus.
76  * \return the capability to the underlying V-BUS.
77  */
78  L4::Cap<Vbus> bus_cap() const { return _bus; }
79 
80  /**
81  * Access the device handle of this device.
82  * \return the device handle for this device.
83  *
84  * The device handle is used to directly address the device on its virtual
85  * bus.
86  */
87  l4vbus_device_handle_t dev_handle() const { return _dev; }
88 
89 
90  /**
91  * Find a device by the HID.
92  *
93  * This function searches the vbus for a device with the given HID and
94  * returns a handle to the first matching device. The HID usually conforms to
95  * an ACPI HID or a Linux device tree compatible ID.
96  *
97  * It is possible to have multiple devices with the same HID on a vbus. In
98  * order to find all matching devices this function has to be called
99  * repeatedly with `child` pointing to the device found in the previous
100  * iteration. The iteration starts at `child` that might be any device node
101  * in the tree.
102  *
103  * \param[in, out] child Handle of the device from where in the device
104  * tree the search should start. To start searching
105  * from the beginning `child` must be initialized
106  * using the default (#L4VBUS_NULL). If a matching
107  * device is found its handle is returned through
108  * this parameter.
109  * \param hid HID of the device
110  * \param depth Maximum depth for the recursive lookup
111  * \param[out] devinfo Device information structure (might be NULL)
112  *
113  * \retval >= 0 A device with the given HID was found.
114  * \retval -L4_ENOENT No device with the given HID could be found on
115  * the vbus.
116  * \retval -L4_EINVAL Invalid or no HID provided.
117  * \retval -L4_ENODEV Function called on a non-existing device.
118  */
119  int device_by_hid(Device *child, char const *hid,
120  int depth = L4VBUS_MAX_DEPTH,
121  l4vbus_device_t *devinfo = 0) const
122  {
123  child->_bus = _bus;
124  return l4vbus_get_device_by_hid(_bus.cap(), _dev, &child->_dev, hid,
125  depth, devinfo);
126  }
127 
128  /**
129  * Find next child following `child`.
130  *
131  * \param[in, out] child Handle of the device that precedes the device
132  * that shall be found. To start from the beginning
133  * `child` must be initialized using the default
134  * (#L4VBUS_NULL).
135  * \param depth Depth to look for
136  * \param[out] devinfo device information (might be NULL)
137  *
138  * \return 0 on success, else failure
139  */
140  int next_device(Device *child, int depth = L4VBUS_MAX_DEPTH,
141  l4vbus_device_t *devinfo = 0) const
142  {
143  child->_bus = _bus;
144  return l4vbus_get_next_device(_bus.cap(), _dev, &child->_dev, depth,
145  devinfo);
146  }
147 
148  /**
149  * Obtain detailed information about a vbus device.
150  *
151  * \param[out] devinfo Information structure which contains details about
152  * the device. The pointer might be NULL after a
153  * successfull call.
154  *
155  * \retval 0 Success.
156  * \retval -L4_ENODEV No device with the given device handle `dev` could be
157  * found.
158  */
159  int device(l4vbus_device_t *devinfo) const
160  { return l4vbus_get_device(_bus.cap(), _dev, devinfo); }
161 
162  /**
163  * Obtain the resource description of an individual device resource.
164  *
165  * \param res_idx Index of the resource for which the resource
166  * description should be returned. The total number of
167  * resources for a device is available in the
168  * l4vbus_device_t structure that is returned by
169  * L4vbus::Device::device_by_hid() and
170  * L4vbus::Device::next_device().
171  * \param[out] res Descriptor of the resource.
172  *
173  * This function returns the resource descriptor of an individual device
174  * resource selected by the `res_idx` parameter.
175  *
176  * \retval 0 Success.
177  * \retval -L4_ENOENT Invalid resource index `res_idx`.
178  */
179  int get_resource(int res_idx, l4vbus_resource_t *res) const
180  {
181  return l4vbus_get_resource(_bus.cap(), _dev, res_idx, res);
182  }
183 
184  /**
185  * Check if the given device has a compatibility ID (CID) or HID that
186  * matches \a cid.
187  *
188  * \param cid the compatibility ID to test
189  * \return 1 when the given ID (\a cid) matches this device,
190  * 0 when the given ID does not match,
191  * <0 on error.
192  */
193  int is_compatible(char const *cid) const
194  { return l4vbus_is_compatible(_bus.cap(), _dev, cid); }
195 
196  /**
197  * Test if two devices are the same V-BUS device.
198  * \return true if the two devices are the same, false else.
199  */
200  bool operator == (Device const &o) const
201  {
202  return _bus == o._bus && _dev == o._dev;
203  }
204 
205  /**
206  * Test if two devices are not the same.
207  * \return true if the two devices are different, false else.
208  */
209  bool operator != (Device const &o) const
210  {
211  return _bus != o._bus || _dev != o._dev;
212  }
213 
214 protected:
215  L4::Cap<Vbus> _bus; /*!< The V-BUS capability (where this device is
216  located on). */
217  l4vbus_device_handle_t _dev; ///< The device handle for this device.
218 };
219 
220 /**
221  * V-BUS Interrupt controller API (ICU)
222  *
223  * Allows to access the underlying L4Re::Icu capability managing IRQs for
224  * the V-BUS.
225  */
226 class Icu : public Device
227 {
228 public:
229  /**
230  * Request the L4Re::Icu capability for this V-BUS ICU.
231  */
232  int vicu(L4::Cap<L4::Icu> icu) const
233  {
234  return l4vbus_vicu_get_cap(_bus.cap(), _dev, icu.cap());
235  }
236 };
237 
238 /**
239  * The virtual BUS.
240  */
241 class Vbus : public L4::Kobject_3t<Vbus, L4Re::Dataspace, L4Re::Inhibitor, L4Re::Event>
242 {
243 public:
244 
245  /**
246  * Request the given resource from the bus.
247  * \param res The resource that shall be requested from the bus.
248  * \param flags The flags for the request.
249  * \return >=0 on success, <0 on error.
250  */
251  int request_resource(l4vbus_resource_t *res, int flags = 0) const
252  {
253  return l4vbus_request_resource(cap(), res, flags);
254  }
255 
256  /**
257  * Release the given resource from the bus.
258  * \param res The resource that shall be requested from the bus.
259  * \return >=0 on success, <0 on error.
260  */
261  int release_resource(l4vbus_resource_t *res) const
262  {
263  return l4vbus_release_resource(cap(), res);
264  }
265 
266  /**
267  * Get the root device of the device tree of this bus.
268  * \return A V-BUS device representing the root of the device tree.
269  */
270  Device root() const
271  {
272  return Device(L4::Cap<Vbus>(cap()), L4VBUS_ROOT_BUS);
273  }
274 
275  typedef L4::Typeid::Raw_ipc<Vbus> Rpcs;
276 };
277 
278 } // namespace L4vbus