1/*
2 * Copyright (c) 2012-2014 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#ifndef _IOREPORT_MACROS_H_
30#define _IOREPORT_MACROS_H_
31
32#include "IOReportTypes.h"
33#include <string.h>
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39#ifndef IOREPORT_ABORT
40#define IOREPORT_ABORT panic
41#endif
42
43/*
44 Background
45
46 These macros allow non-I/O Kit software to generate IOReporting
47 reports. Clients must prevent concurrent access to any given
48 report buffer from multiple threads.
49
50 While these macros allow non-I/O Kit software to participate
51 in IOReporting, an IOService instance must lend its driver ID,
52 respond to the appropriate IOService overrides, and shuttle
53 data back and forth. In some cases, it may be useful to have
54 the I/O Kit driver initialize the report buffer with the
55 appropriate macro.
56*/
57
58
59/* ----- Reporting Single Integers (SimpleReport) ----- */
60
61/*
62 * The buffer size required for a SimpleReport.
63 */
64
65#define SIMPLEREPORT_BUFSIZE (sizeof(IOReportElement))
66
67
68/*
69 * Initialize a buffer to hold a SimpleReport.
70 *
71 * void* buffer - ptr to SIMPLEREPORT_BUFSIZE bytes
72 * size_t bufSize - sanity check of buffer's size
73 * uint64_t providerID - registry Entry ID of the reporting service
74 * uint64_t channelID - the report's channel ID
75 * IOReportCategories categories - categories of this channel
76 *
77 * If the buffer is not of sufficient size, the macro calls IOREPORT_ABORT().
78 * If that returns, the buffer is left full of '&'.
79 */
80
81#define SIMPLEREPORT_INIT(buf, bufSize, providerID, channelID, cats) \
82do { \
83 memset((buf), '&', (bufSize)); \
84 IOReportElement *__elem = (IOReportElement *)(buf); \
85 IOSimpleReportValues *__vals; \
86 if ((bufSize) >= SIMPLEREPORT_BUFSIZE) { \
87 __elem->provider_id = (providerID); \
88 __elem->channel_id = (channelID); \
89 __elem->channel_type.report_format = kIOReportFormatSimple; \
90 __elem->channel_type.reserved = 0; \
91 __elem->channel_type.categories = (cats); \
92 __elem->channel_type.nelements = 1; \
93 __elem->channel_type.element_idx = 0; \
94 __elem->timestamp = 0; \
95 __vals = (IOSimpleReportValues*)&__elem->values; \
96 __vals->simple_value = kIOReportInvalidIntValue; \
97 } \
98 else { \
99 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
100 } \
101} while(0)
102
103
104/*
105 * Set a SimpleReport to a new value.
106 *
107 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
108 * int64_t new_value - new value for the report
109 */
110
111#define SIMPLEREPORT_SETVALUE(simp_buf, new_value) \
112do { \
113 IOReportElement *__elem = (IOReportElement *)(simp_buf); \
114 IOSimpleReportValues *__vals; \
115 __vals = (IOSimpleReportValues*)&__elem->values; \
116 __vals->simple_value = (new_value); \
117} while(0)
118
119
120/*
121 * Increment the value of a SimpleReport.
122 *
123 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
124 * int64_t increment - amount by which to increment the value
125 */
126#define SIMPLEREPORT_INCREMENTVALUE(simp_buf, new_value) \
127do { \
128 IOReportElement *__elem = (IOReportElement *)(simp_buf); \
129 IOSimpleReportValues *__vals; \
130 __vals = (IOSimpleReportValues*)&__elem->values; \
131 __vals->simple_value += (new_value); \
132} while(0)
133
134
135/*
136 * Prepare a SimpleReport for
137 * IOService::updateReport(kIOReportCopyChannelData...)
138 *
139 * void* simp_buf - Ptr to memory updated by SIMPLEREPORT_SETVALUE()
140 * void* ptr2cpy - On return, 'ptr2cpy' points to the memory that needs to be
141 * copied for kIOReportCopyChannelData.
142 * size_t size2cpy - On return, 'size2cpy' is set to the size of the report
143 * data that needs to be copied for kIOReportCopyChannelData.
144 */
145
146#define SIMPLEREPORT_UPDATEPREP(simp_buf, ptr2cpy, size2cpy) \
147do { \
148 (ptr2cpy) = (simp_buf); \
149 (size2cpy) = sizeof(IOReportElement); \
150} while(0)
151
152
153/*
154 * Update the result field received as a parameter for
155 * kIOReportGetDimensions & kIOReportCopyChannelData actions.
156 *
157 * IOReportConfigureAction action - configure/updateReport() 'action' param
158 * void* result - configure/updateReport() 'result' param
159 */
160
161#define SIMPLEREPORT_UPDATERES(action, result) \
162do { \
163 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
164 int *__nElements = (int *)(result); \
165 *__nElements += 1; \
166 } \
167} while (0)
168
169
170/*
171 * Get the 64-bit channel ID of a SimpleReport.
172 *
173 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
174 */
175
176#define SIMPLEREPORT_GETCHID(simp_buf) \
177 (((IOReportElement *)(simp_buf))->channel_id)
178
179/*
180 * Get the IOReportChannelType of a SimpleReport.
181 *
182 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
183 */
184
185#define SIMPLEREPORT_GETCHTYPE(simp_buf) \
186 (*(uint64_t*)&(((IOReportElement *)(simp_buf))->channel_type))
187
188
189/*
190 * Get the integer value of a SimpleReport.
191 *
192 * void* simp_buf - memory initialized by SIMPLEREPORT_INIT()
193 */
194
195#define SIMPLEREPORT_GETVALUE(simp_buf) \
196 (((IOSimpleReportValues*)&(((IOReportElement*)(simp_buf))->values)) \
197 ->simple_value)
198
199
200/* ----- State Machine Reporting (StateReport) ----- */
201
202// Internal struct for StateReport
203typedef struct {
204 uint16_t curr_state;
205 uint64_t update_ts;
206 IOReportElement elem[]; // Array of elements
207} IOStateReportInfo;
208
209/*
210 * Determine the size required for a StateReport buffer.
211 *
212 * int nstates - number of states to be reported
213 */
214#define STATEREPORT_BUFSIZE(nstates) \
215 (sizeof(IOStateReportInfo) + (nstates) * sizeof(IOReportElement))
216
217
218/*
219 * Initialize a StateReport buffer.
220 *
221 * int nstates - number of states to be reported
222 * void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes
223 * size_t bufSize - sanity check of buffer's size
224 * uint64_t providerID - registry Entry ID of the reporting service
225 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
226 * IOReportCategories categories - categories of this channel
227 *
228 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
229 * If that returns, the buffer is left full of '&'.
230 */
231#define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \
232do { \
233 memset((buf), '&', (bufSize)); \
234 IOStateReportInfo *__info = (IOStateReportInfo *)(buf); \
235 IOStateReportValues *__rep; \
236 IOReportElement *__elem; \
237 if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) { \
238 for (unsigned __no = 0; __no < (nstates); __no++) { \
239 __elem = &(__info->elem[__no]); \
240 __rep = (IOStateReportValues *) &(__elem->values); \
241 __elem->provider_id = (providerID); \
242 __elem->channel_id = (channelID); \
243 __elem->channel_type.report_format = kIOReportFormatState; \
244 __elem->channel_type.reserved = 0; \
245 __elem->channel_type.categories = (cats); \
246 __elem->channel_type.nelements = (nstates); \
247 __elem->channel_type.element_idx = __no; \
248 __elem->timestamp = 0; \
249 __rep->state_id = __no; \
250 __rep->intransitions = 0; \
251 __rep->upticks = 0; \
252 __rep->last_intransition = 0; \
253 } \
254 __info->curr_state = 0; \
255 __info->update_ts = 0; \
256 } \
257 else { \
258 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
259 } \
260} while(0)
261
262/*
263 * Initialize the state id field of a state with the specified value. By
264 * default, STATEREPORT_INIT() initializes the state IDs with the index of
265 * that state. This macro can be used to provide a more descriptive state id.
266 *
267 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
268 * unsigned stateIdx - index of the state, out of bounds -> no-op
269 * uint64_t stateID - new state id, see IOREPORT_MAKEID()
270 */
271#define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID) \
272do { \
273 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
274 IOStateReportValues *__rep; \
275 if ((stateIdx) < __info->elem[0].channel_type.nelements) { \
276 __rep = (IOStateReportValues*) &(__info->elem[(stateIdx)].values); \
277 __rep->state_id = (stateID); \
278 } \
279} while (0)
280
281
282/*
283 * Set the state of a StateReport.
284 *
285 * void* state_buf - pointer to memory initialized by STATEREPORT_INIT()
286 * unsigned newStateIdx - index of new state, out of bounds -> no-op
287 * uint64_t changeTime - time at which the transition occurred
288 */
289#define STATEREPORT_SETSTATE(state_buf, newStateIdx, changeTime) \
290do { \
291 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
292 IOStateReportValues *__rep; \
293 if ((newStateIdx) < __info->elem[0].channel_type.nelements ) { \
294 __rep = (IOStateReportValues*) &(__info->elem[__info->curr_state].values); \
295 if (__info->update_ts) \
296 __rep->upticks += (changeTime) - __info->update_ts; \
297 __info->elem[(newStateIdx)].timestamp = (changeTime); \
298 __rep = (IOStateReportValues*) &(__info->elem[(newStateIdx)].values); \
299 __rep->intransitions++; \
300 __info->curr_state = (newStateIdx); \
301 __info->update_ts = (changeTime); \
302 } \
303} while(0)
304
305/*
306 * Prepare a StateReport for
307 * IOService::updateReport(kIOReportCopyChannelData...)
308 *
309 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
310 * uint64_t currentTime - current timestamp
311 * void* ptr2cpy - filled in with pointer to buffer to be copied out
312 * size_t size2cpy - filled in with the size of the buffer to copy out
313 */
314#define STATEREPORT_UPDATEPREP(state_buf, currentTime, ptr2cpy, size2cpy) \
315do { \
316 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
317 IOReportElement *__elem; \
318 IOStateReportValues *__state; \
319 (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
320 (ptr2cpy) = (void *) &__info->elem[0]; \
321 if (__info->update_ts) { \
322 __elem = &__info->elem[__info->curr_state]; \
323 __state = (IOStateReportValues *)&__elem->values; \
324 __elem->timestamp = (currentTime); \
325 __state->upticks += (currentTime) - __info->update_ts; \
326 __info->update_ts = (currentTime); \
327 } \
328} while(0)
329
330/*
331 * Update the result field received as a parameter for kIOReportGetDimensions &
332 * kIOReportCopyChannelData actions.
333 *
334 * void* state_buf - memory initialized by STATEREPORT_INIT()
335 * IOReportConfigureAction action - configure/updateReport() 'action'
336 * void* result - configure/updateReport() 'result'
337 */
338
339#define STATEREPORT_UPDATERES(state_buf, action, result) \
340do { \
341 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
342 IOReportElement *__elem; \
343 int *__nElements = (int *)(result); \
344 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
345 __elem = &(__info->elem[0]); \
346 *__nElements += __elem->channel_type.nelements; \
347 } \
348} while (0)
349
350
351/*
352 * Get the 64-bit channel ID of a StateReport.
353 *
354 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
355 */
356#define STATEREPORT_GETCHID(state_buf) \
357 (((IOStateReportInfo *)(state_buf))->elem[0].channel_id)
358
359/*
360 * Get the IOReportChannelType of a StateReport.
361 *
362 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
363 */
364#define STATEREPORT_GETCHTYPE(state_buf) \
365 (*(uint64_t*)&(((IOStateReportInfo *)(state_buf))->elem[0].channel_type))
366
367/*
368 * Get the number of transitions into a given state.
369 *
370 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
371 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
372 *
373 */
374#define STATEREPORT_GETTRANSITIONS(state_buf, stateIdx) \
375 (((stateIdx) < ((IOStateReportInfo *)(state_buf))->elem[0].channel_type.nelements) \
376 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->intransitions \
377 : kIOReportInvalidValue)
378
379/*
380 * Get the total number of ticks spent in a given state.
381 *
382 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
383 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
384 */
385#define STATEREPORT_GETTICKS(state_buf, stateIdx) \
386 (((stateIdx) < ((IOStateReportInfo*)(state_buf))->elem[0].channel_type.nelements) \
387 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->upticks \
388 : kIOReportInvalidValue)
389
390
391/* ----- Reporting an Array of Integers (SimpleArrayReport) ----- */
392
393/*
394 * Determine the buffer size for a SimpleArrayReport.
395 *
396 * int nValues - number of values to be reported
397 */
398
399#define SIMPLEARRAY_BUFSIZE(nValues) \
400 ((((nValues)/IOR_VALUES_PER_ELEMENT) + (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1:0)) \
401 * sizeof(IOReportElement))
402
403/*
404 * Initialize a buffer for use as a SimpleArrayReport.
405 *
406 * int nValues - number of elements to be reported
407 * void* buf - ptr to SIMPLEARRAY_BUFSIZE(nValues) bytes
408 * size_t bufSize - sanity check of buffer's size
409 * uint64_t providerID - registry Entry ID of the reporting service
410 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
411 * IOReportCategories categories - categories of this channel
412 *
413 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT().
414 * If that returns, the buffer is left full of '&'.
415 */
416
417#define SIMPLEARRAY_INIT(nValues, buf, bufSize, providerID, channelID, cats) \
418do { \
419 memset((buf), '&', (bufSize)); \
420 IOSimpleArrayReportValues *__rep; \
421 IOReportElement *__elem; \
422 uint32_t __nElems = (((nValues) / IOR_VALUES_PER_ELEMENT) + \
423 (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1 : 0)); \
424 if ((bufSize) >= SIMPLEARRAY_BUFSIZE(nValues)) { \
425 for (unsigned __no = 0; __no < __nElems; __no++) { \
426 __elem = &(((IOReportElement *)(buf))[__no]); \
427 __rep = (IOSimpleArrayReportValues *) &(__elem->values); \
428 __elem->provider_id = (providerID); \
429 __elem->channel_id = (channelID); \
430 __elem->channel_type.report_format = kIOReportFormatSimpleArray; \
431 __elem->channel_type.reserved = 0; \
432 __elem->channel_type.categories = (cats); \
433 __elem->channel_type.nelements = (__nElems); \
434 __elem->channel_type.element_idx = __no; \
435 __elem->timestamp = 0; \
436 __rep->simple_values[0] = kIOReportInvalidIntValue; \
437 __rep->simple_values[1] = kIOReportInvalidIntValue; \
438 __rep->simple_values[2] = kIOReportInvalidIntValue; \
439 __rep->simple_values[3] = kIOReportInvalidIntValue; \
440 } \
441 } \
442 else { \
443 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
444 } \
445} while(0)
446
447
448/* SimpleArrayReport helpers */
449
450 #define __SA_FINDREP(array_buf, idx) \
451 IOSimpleArrayReportValues *__rep; \
452 IOReportElement *__elem; \
453 unsigned __elemIdx = (idx) / IOR_VALUES_PER_ELEMENT; \
454 unsigned __valueIdx = (idx) % IOR_VALUES_PER_ELEMENT; \
455 __elem = &(((IOReportElement *)(array_buf))[0]); \
456 if (__elemIdx < __elem->channel_type.nelements) { \
457 __elem = &(((IOReportElement *)(array_buf))[__elemIdx]); \
458 __rep = (IOSimpleArrayReportValues *) &(__elem->values); \
459
460 #define __SA_MAXINDEX(array_buf) \
461 ((((IOReportElement*)(array_buf))->channel_type.nelements) \
462 * IOR_VALUES_PER_ELEMENT) - 1
463
464/*
465 * Set a value at a specified index in a SimpleArrayReport.
466 *
467 * void* array_bufbuf - ptr to memory initialized by SIMPLEARRAY_INIT()
468 * unsigned idx - array index, out of bounds -> no-op
469 * uint64_t newValue - new value to be stored at array[idx]
470 */
471#define SIMPLEARRAY_SETVALUE(array_buf, idx, newValue) \
472do { \
473 __SA_FINDREP((array_buf), (idx)) \
474 __rep->simple_values[__valueIdx] = (newValue); \
475 } \
476} while(0)
477
478/*
479 * Increment an array value within a SimpleArrayReport.
480 *
481 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
482 * unsigned idx - array index to increment, out of bounds -> no-op
483 * int64_t value - amount by which to increment array[idx]
484 */
485#define SIMPLEARRAY_INCREMENTVALUE(array_buf, idx, value) \
486do { \
487 __SA_FINDREP((array_buf), (idx)) \
488 __rep->simple_values[__valueIdx] += (value); \
489 } \
490} while(0)
491
492
493/*
494 * Prepare a SimpleArrayReport for
495 * IOService::updateReport(kIOReportCopyChannelData...)
496 *
497 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
498 * void* ptr2cpy - filled in with pointer to buffer to be copied out
499 * size_t size2cpy - filled in with the size of the buffer to copy out
500 */
501
502#define SIMPLEARRAY_UPDATEPREP(array_buf, ptr2cpy, size2cpy) \
503do { \
504 IOReportElement *__elem; \
505 __elem = &(((IOReportElement *)(array_buf))[0]); \
506 (ptr2cpy) = (void *) (array_buf); \
507 (size2cpy) = __elem->channel_type.nelements * sizeof(IOReportElement); \
508} while(0)
509
510
511/*
512 * Update the result field received as a parameter for kIOReportGetDimensions &
513 * kIOReportCopyChannelData actions.
514 *
515 * void* array_buf - memory initialized by SIMPLEARRAY_INIT()
516 * IOReportConfigureAction action - configure/updateReport() 'action'
517 * void* result - configure/updateReport() 'result'
518 */
519
520#define SIMPLEARRAY_UPDATERES(array_buf, action, result) \
521do { \
522 IOReportElement *__elem; \
523 int *__nElements = (int *)(result); \
524 __elem = &(((IOReportElement *)(array_buf))[0]); \
525 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
526 *__nElements += __elem->channel_type.nelements; \
527 } \
528} while (0)
529
530
531/*
532 * Get the 64-bit channel ID of a SimpleArrayReport.
533 *
534 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
535 */
536#define SIMPLEARRAY_GETCHID(array_buf) \
537 (((IOReportElement *)(array_buf))->channel_id)
538
539
540/*
541 * Get the IOReportChannelType of a SimpleArrayReport.
542 *
543 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
544 */
545#define SIMPLEARRAY_GETCHTYPE(array_buf) \
546 (*(uint64_t*)&(((IOReportElement *)(array_buf))->channel_type))
547
548/*
549 * Get a value from a SimpleArrayReport.
550 *
551 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
552 * unsigned idx - index of the value, out of bounds -> kIOReportInvalidValue
553 */
554#define SIMPLEARRAY_GETVALUE(array_buf, idx) \
555 (((idx) > __SA_MAXINDEX(array_buf) || (idx) < 0) ? kIOReportInvalidIntValue : \
556 ((IOSimpleArrayReportValues*)&( \
557 ((IOReportElement*)(array_buf))[(idx) / IOR_VALUES_PER_ELEMENT].values)) \
558 ->simple_values[(idx) % IOR_VALUES_PER_ELEMENT])
559
560
561/* ----- Histogram Reporting (HistogramReport) ----- */
562
563// Internal struct for HistogramReport
564typedef struct {
565 int bucketWidth;
566 IOReportElement elem[]; // Array of elements
567} IOHistReportInfo;
568
569/*
570 * Determine the size required for a HistogramReport buffer.
571 *
572 * int nbuckets - number of buckets in the histogram
573 */
574#define HISTREPORT_BUFSIZE(nbuckets) \
575 (sizeof(IOHistReportInfo) + ((nbuckets) * sizeof(IOReportElement)))
576
577/*
578 * Initialize a HistogramReport buffer. Supports only linear scale histogram.
579 *
580 * int nbuckets - number of buckets data is combined into
581 * uint32_t bucketWidth - size of each bucket
582 * void* buffer - ptr to HISTREPORT_BUFSIZE(nbuckets) bytes
583 * size_t bufSize - sanity check of buffer's size
584 * uint64_t providerID - registry Entry ID of the reporting service
585 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
586 * IOReportCategories categories - categories of this channel
587 *
588 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
589 * If that returns, the buffer is left full of '&'.
590 */
591#define HISTREPORT_INIT(nbuckets, bktSize, buf, bufSize, providerID, channelID, cats) \
592do { \
593 memset((buf), '&', (bufSize)); \
594 IOHistReportInfo *__info = (IOHistReportInfo *)(buf); \
595 IOReportElement *__elem; \
596 IOHistogramReportValues *__rep; \
597 if ((bufSize) >= HISTREPORT_BUFSIZE(nbuckets)) { \
598 __info->bucketWidth = (bktSize); \
599 for (unsigned __no = 0; __no < (nbuckets); __no++) { \
600 __elem = &(__info->elem[__no]); \
601 __rep = (IOHistogramReportValues *) &(__elem->values); \
602 __elem->provider_id = (providerID); \
603 __elem->channel_id = (channelID); \
604 __elem->channel_type.report_format = kIOReportFormatHistogram; \
605 __elem->channel_type.reserved = 0; \
606 __elem->channel_type.categories = (cats); \
607 __elem->channel_type.nelements = (nbuckets); \
608 __elem->channel_type.element_idx = __no; \
609 __elem->timestamp = 0; \
610 memset(__rep, '\0', sizeof(IOHistogramReportValues)); \
611 } \
612 } \
613 else { \
614 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
615 } \
616} while (0)
617
618/*
619 * Update histogram with a new value.
620 *
621 *
622 * void* hist_buf - pointer to memory initialized by HISTREPORT_INIT()
623 * int64_t value - new value to add to the histogram
624 */
625#define HISTREPORT_TALLYVALUE(hist_buf, value) \
626do { \
627 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
628 IOReportElement *__elem; \
629 IOHistogramReportValues *__rep; \
630 for (unsigned __no = 0; __no < __info->elem[0].channel_type.nelements; __no++) { \
631 if ((value) <= __info->bucketWidth * (__no+1)) { \
632 __elem = &(__info->elem[__no]); \
633 __rep = (IOHistogramReportValues *) &(__elem->values); \
634 if (__rep->bucket_hits == 0) { \
635 __rep->bucket_min = __rep->bucket_max = (value); \
636 } \
637 else if ((value) < __rep->bucket_min) { \
638 __rep->bucket_min = (value); \
639 } \
640 else if ((value) > __rep->bucket_max) { \
641 __rep->bucket_max = (value); \
642 } \
643 __rep->bucket_sum += (value); \
644 __rep->bucket_hits++; \
645 break; \
646 } \
647 } \
648} while (0)
649
650/*
651 * Prepare a HistogramReport for
652 * IOService::updateReport(kIOReportCopyChannelData...)
653 *
654 * void* array_buf - ptr to memory initialized by HISTREPORT_INIT()
655 * void* ptr2cpy - filled in with pointer to buffer to be copied out
656 * size_t size2cpy - filled in with the size of the buffer to copy out
657 */
658
659#define HISTREPORT_UPDATEPREP(hist_buf, ptr2cpy, size2cpy) \
660do { \
661 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
662 (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
663 (ptr2cpy) = (void *) &__info->elem[0]; \
664} while(0)
665
666
667/*
668 * Update the result field received as a parameter for kIOReportGetDimensions &
669 * kIOReportCopyChannelData actions.
670 *
671 * void* array_buf - memory initialized by HISTREPORT_INIT()
672 * IOReportConfigureAction action - configure/updateReport() 'action'
673 * void* result - configure/updateReport() 'result'
674 */
675
676#define HISTREPORT_UPDATERES(hist_buf, action, result) \
677do { \
678 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
679 int *__nElements = (int *)(result); \
680 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
681 *__nElements += __info->elem[0].channel_type.nelements; \
682 } \
683} while (0)
684
685/*
686 * Get the 64-bit channel ID of a HistogramReport.
687 *
688 * void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
689 */
690#define HISTREPORT_GETCHID(hist_buf) \
691 (((IOHistReportInfo *)(hist_buf))->elem[0].channel_id)
692
693/*
694 * Get the IOReportChannelType of a HistogramReport.
695 *
696 * void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
697 */
698#define HISTREPORT_GETCHTYPE(hist_buf) \
699 (*(uint64_t*)&(((IOHistReportInfo *)(hist_buf))->elem[0].channel_type))
700
701#ifdef __cplusplus
702}
703#endif
704
705#endif // _IOREPORT_MACROS_H_
706
707
708