]>
Commit | Line | Data |
---|---|---|
39236c6e A |
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 | |
37 | extern "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) \ | |
74 | do { \ | |
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) \ | |
104 | do { \ | |
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) \ | |
122 | do { \ | |
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) \ | |
137 | do { \ | |
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 | |
159 | typedef 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) \ | |
189 | do { \ | |
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) \ | |
229 | do { \ | |
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) \ | |
247 | do { \ | |
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) \ | |
271 | do { \ | |
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) \ | |
296 | do { \ | |
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) \ | |
344 | do { \ | |
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 |