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