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