1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 2012 Apple Computer, Inc.  All Rights Reserved.
5 *
6 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. The rights granted to you under the License
12 * may not be used to create, or enable the creation or redistribution of,
13 * unlawful or unlicensed copies of an Apple operating system, or to
14 * circumvent, violate, or enable the circumvention or violation of, any
15 * terms of an Apple operating system software license agreement.
16 *
17 * Please obtain a copy of the License at
18 * http://www.opensource.apple.com/apsl/ and read it before using this file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 */
30
31#ifndef _IOREPORT_MACROS_H_
32#define _IOREPORT_MACROS_H_
33
34#include "IOReportTypes.h"
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40/*
41    Background
42
43    These macros allow non-I/O Kit software to generate IOReporting
44    reports.  Clients must prevent concurrent access to any given
45    report buffer from multiple threads.
46
47    While these macros allow non-I/O Kit software to participate
48    in IOReporting, an IOService instance must lend its driver ID,
49    respond to the appropriate IOService overrides, and shuttle
50    data back and forth.  In some cases, it may be useful to have
51    the I/O Kit driver initialize the report buffer with the
52    appropriate macro.
53*/
54
55/*
56 * Returns the buffer size required for a Simple report.
57 */
58#define SIMPLEREPORT_BUFSIZE   (sizeof(IOReportElement))
59
60/*
61 * Initialize a buffer to hold a Simple (integer) report.
62 *
63 *                  void* buffer - ptr to SIMPLEREPORT_BUFSIZE bytes
64 *                size_t bufSize - sanity check of buffer's size
65 *           uint64_t providerID - registry Entry ID of the reporting service
66 *            uint64_t channelID - the report's channel ID
67 * IOReportCategories categories - categories of this channel
68 *
69 * If the buffer is not of sufficient size, the macro performs a
70 * null pointer reference to trigger a segfault.  Then, the buffer is
71 * filled with 0xbadcafe.
72 */
73#define SIMPLEREPORT_INIT(buffer, bufSize, providerID, channelID, cats)  \
74do {  \
75    IOReportElement     *__elem = (IOReportElement *)(buffer);  \
76    IOSimpleReportValues *__vals;  \
77    if ((bufSize) >= SIMPLEREPORT_BUFSIZE) {  \
78        __elem->channel_id = (channelID);  \
79        __elem->provider_id = (providerID);  \
80        __elem->channel_type.report_format = kIOReportFormatSimple;  \
81        __elem->channel_type.reserved = 0;  \
82        __elem->channel_type.categories = (cats);  \
83        __elem->channel_type.nelements = 1;  \
84        __elem->channel_type.element_idx = 0;  \
85        __elem->timestamp = 0;  \
86		__vals = (IOSimpleReportValues*)&__elem->values;  \
87		__vals->simple_value = kIOReportInvalidValue;  \
88    }  \
89    else {  \
90        uint32_t *__nptr = NULL;  \
91        *__nptr = 1;  \
92        POLLUTE_BUF((buffer), (bufSize));  \
93    }  \
94} while(0)
95
96
97/*
98 * Sets the SimpleReport channel to a new value.
99 *
100 *     void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
101 * uint64_t new_value - new value for the channel
102 */
103#define SIMPLEREPORT_SETVALUE(simp_buf, new_value)  \
104do {  \
105    IOReportElement *__elem = (IOReportElement *)(simp_buf);  \
106    IOSimpleReportValues *__vals;  \
107    __vals = (IOSimpleReportValues*)&__elem->values;  \
108    __vals->simple_value = (new_value);  \
109} while(0)
110
111/*
112 * Prepare simple report buffer for
113 * IOService::updateReport(kIOReportCopyChannelData...)
114 *
115 * void* simp_buf  - Ptr to memory updated by SIMPLEREPORT_SETVALUE()
116 * void* ptr2cpy   - On return, 'ptr2cpy' points to the memory that needs to be
117 *                   copied for kIOReportCopyChannelData.
118 * size_t size2cpy - On return, 'size2cpy' is set to the size of the report
119 *                   data that needs to be copied for kIOReportCopyChannelData.
120 */
121#define SIMPLEREPORT_UPDATEPREP(simp_buf, ptr2cpy, size2cpy)  \
122do {  \
123    (ptr2cpy) = (simp_buf);  \
124    (size2cpy) = sizeof(IOReportElement);  \
125} while(0)
126
127
128/*
129 * Updates the result field received as a parameter for
130 * kIOReportGetDimensions & kIOReportCopyChannelData actions.
131 *
132 * IOReportConfigureAction action - configure/updateReport() 'action' param
133 *                   void* result - configure/updateReport() 'result' param
134 */
135
136#define SIMPLEREPORT_UPDATERES(action, result)  \
137do {  \
138    if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) {  \
139        int *__nElements = (int *)(result);  \
140        *__nElements += 1;  \
141    }  \
142} while (0)
143
144
145
146/*
147 * Returns the channel id from the buffer previously initialized by
148 * SIMPLEREPORT_INIT().
149 *
150 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
151 */
152
153#define SIMPLEREPORT_GETCHID(simp_buf)  \
154    (((IOReportElement *)(simp_buf))->channel_id);  \
155
156
157
158// Internal struct for State report buffer
159typedef struct {
160   uint16_t        curr_state;
161   uint64_t        update_ts;
162   IOReportElement elem[]; // Array of elements
163} IOStateReportInfo;
164
165/*
166 * Returns the size required to be allocated for using STATEREPORT_*()
167 *
168 * int nstates - number of states for the intended channel
169 */
170#define STATEREPORT_BUFSIZE(nstates)  \
171    (sizeof(IOStateReportInfo) + (nstates) * sizeof(IOReportElement))
172
173
174/*
175 * Initializes a buffer so it can be used with STATEREPORT_*().
176 *
177 *                   int nstates - number of states to be reported
178 *                  void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes
179 *                size_t bufSize - sanity check of buffer's size
180 *           uint64_t providerID - registry Entry ID of the reporting service
181 *            uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
182 * IOReportCategories categories - categories of this channel
183 *
184 * If the buffer is not of sufficient size, the macro performs a
185 * null pointer reference to trigger a segfault.  Then, the buffer is
186 * filled with 0xbadcafe.
187 */
188#define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \
189do {  \
190    IOStateReportInfo *__info = (IOStateReportInfo *)(buf);  \
191    IOStateReportValues *__rep;  \
192    IOReportElement     *__elem;  \
193    if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) {  \
194        for (unsigned __no = 0; __no < (nstates); __no++) {  \
195            __elem =  &(__info->elem[__no]);  \
196            __rep = (IOStateReportValues *) &(__elem->values);  \
197            __elem->channel_id = (channelID);  \
198            __elem->provider_id = (providerID);  \
199            __elem->channel_type.report_format = kIOReportFormatState;  \
200            __elem->channel_type.reserved = 0;  \
201            __elem->channel_type.categories = (cats);  \
202            __elem->channel_type.nelements = (nstates);  \
203            __elem->channel_type.element_idx = __no;  \
204            __elem->timestamp = 0;  \
205            __rep->state_id = __no;  \
206            __rep->intransitions = 0;  \
207            __rep->upticks = 0;  \
208        }  \
209        __info->curr_state = 0;  \
210        __info->update_ts = 0;  \
211    }  \
212    else {  \
213        int *__nptr = NULL;  \
214        *__nptr = 1;  \
215        POLLUTE_BUF((buf), (bufSize));  \
216    }  \
217} while(0)
218
219/*
220 * Initializes the state id field of a state with the specified value.  By
221 * default, STATEREPORT_INIT initializes the state id with the index of
222 * that state.  This macro can be used to provide a more descriptive state id.
223 *
224 *   void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
225 * unsigned stateIdx - index of the state, out of bounds -> no-op
226 *  uint64_t stateID - new state id, see IOREPORT_MAKEID()
227 */
228#define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID)  \
229do {  \
230    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
231    IOStateReportValues *__rep;  \
232    if ((stateIdx) < __info->elem[0].channel_type.nelements) {  \
233        __rep = (IOStateReportValues*) &(__info->elem[(stateIdx)].values);  \
234        __rep->state_id = (stateID);  \
235    }  \
236} while (0)
237
238
239/*
240 * Set the state of a State report.
241 *
242 *      void* state_buf - pointer to memory initialized by STATEREPORT_INIT()
243 * unsigned newStateIdx - index of new state, out of bounds -> no-op
244 *  uint64_t changeTime - time at which the transition occurred
245 */
246#define STATEREPORT_SETSTATE(state_buf, newStateIdx, changeTime)  \
247do {  \
248    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
249    IOStateReportValues *__rep;  \
250    if ((newStateIdx) < __info->elem[0].channel_type.nelements ) {  \
251        __rep = (IOStateReportValues*) &(__info->elem[__info->curr_state].values);  \
252        if (__info->update_ts)  \
253            __rep->upticks += (changeTime) - __info->update_ts;  \
254        __info->elem[(newStateIdx)].timestamp = (changeTime);  \
255        __rep = (IOStateReportValues*) &(__info->elem[(newStateIdx)].values);  \
256        __rep->intransitions++;  \
257        __info->curr_state = (newStateIdx);  \
258        __info->update_ts = (changeTime);  \
259    }  \
260} while(0)
261
262/*
263 * Prepare StateReport for UpdateReport call
264 *
265 *      void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
266 * uint64_t currentTime - current timestamp
267 *        void* ptr2cpy - filled in with pointer to buffer to be copied out
268 *      size_t size2cpy - filled in with the size of the buffer to copy out
269 */
270#define STATEREPORT_UPDATEPREP(state_buf, currentTime, ptr2cpy, size2cpy)  \
271do {  \
272    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
273    IOReportElement     *__elem;  \
274    IOStateReportValues *__state;  \
275    (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement);  \
276    (ptr2cpy) =  (void *) &__info->elem[0];  \
277    if (__info->update_ts)  {  \
278        __elem = &__info->elem[__info->curr_state];  \
279        __state = (IOStateReportValues *)&__elem->values;  \
280        __elem->timestamp = (currentTime);  \
281        __state->upticks  += (currentTime) - __info->update_ts;  \
282        __info->update_ts = (currentTime);  \
283    }  \
284} while(0)
285
286/*
287 * Updates the result field received as a parameter for kIOReportGetDimensions &
288 * kIOReportCopyChannelData actions.
289 *
290 *                void* state_buf - memory initialized by STATEREPORT_INIT()
291 * IOReportConfigureAction action - configure/updateReport() 'action'
292 *                   void* result - configure/updateReport() 'result'
293 */
294
295#define STATEREPORT_UPDATERES(state_buf, action, result)  \
296do {  \
297    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
298    IOReportElement     *__elem;  \
299    int *__nElements = (int *)(result);  \
300    if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) {  \
301        __elem =  &(__info->elem[0]);  \
302        *__nElements += __elem->channel_type.nelements;  \
303    }  \
304} while (0)
305
306
307
308/*
309 * Returns the channel id from the buffer previously initialized by STATEREPORT_INIT().
310 *
311 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
312 */
313
314#define STATEREPORT_GETCHID(state_buf)  \
315    (((IOStateReportInfo *)(state_buf))->elem[0].channel_id)
316
317/*
318 * Returns number of transitions occurred from the given state
319 *
320 *   void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
321 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
322 *
323 */
324
325#define STATEREPORT_GETTRANSITIONS(state_buf, stateIdx)  \
326    (((stateIdx) < ((IOStateReportInfo *)(state_buf))->elem[0].channel_type.nelements)  \
327        ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->intransitions  \
328        : kIOReportInvalidValue)
329
330/*
331 * Returns the total number of ticks spent in the given state.
332 *
333 *   void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
334 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
335 */
336
337#define STATEREPORT_GETTICKS(state_buf, stateIdx)  \
338    (((stateIdx) < ((IOStateReportInfo*)(state_buf))->elem[0].channel_type.nelements)  \
339        ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->upticks  \
340        : kIOReportInvalidValue)
341
342
343#define POLLUTE_BUF(buf, bufSize)  \
344do {  \
345    int __cnt = (bufSize)/sizeof(uint32_t);  \
346    while (--__cnt >= 0)  \
347        ((uint32_t*)(buf))[__cnt] = 0xbadcafe;  \
348} while (0)
349
350#ifdef __cplusplus
351}
352#endif
353
354#endif // _IOREPORT_MACROS_H_
355
356
357