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