2 * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #define IOKIT_ENABLE_SHARED_PTR
31 #include <IOKit/IOKernelReportStructs.h>
32 #include <IOKit/IOKernelReporters.h>
33 #include "IOReporterDefs.h"
36 #include <IOKit/IORegistryEntry.h>
38 #define super OSObject
39 OSDefineMetaClassAndStructors(IOReporter
, OSObject
);
41 static OSSharedPtr
<const OSSymbol
> gIOReportNoChannelName
;
43 // * We might someday want an IOReportManager (vs. these static funcs)
45 /**************************************/
46 /*** STATIC METHODS ***/
47 /**************************************/
49 IOReporter::configureAllReports(OSSet
*reporters
,
50 IOReportChannelList
*channelList
,
51 IOReportConfigureAction action
,
55 IOReturn rval
= kIOReturnError
;
56 OSSharedPtr
<OSCollectionIterator
> iterator
;
58 if (reporters
== NULL
|| channelList
== NULL
|| result
== NULL
) {
59 rval
= kIOReturnBadArgument
;
64 case kIOReportGetDimensions
:
66 case kIOReportDisable
:
69 iterator
= OSCollectionIterator::withCollection(reporters
);
71 while ((object
= iterator
->getNextObject())) {
72 IOReporter
*rep
= OSDynamicCast(IOReporter
, object
);
75 (void)rep
->configureReport(channelList
, action
, result
, destination
);
77 rval
= kIOReturnUnsupported
; // kIOReturnNotFound?
85 case kIOReportTraceOnChange
:
86 case kIOReportNotifyHubOnChange
:
88 rval
= kIOReturnUnsupported
;
92 rval
= kIOReturnSuccess
;
98 // the duplication in these functions almost makes one want Objective-C SEL* ;)
100 IOReporter::updateAllReports(OSSet
*reporters
,
101 IOReportChannelList
*channelList
,
102 IOReportConfigureAction action
,
106 IOReturn rval
= kIOReturnError
;
107 OSSharedPtr
<OSCollectionIterator
> iterator
;
109 if (reporters
== NULL
||
110 channelList
== NULL
||
112 destination
== NULL
) {
113 rval
= kIOReturnBadArgument
;
118 case kIOReportCopyChannelData
:
121 iterator
= OSCollectionIterator::withCollection(reporters
);
123 while ((object
= iterator
->getNextObject())) {
124 IOReporter
*rep
= OSDynamicCast(IOReporter
, object
);
127 (void)rep
->updateReport(channelList
, action
, result
, destination
);
129 rval
= kIOReturnUnsupported
; // kIOReturnNotFound?
137 case kIOReportTraceChannelData
:
139 rval
= kIOReturnUnsupported
;
143 rval
= kIOReturnSuccess
;
150 /**************************************/
151 /*** COMMON INIT METHODS ***/
152 /**************************************/
155 IOReporter::init(IOService
*reportingService
,
156 IOReportChannelType channelType
,
159 bool success
= false;
161 // ::free() relies on these being initialized
162 _reporterLock
= NULL
;
165 _enableCounts
= NULL
;
166 _channelNames
= nullptr;
168 if (channelType
.report_format
== kIOReportInvalidFormat
) {
169 IORLOG("init ERROR: Channel Type ill-defined");
173 _driver_id
= reportingService
->getRegistryEntryID();
174 if (_driver_id
== 0) {
175 IORLOG("init() ERROR: no registry ID");
179 if (!super::init()) {
183 if (channelType
.nelements
> INT16_MAX
) {
186 _channelDimension
= channelType
.nelements
;
187 _channelType
= channelType
;
188 // FIXME: need to look up dynamically
189 if (unit
== kIOReportUnitHWTicks
) {
190 #if defined(__arm__) || defined(__arm64__)
191 unit
= kIOReportUnit24MHzTicks
;
192 #elif defined(__i386__) || defined(__x86_64__)
193 // Most, but not all Macs use 1GHz
194 unit
= kIOReportUnit1GHzTicks
;
196 #error kIOReportUnitHWTicks not defined
201 // Allocate a reporter (data) lock
202 _reporterLock
= IOSimpleLockAlloc();
203 if (!_reporterLock
) {
206 _reporterIsLocked
= false;
208 // Allocate a config lock
209 _configLock
= IOLockAlloc();
213 _reporterConfigIsLocked
= false;
215 // Allocate channel names array
216 _channelNames
= OSArray::withCapacity(1);
217 if (!_channelNames
) {
229 /*******************************/
230 /*** PUBLIC METHODS ***/
231 /*******************************/
234 IOReporter::initialize(void)
236 gIOReportNoChannelName
= OSSymbol::withCString("_NO_NAME_4");
239 // init() [possibly via init*()] must be called before free()
240 // to ensure that _<var> = NULL
242 IOReporter::free(void)
245 IOLockFree(_configLock
);
248 IOSimpleLockFree(_reporterLock
);
252 PREFL_MEMOP_PANIC(_nElements
, IOReportElement
);
253 IOFree(_elements
, (size_t)_nElements
* sizeof(IOReportElement
));
256 PREFL_MEMOP_PANIC(_nChannels
, int);
257 IOFree(_enableCounts
, (size_t)_nChannels
* sizeof(int));
264 #define TESTALLOC() do { \
266 * tbuf = IOMalloc(10); \
267 * IOFree(tbuf, 10); \
268 * IORLOG("%s:%d - _reporterIsLocked = %d & allocation successful", \
269 * __PRETTY_FUNCTION__, __LINE__, _reporterIsLocked); \
273 IOReporter::addChannel(uint64_t channelID
,
274 const char *channelName
/* = NULL */)
276 IOReturn res
= kIOReturnError
, kerr
;
277 OSSharedPtr
<const OSSymbol
> symChannelName
;
278 int oldNChannels
, newNChannels
= 0, freeNChannels
= 0;
280 IORLOG("IOReporter::addChannel %llx", channelID
);
282 // protect instance variables (but not contents)
283 lockReporterConfig();
285 // FIXME: Check if any channel is already present and return error
287 // addChannel() always adds one channel
288 oldNChannels
= _nChannels
;
289 if (oldNChannels
< 0 || oldNChannels
> INT_MAX
- 1) {
290 res
= kIOReturnOverrun
;
293 newNChannels
= oldNChannels
+ 1;
294 freeNChannels
= newNChannels
; // until swap success
296 // Expand addChannel()-specific data structure
297 if (_channelNames
->ensureCapacity((unsigned)newNChannels
) <
298 (unsigned)newNChannels
) {
299 res
= kIOReturnNoMemory
; goto finish
;
302 symChannelName
= OSSymbol::withCString(channelName
);
303 if (!symChannelName
) {
304 res
= kIOReturnNoMemory
; goto finish
;
307 // grab a reference to our shared global
308 symChannelName
= gIOReportNoChannelName
;
311 // allocate new buffers into _swap* variables
312 if ((kerr
= handleSwapPrepare(newNChannels
))) {
313 // on error, channels are *not* swapped
314 res
= kerr
; goto finish
;
317 // exchange main and _swap* buffers with buffer contents protected
318 // IOReporter::handleAddChannelSwap() also increments _nElements, etc
320 res
= handleAddChannelSwap(channelID
, symChannelName
.get());
322 // On failure, handleAddChannelSwap() leaves *new* buffers in _swap*.
323 // On success, it's the old buffers, so we put the right size in here.
324 if (res
== kIOReturnSuccess
) {
325 freeNChannels
= oldNChannels
;
329 // free up not-in-use buffers (tracked by _swap*)
330 handleSwapCleanup(freeNChannels
);
332 unlockReporterConfig();
338 OSSharedPtr
<IOReportLegendEntry
>
339 IOReporter::createLegend(void)
341 OSSharedPtr
<IOReportLegendEntry
> legendEntry
;
343 lockReporterConfig();
345 legendEntry
= handleCreateLegend();
347 unlockReporterConfig();
354 IOReporter::configureReport(IOReportChannelList
*channelList
,
355 IOReportConfigureAction action
,
359 IOReturn res
= kIOReturnError
;
361 lockReporterConfig();
363 res
= handleConfigureReport(channelList
, action
, result
, destination
);
365 unlockReporterConfig();
372 IOReporter::updateReport(IOReportChannelList
*channelList
,
373 IOReportConfigureAction action
,
377 IOReturn res
= kIOReturnError
;
381 res
= handleUpdateReport(channelList
, action
, result
, destination
);
389 /*******************************/
390 /*** PROTECTED METHODS ***/
391 /*******************************/
395 IOReporter::lockReporter()
397 _interruptState
= IOSimpleLockLockDisableInterrupt(_reporterLock
);
398 _reporterIsLocked
= true;
403 IOReporter::unlockReporter()
405 _reporterIsLocked
= false;
406 IOSimpleLockUnlockEnableInterrupt(_reporterLock
, _interruptState
);
410 IOReporter::lockReporterConfig()
412 IOLockLock(_configLock
);
413 _reporterConfigIsLocked
= true;
417 IOReporter::unlockReporterConfig()
419 _reporterConfigIsLocked
= false;
420 IOLockUnlock(_configLock
);
425 IOReporter::handleSwapPrepare(int newNChannels
)
427 IOReturn res
= kIOReturnError
;
429 size_t newElementsSize
, newECSize
;
431 // analyzer appeasement
432 newElementsSize
= newECSize
= 0;
434 //IORLOG("IOReporter::handleSwapPrepare");
436 IOREPORTER_CHECK_CONFIG_LOCK();
438 if (newNChannels
< _nChannels
) {
439 panic("%s doesn't support shrinking", __func__
);
441 if (newNChannels
<= 0 || _channelDimension
<= 0) {
442 res
= kIOReturnUnderrun
;
445 if (_swapElements
|| _swapEnableCounts
) {
446 panic("IOReporter::_swap* already in use");
449 // calculate the number of elements given #ch & the dimension of each
450 if (newNChannels
< 0 || newNChannels
> INT_MAX
/ _channelDimension
) {
451 res
= kIOReturnOverrun
;
454 newNElements
= newNChannels
* _channelDimension
;
456 // Allocate memory for the new array of report elements
457 PREFL_MEMOP_FAIL(newNElements
, IOReportElement
);
458 newElementsSize
= (size_t)newNElements
* sizeof(IOReportElement
);
459 _swapElements
= (IOReportElement
*)IOMalloc(newElementsSize
);
460 if (_swapElements
== NULL
) {
461 res
= kIOReturnNoMemory
; goto finish
;
463 memset(_swapElements
, 0, newElementsSize
);
465 // Allocate memory for the new array of channel watch counts
466 PREFL_MEMOP_FAIL(newNChannels
, int);
467 newECSize
= (size_t)newNChannels
* sizeof(int);
468 _swapEnableCounts
= (int *)IOMalloc(newECSize
);
469 if (_swapEnableCounts
== NULL
) {
470 res
= kIOReturnNoMemory
; goto finish
;
472 memset(_swapEnableCounts
, 0, newECSize
);
475 res
= kIOReturnSuccess
;
480 IOFree(_swapElements
, newElementsSize
);
481 _swapElements
= NULL
;
483 if (_swapEnableCounts
) {
484 IOFree(_swapEnableCounts
, newECSize
);
485 _swapEnableCounts
= NULL
;
494 IOReporter::handleAddChannelSwap(uint64_t channel_id
,
495 const OSSymbol
*symChannelName
)
497 IOReturn res
= kIOReturnError
;
499 int *tmpWatchCounts
= NULL
;
500 IOReportElement
*tmpElements
= NULL
;
501 bool swapComplete
= false;
503 //IORLOG("IOReporter::handleSwap");
505 IOREPORTER_CHECK_CONFIG_LOCK();
506 IOREPORTER_CHECK_LOCK();
508 if (!_swapElements
|| !_swapEnableCounts
) {
509 IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!");
513 // Copy any existing elements to the new location
514 //IORLOG("handleSwap (base) -> copying %u elements over...", _nChannels);
516 PREFL_MEMOP_PANIC(_nElements
, IOReportElement
);
517 memcpy(_swapElements
, _elements
,
518 (size_t)_nElements
* sizeof(IOReportElement
));
520 PREFL_MEMOP_PANIC(_nElements
, int);
521 memcpy(_swapEnableCounts
, _enableCounts
,
522 (size_t)_nChannels
* sizeof(int));
525 // Update principal instance variables, keep old buffers for cleanup
526 tmpElements
= _elements
;
527 _elements
= _swapElements
;
528 _swapElements
= tmpElements
;
530 tmpWatchCounts
= _enableCounts
;
531 _enableCounts
= _swapEnableCounts
;
532 _swapEnableCounts
= tmpWatchCounts
;
536 // but _nChannels & _nElements is still the old (one smaller) size
538 // Initialize new element metadata (existing elements copied above)
539 for (cnt
= 0; cnt
< _channelDimension
; cnt
++) {
540 _elements
[_nElements
+ cnt
].channel_id
= channel_id
;
541 _elements
[_nElements
+ cnt
].provider_id
= _driver_id
;
542 _elements
[_nElements
+ cnt
].channel_type
= _channelType
;
543 _elements
[_nElements
+ cnt
].channel_type
.element_idx
= ((int16_t) cnt
);
545 //IOREPORTER_DEBUG_ELEMENT(_swapNElements + cnt);
548 // Store a channel name at the end
549 if (!_channelNames
->setObject((unsigned)_nChannels
, symChannelName
)) {
550 // Should never happen because we ensured capacity in addChannel()
551 res
= kIOReturnNoMemory
;
555 // And update the metadata: addChannel() always adds just one channel
557 _nElements
+= _channelDimension
;
560 res
= kIOReturnSuccess
;
563 if (res
&& swapComplete
) {
564 // unswap so new buffers get cleaned up instead of old
565 tmpElements
= _elements
;
566 _elements
= _swapElements
;
567 _swapElements
= tmpElements
;
569 tmpWatchCounts
= _enableCounts
;
570 _enableCounts
= _swapEnableCounts
;
571 _swapEnableCounts
= tmpWatchCounts
;
577 IOReporter::handleSwapCleanup(int swapNChannels
)
581 if (!_channelDimension
|| swapNChannels
> INT_MAX
/ _channelDimension
) {
582 panic("%s - can't free %d channels of dimension %d", __func__
,
583 swapNChannels
, _channelDimension
);
585 swapNElements
= swapNChannels
* _channelDimension
;
587 IOREPORTER_CHECK_CONFIG_LOCK();
589 // release buffers no longer used after swapping
591 PREFL_MEMOP_PANIC(swapNElements
, IOReportElement
);
592 IOFree(_swapElements
, (size_t)swapNElements
* sizeof(IOReportElement
));
593 _swapElements
= NULL
;
595 if (_swapEnableCounts
) {
596 PREFL_MEMOP_PANIC(swapNChannels
, int);
597 IOFree(_swapEnableCounts
, (size_t)swapNChannels
* sizeof(int));
598 _swapEnableCounts
= NULL
;
603 // The reporter wants to know if its channels have observers.
604 // Eventually we'll add some sort of bool ::anyChannelsInUse() which
605 // clients can use to cull unused reporters after configureReport(disable).
607 IOReporter::handleConfigureReport(IOReportChannelList
*channelList
,
608 IOReportConfigureAction action
,
612 IOReturn res
= kIOReturnError
;
613 int channel_index
= 0;
615 int *nElements
, *nChannels
;
617 // Check on channelList and result because used below
618 if (!channelList
|| !result
) {
622 //IORLOG("IOReporter::configureReport action %u for %u channels",
623 // action, channelList->nchannels);
625 // Make sure channel is present, increase matching watch count, 'result'
626 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
627 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
628 &channel_index
) == kIOReturnSuccess
) {
629 // IORLOG("reporter %p recognizes channel %lld", this, channelList->channels[chIdx].channel_id);
632 case kIOReportEnable
:
633 nChannels
= (int*)result
;
635 _enableCounts
[channel_index
]++;
639 case kIOReportDisable
:
640 nChannels
= (int*)result
;
642 _enableCounts
[channel_index
]--;
646 case kIOReportGetDimensions
:
647 nElements
= (int *)result
;
648 *nElements
+= _channelDimension
;
652 IORLOG("ERROR configureReport unknown action!");
659 res
= kIOReturnSuccess
;
667 IOReporter::handleUpdateReport(IOReportChannelList
*channelList
,
668 IOReportConfigureAction action
,
672 IOReturn res
= kIOReturnError
;
673 int *nElements
= (int *)result
;
674 int channel_index
= 0;
676 IOBufferMemoryDescriptor
*dest
;
678 if (!channelList
|| !result
|| !destination
) {
682 dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
684 // Invalid destination
685 res
= kIOReturnBadArgument
;
693 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
694 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
695 &channel_index
) == kIOReturnSuccess
) {
696 //IORLOG("%s - found channel_id %llx @ index %d", __func__,
697 // channelList->channels[chIdx].channel_id,
701 case kIOReportCopyChannelData
:
702 res
= updateChannelValues(channel_index
);
704 IORLOG("ERROR: updateChannelValues() failed: %x", res
);
708 res
= updateReportChannel(channel_index
, nElements
, dest
);
710 IORLOG("ERROR: updateReportChannel() failed: %x", res
);
716 IORLOG("ERROR updateReport unknown action!");
717 res
= kIOReturnError
;
724 res
= kIOReturnSuccess
;
731 OSSharedPtr
<IOReportLegendEntry
>
732 IOReporter::handleCreateLegend(void)
734 OSSharedPtr
<IOReportLegendEntry
> legendEntry
= nullptr;
735 OSSharedPtr
<OSArray
> channelIDs
;
737 channelIDs
= copyChannelIDs();
740 legendEntry
= IOReporter::legendWith(channelIDs
.get(), _channelNames
.get(), _channelType
, _unit
);
748 IOReporter::setElementValues(int element_index
,
749 IOReportElementValues
*values
,
750 uint64_t record_time
/* = 0 */)
752 IOReturn res
= kIOReturnError
;
754 IOREPORTER_CHECK_LOCK();
756 if (record_time
== 0) {
757 record_time
= mach_absolute_time();
760 if (element_index
>= _nElements
|| values
== NULL
) {
761 res
= kIOReturnBadArgument
;
765 memcpy(&_elements
[element_index
].values
, values
, sizeof(IOReportElementValues
));
767 _elements
[element_index
].timestamp
= record_time
;
769 //IOREPORTER_DEBUG_ELEMENT(index);
771 res
= kIOReturnSuccess
;
778 const IOReportElementValues
*
779 IOReporter::getElementValues(int element_index
)
781 IOReportElementValues
*elementValues
= NULL
;
783 IOREPORTER_CHECK_LOCK();
785 if (element_index
< 0 || element_index
>= _nElements
) {
786 IORLOG("ERROR getElementValues out of bounds!");
790 elementValues
= &_elements
[element_index
].values
;
793 return elementValues
;
798 IOReporter::updateChannelValues(int channel_index
)
800 return kIOReturnSuccess
;
805 IOReporter::updateReportChannel(int channel_index
,
807 IOBufferMemoryDescriptor
*destination
)
809 IOReturn res
= kIOReturnError
;
810 int start_element_idx
, chElems
;
813 res
= kIOReturnBadArgument
;
814 if (!nElements
|| !destination
) {
817 if (channel_index
> _nChannels
) {
821 IOREPORTER_CHECK_LOCK();
823 res
= kIOReturnOverrun
;
825 start_element_idx
= channel_index
* _channelDimension
;
826 if (start_element_idx
>= _nElements
) {
830 chElems
= _elements
[start_element_idx
].channel_type
.nelements
;
832 // make sure we don't go beyond the end of _elements[_nElements-1]
833 if (start_element_idx
+ chElems
> _nElements
) {
837 PREFL_MEMOP_FAIL(chElems
, IOReportElement
);
838 size2cpy
= (size_t)chElems
* sizeof(IOReportElement
);
840 // make sure there's space in the destination
841 if (size2cpy
> (destination
->getCapacity() - destination
->getLength())) {
842 IORLOG("CRITICAL ERROR: Report Buffer Overflow (buffer cap %luB, length %luB, size2cpy %luB",
843 (unsigned long)destination
->getCapacity(),
844 (unsigned long)destination
->getLength(),
845 (unsigned long)size2cpy
);
849 destination
->appendBytes(&_elements
[start_element_idx
], size2cpy
);
850 *nElements
+= chElems
;
852 res
= kIOReturnSuccess
;
860 IOReporter::copyElementValues(int element_index
,
861 IOReportElementValues
*elementValues
)
863 IOReturn res
= kIOReturnError
;
865 if (!elementValues
) {
869 IOREPORTER_CHECK_LOCK();
871 if (element_index
>= _nElements
) {
872 IORLOG("ERROR getElementValues out of bounds!");
873 res
= kIOReturnBadArgument
;
877 memcpy(elementValues
, &_elements
[element_index
].values
, sizeof(IOReportElementValues
));
878 res
= kIOReturnSuccess
;
886 IOReporter::getFirstElementIndex(uint64_t channel_id
,
889 IOReturn res
= kIOReturnError
;
890 int channel_index
= 0, element_index
= 0;
896 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
898 if (res
== kIOReturnSuccess
) {
899 *index
= element_index
;
908 IOReporter::getChannelIndex(uint64_t channel_id
,
911 IOReturn res
= kIOReturnError
;
912 int channel_index
= 0, element_index
= 0;
918 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
920 if (res
== kIOReturnSuccess
) {
921 *index
= channel_index
;
930 IOReporter::getChannelIndices(uint64_t channel_id
,
934 IOReturn res
= kIOReturnNotFound
;
937 if (!channel_index
|| !element_index
) {
941 for (chIdx
= 0; chIdx
< _nChannels
; chIdx
++) {
942 elemIdx
= chIdx
* _channelDimension
;
943 if (elemIdx
>= _nElements
) {
944 IORLOG("ERROR getChannelIndices out of bounds!");
945 res
= kIOReturnOverrun
;
949 if (channel_id
== _elements
[elemIdx
].channel_id
) {
950 // The channel index does not care about the depth of elements...
951 *channel_index
= chIdx
;
952 *element_index
= elemIdx
;
954 res
= kIOReturnSuccess
;
963 /********************************/
964 /*** PRIVATE METHODS ***/
965 /********************************/
968 // copyChannelIDs relies on the caller to take lock
970 IOReporter::copyChannelIDs()
973 OSSharedPtr
<OSArray
> channelIDs
;
974 OSSharedPtr
<OSNumber
> tmpNum
;
976 channelIDs
= OSArray::withCapacity((unsigned)_nChannels
);
982 for (cnt
= 0; cnt
< _nChannels
; cnt
++) {
983 cnt2
= cnt
* _channelDimension
;
985 // Encapsulate the Channel ID in OSNumber
986 tmpNum
= OSNumber::withNumber(_elements
[cnt2
].channel_id
, 64);
988 IORLOG("ERROR: Could not create array of channelIDs");
992 channelIDs
->setObject((unsigned)cnt
, tmpNum
.get());
1000 // DO NOT REMOVE THIS METHOD WHICH IS THE MAIN LEGEND CREATION FUNCTION
1001 /*static */ OSSharedPtr
<IOReportLegendEntry
>
1002 IOReporter::legendWith(OSArray
*channelIDs
,
1003 OSArray
*channelNames
,
1004 IOReportChannelType channelType
,
1007 unsigned int cnt
, chCnt
;
1009 OSSharedPtr
<OSNumber
> tmpNum
;
1010 const OSSymbol
*tmpSymbol
;
1011 OSSharedPtr
<OSArray
> channelLegendArray
;
1012 OSSharedPtr
<OSArray
> tmpChannelArray
;
1013 OSSharedPtr
<OSDictionary
> channelInfoDict
;
1014 OSSharedPtr
<IOReportLegendEntry
> legendEntry
= nullptr;
1016 // No need to check validity of channelNames because param is optional
1020 chCnt
= channelIDs
->getCount();
1022 channelLegendArray
= OSArray::withCapacity(chCnt
);
1024 for (cnt
= 0; cnt
< chCnt
; cnt
++) {
1025 tmpChannelArray
= OSArray::withCapacity(3);
1027 // Encapsulate the Channel ID in OSNumber
1028 tmpChannelArray
->setObject(kIOReportChannelIDIdx
, channelIDs
->getObject(cnt
));
1030 // Encapsulate the Channel Type in OSNumber
1031 memcpy(&type64
, &channelType
, sizeof(type64
));
1032 tmpNum
= OSNumber::withNumber(type64
, 64);
1036 tmpChannelArray
->setObject(kIOReportChannelTypeIdx
, tmpNum
.get());
1039 // Encapsulate the Channel Name in OSSymbol
1040 // Use channelNames if provided
1041 if (channelNames
!= NULL
) {
1042 tmpSymbol
= OSDynamicCast(OSSymbol
, channelNames
->getObject(cnt
));
1043 if (tmpSymbol
&& tmpSymbol
!= gIOReportNoChannelName
) {
1044 tmpChannelArray
->setObject(kIOReportChannelNameIdx
, tmpSymbol
);
1045 } // Else, skip and leave name field empty
1048 channelLegendArray
->setObject(cnt
, tmpChannelArray
.get());
1049 tmpChannelArray
.reset();
1052 // Stuff the legend entry only if we have channels...
1053 if (channelLegendArray
->getCount() != 0) {
1054 channelInfoDict
= OSDictionary::withCapacity(1);
1056 if (!channelInfoDict
) {
1060 tmpNum
= OSNumber::withNumber(unit
, 64);
1062 channelInfoDict
->setObject(kIOReportLegendUnitKey
, tmpNum
.get());
1065 legendEntry
= OSDictionary::withCapacity(1);
1068 legendEntry
->setObject(kIOReportLegendChannelsKey
, channelLegendArray
.get());
1069 legendEntry
->setObject(kIOReportLegendInfoKey
, channelInfoDict
.get());