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 #include <IOKit/IOKernelReportStructs.h>
30 #include <IOKit/IOKernelReporters.h>
31 #include "IOReporterDefs.h"
34 #include <IOKit/IORegistryEntry.h>
36 #define super OSObject
37 OSDefineMetaClassAndStructors(IOReporter
, OSObject
);
39 // be careful to retain and release as necessary
40 static const OSSymbol
*gIOReportNoChannelName
= OSSymbol::withCString("_NO_NAME_4");
42 // * We might someday want an IOReportManager (vs. these static funcs)
44 /**************************************/
45 /*** STATIC METHODS ***/
46 /**************************************/
48 IOReporter::configureAllReports(OSSet
*reporters
,
49 IOReportChannelList
*channelList
,
50 IOReportConfigureAction action
,
54 IOReturn rval
= kIOReturnError
;
55 OSCollectionIterator
*iterator
= NULL
;
57 if (reporters
== NULL
|| channelList
== NULL
|| result
== NULL
) {
58 rval
= kIOReturnBadArgument
;
64 case kIOReportGetDimensions
:
66 case kIOReportDisable
:
69 iterator
= OSCollectionIterator::withCollection(reporters
);
71 while ((object
= iterator
->getNextObject())) {
73 IOReporter
*rep
= OSDynamicCast(IOReporter
, object
);
76 (void)rep
->configureReport(channelList
, action
, result
, destination
);
78 rval
= kIOReturnUnsupported
; // kIOReturnNotFound?
86 case kIOReportTraceOnChange
:
87 case kIOReportNotifyHubOnChange
:
89 rval
= kIOReturnUnsupported
;
93 rval
= kIOReturnSuccess
;
96 if (iterator
) iterator
->release();
101 // the duplication in these functions almost makes one want Objective-C SEL* ;)
103 IOReporter::updateAllReports(OSSet
*reporters
,
104 IOReportChannelList
*channelList
,
105 IOReportConfigureAction action
,
109 IOReturn rval
= kIOReturnError
;
110 OSCollectionIterator
*iterator
= NULL
;
112 if (reporters
== NULL
||
113 channelList
== NULL
||
115 destination
== NULL
) {
116 rval
= kIOReturnBadArgument
;
122 case kIOReportCopyChannelData
:
125 iterator
= OSCollectionIterator::withCollection(reporters
);
127 while ((object
= iterator
->getNextObject())) {
129 IOReporter
*rep
= OSDynamicCast(IOReporter
, object
);
132 (void)rep
->updateReport(channelList
, action
, result
, destination
);
134 rval
= kIOReturnUnsupported
; // kIOReturnNotFound?
142 case kIOReportTraceChannelData
:
144 rval
= kIOReturnUnsupported
;
148 rval
= kIOReturnSuccess
;
151 if (iterator
) iterator
->release();
157 /**************************************/
158 /*** COMMON INIT METHODS ***/
159 /**************************************/
162 IOReporter::init(IOService
*reportingService
,
163 IOReportChannelType channelType
,
166 bool success
= false;
168 // ::free() relies on these being initialized
169 _reporterLock
= NULL
;
172 _enableCounts
= NULL
;
173 _channelNames
= NULL
;
175 if (channelType
.report_format
== kIOReportInvalidFormat
) {
176 IORLOG("init ERROR: Channel Type ill-defined");
180 _driver_id
= reportingService
->getRegistryEntryID();
181 if (_driver_id
== 0) {
182 IORLOG("init() ERROR: no registry ID");
186 if (!super::init()) return false;
188 _channelDimension
= channelType
.nelements
;
189 _channelType
= channelType
;
190 // FIXME: need to look up dynamically
191 if (unit
== kIOReportUnitHWTicks
) {
192 #if 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
) goto finish
;
204 _reporterIsLocked
= false;
206 // Allocate a config lock
207 _configLock
= IOLockAlloc();
208 if (!_configLock
) goto finish
;
209 _reporterConfigIsLocked
= false;
211 // Allocate channel names array
212 _channelNames
= OSArray::withCapacity(1);
213 if (!_channelNames
) goto finish
;
220 if (_configLock
) IOLockFree(_configLock
);
221 if (_reporterLock
) IOSimpleLockFree(_reporterLock
);
222 if (_channelNames
) _channelNames
->release();
229 /*******************************/
230 /*** PUBLIC METHODS ***/
231 /*******************************/
233 // init() [possibly via init*()] must be called before free()
234 // to ensure that _<var> = NULL
236 IOReporter::free(void)
238 if (_configLock
) IOLockFree(_configLock
);
239 if (_reporterLock
) IOSimpleLockFree(_reporterLock
);
242 PREFL_MEMOP_PANIC(_nElements
, IOReportElement
);
243 IOFree(_elements
, (size_t)_nElements
* sizeof(IOReportElement
));
246 PREFL_MEMOP_PANIC(_nChannels
, int);
247 IOFree(_enableCounts
, (size_t)_nChannels
* sizeof(int));
254 #define TESTALLOC() do { \
256 tbuf = IOMalloc(10); \
258 IORLOG("%s:%d - _reporterIsLocked = %d & allocation successful", \
259 __PRETTY_FUNCTION__, __LINE__, _reporterIsLocked); \
263 IOReporter::addChannel(uint64_t channelID
,
264 const char *channelName
/* = NULL */)
266 IOReturn res
= kIOReturnError
, kerr
;
267 const OSSymbol
*symChannelName
= NULL
;
268 int oldNChannels
, newNChannels
= 0, freeNChannels
= 0;
270 IORLOG("IOReporter::addChannel %llx", channelID
);
272 // protect instance variables (but not contents)
273 lockReporterConfig();
275 // FIXME: Check if any channel is already present and return error
277 // addChannel() always adds one channel
278 oldNChannels
= _nChannels
;
279 if (oldNChannels
< 0 || oldNChannels
> INT_MAX
- 1) {
280 res
= kIOReturnOverrun
;
283 newNChannels
= oldNChannels
+ 1;
284 freeNChannels
= newNChannels
; // until swap success
286 // Expand addChannel()-specific data structure
287 if (_channelNames
->ensureCapacity((unsigned)newNChannels
) <
288 (unsigned)newNChannels
) {
289 res
= kIOReturnNoMemory
; goto finish
;
292 symChannelName
= OSSymbol::withCString(channelName
);
293 if (!symChannelName
) {
294 res
= kIOReturnNoMemory
; goto finish
;
297 // grab a reference to our shared global
298 symChannelName
= gIOReportNoChannelName
;
299 symChannelName
->retain();
302 // allocate new buffers into _swap* variables
303 if ((kerr
= handleSwapPrepare(newNChannels
))) {
304 // on error, channels are *not* swapped
305 res
= kerr
; goto finish
;
308 // exchange main and _swap* buffers with buffer contents protected
309 // IOReporter::handleAddChannelSwap() also increments _nElements, etc
311 res
= handleAddChannelSwap(channelID
, symChannelName
);
313 // On failure, handleAddChannelSwap() leaves *new* buffers in _swap*.
314 // On success, it's the old buffers, so we put the right size in here.
315 if (res
== kIOReturnSuccess
) {
316 freeNChannels
= oldNChannels
;
320 // free up not-in-use buffers (tracked by _swap*)
321 handleSwapCleanup(freeNChannels
);
322 if (symChannelName
) symChannelName
->release();
323 unlockReporterConfig();
330 IOReporter::createLegend(void)
332 IOReportLegendEntry
*legendEntry
= NULL
;
334 lockReporterConfig();
336 legendEntry
= handleCreateLegend();
338 unlockReporterConfig();
345 IOReporter::configureReport(IOReportChannelList
*channelList
,
346 IOReportConfigureAction action
,
350 IOReturn res
= kIOReturnError
;
352 lockReporterConfig();
354 res
= handleConfigureReport(channelList
, action
, result
, destination
);
356 unlockReporterConfig();
364 IOReporter::updateReport(IOReportChannelList
*channelList
,
365 IOReportConfigureAction action
,
369 IOReturn res
= kIOReturnError
;
373 res
= handleUpdateReport(channelList
, action
, result
, destination
);
382 /*******************************/
383 /*** PROTECTED METHODS ***/
384 /*******************************/
388 IOReporter::lockReporter()
390 _interruptState
= IOSimpleLockLockDisableInterrupt(_reporterLock
);
391 _reporterIsLocked
= true;
396 IOReporter::unlockReporter()
398 _reporterIsLocked
= false;
399 IOSimpleLockUnlockEnableInterrupt(_reporterLock
, _interruptState
);
403 IOReporter::lockReporterConfig()
405 IOLockLock(_configLock
);
406 _reporterConfigIsLocked
= true;
410 IOReporter::unlockReporterConfig()
412 _reporterConfigIsLocked
= false;
413 IOLockUnlock(_configLock
);
418 IOReporter::handleSwapPrepare(int newNChannels
)
420 IOReturn res
= kIOReturnError
;
422 size_t newElementsSize
, newECSize
;
424 // analyzer appeasement
425 newElementsSize
= newECSize
= 0;
427 //IORLOG("IOReporter::handleSwapPrepare");
429 IOREPORTER_CHECK_CONFIG_LOCK();
431 if (newNChannels
< _nChannels
) {
432 panic("%s doesn't support shrinking", __func__
);
434 if (newNChannels
<= 0 || _channelDimension
<= 0) {
435 res
= kIOReturnUnderrun
;
438 if (_swapElements
|| _swapEnableCounts
) {
439 panic("IOReporter::_swap* already in use");
442 // calculate the number of elements given #ch & the dimension of each
443 if (newNChannels
< 0 || newNChannels
> INT_MAX
/ _channelDimension
) {
444 res
= kIOReturnOverrun
;
447 newNElements
= newNChannels
* _channelDimension
;
449 // Allocate memory for the new array of report elements
450 PREFL_MEMOP_FAIL(newNElements
, IOReportElement
);
451 newElementsSize
= (size_t)newNElements
* sizeof(IOReportElement
);
452 _swapElements
= (IOReportElement
*)IOMalloc(newElementsSize
);
453 if (_swapElements
== NULL
) {
454 res
= kIOReturnNoMemory
; goto finish
;
456 memset(_swapElements
, 0, newElementsSize
);
458 // Allocate memory for the new array of channel watch counts
459 PREFL_MEMOP_FAIL(newNChannels
, int);
460 newECSize
= (size_t)newNChannels
* sizeof(int);
461 _swapEnableCounts
= (int *)IOMalloc(newECSize
);
462 if (_swapEnableCounts
== NULL
){
463 res
= kIOReturnNoMemory
; goto finish
;
465 memset(_swapEnableCounts
, 0, newECSize
);
468 res
= kIOReturnSuccess
;
473 IOFree(_swapElements
, newElementsSize
);
474 _swapElements
= NULL
;
476 if (_swapEnableCounts
) {
477 IOFree(_swapEnableCounts
, newECSize
);
478 _swapEnableCounts
= NULL
;
487 IOReporter::handleAddChannelSwap(uint64_t channel_id
,
488 const OSSymbol
*symChannelName
)
490 IOReturn res
= kIOReturnError
;
492 int *tmpWatchCounts
= NULL
;
493 IOReportElement
*tmpElements
= NULL
;
494 bool swapComplete
= false;
496 //IORLOG("IOReporter::handleSwap");
498 IOREPORTER_CHECK_CONFIG_LOCK();
499 IOREPORTER_CHECK_LOCK();
501 if (!_swapElements
|| !_swapEnableCounts
) {
502 IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!");
506 // Copy any existing elements to the new location
507 //IORLOG("handleSwap (base) -> copying %u elements over...", _nChannels);
509 PREFL_MEMOP_PANIC(_nElements
, IOReportElement
);
510 memcpy(_swapElements
, _elements
,
511 (size_t)_nElements
* sizeof(IOReportElement
));
513 PREFL_MEMOP_PANIC(_nElements
, int);
514 memcpy(_swapEnableCounts
, _enableCounts
,
515 (size_t)_nChannels
* sizeof(int));
518 // Update principal instance variables, keep old buffers for cleanup
519 tmpElements
= _elements
;
520 _elements
= _swapElements
;
521 _swapElements
= tmpElements
;
523 tmpWatchCounts
= _enableCounts
;
524 _enableCounts
= _swapEnableCounts
;
525 _swapEnableCounts
= tmpWatchCounts
;
529 // but _nChannels & _nElements is still the old (one smaller) size
531 // Initialize new element metadata (existing elements copied above)
532 for (cnt
= 0; cnt
< _channelDimension
; cnt
++) {
534 _elements
[_nElements
+ cnt
].channel_id
= channel_id
;
535 _elements
[_nElements
+ cnt
].provider_id
= _driver_id
;
536 _elements
[_nElements
+ cnt
].channel_type
= _channelType
;
537 _elements
[_nElements
+ cnt
].channel_type
.element_idx
= cnt
;
539 //IOREPORTER_DEBUG_ELEMENT(_swapNElements + cnt);
542 // Store a channel name at the end
543 if (!_channelNames
->setObject((unsigned)_nChannels
, symChannelName
)) {
544 // Should never happen because we ensured capacity in addChannel()
545 res
= kIOReturnNoMemory
;
549 // And update the metadata: addChannel() always adds just one channel
551 _nElements
+= _channelDimension
;
554 res
= kIOReturnSuccess
;
557 if (res
&& swapComplete
) {
558 // unswap so new buffers get cleaned up instead of old
559 tmpElements
= _elements
;
560 _elements
= _swapElements
;
561 _swapElements
= tmpElements
;
563 tmpWatchCounts
= _enableCounts
;
564 _enableCounts
= _swapEnableCounts
;
565 _swapEnableCounts
= tmpWatchCounts
;
571 IOReporter::handleSwapCleanup(int swapNChannels
)
575 if (!_channelDimension
|| swapNChannels
> INT_MAX
/ _channelDimension
) {
576 panic("%s - can't free %d channels of dimension %d", __func__
,
577 swapNChannels
, _channelDimension
);
579 swapNElements
= swapNChannels
* _channelDimension
;
581 IOREPORTER_CHECK_CONFIG_LOCK();
583 // release buffers no longer used after swapping
585 PREFL_MEMOP_PANIC(swapNElements
, IOReportElement
);
586 IOFree(_swapElements
, (size_t)swapNElements
* sizeof(IOReportElement
));
587 _swapElements
= NULL
;
589 if (_swapEnableCounts
) {
590 PREFL_MEMOP_PANIC(swapNChannels
, int);
591 IOFree(_swapEnableCounts
, (size_t)swapNChannels
* sizeof(int));
592 _swapEnableCounts
= NULL
;
597 // The reporter wants to know if its channels have observers.
598 // Eventually we'll add some sort of bool ::anyChannelsInUse() which
599 // clients can use to cull unused reporters after configureReport(disable).
601 IOReporter::handleConfigureReport(IOReportChannelList
*channelList
,
602 IOReportConfigureAction action
,
606 IOReturn res
= kIOReturnError
;
607 int channel_index
= 0;
609 int *nElements
, *nChannels
;
611 // Check on channelList and result because used below
612 if (!channelList
|| !result
) goto finish
;
614 //IORLOG("IOReporter::configureReport action %u for %u channels",
615 // action, channelList->nchannels);
617 // Make sure channel is present, increase matching watch count, 'result'
618 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
620 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
621 &channel_index
) == kIOReturnSuccess
) {
622 // IORLOG("reporter %p recognizes channel %lld", this, channelList->channels[chIdx].channel_id);
626 case kIOReportEnable
:
627 nChannels
= (int*)result
;
629 _enableCounts
[channel_index
]++;
633 case kIOReportDisable
:
634 nChannels
= (int*)result
;
636 _enableCounts
[channel_index
]--;
640 case kIOReportGetDimensions
:
641 nElements
= (int *)result
;
642 *nElements
+= _channelDimension
;
646 IORLOG("ERROR configureReport unknown action!");
653 res
= kIOReturnSuccess
;
661 IOReporter::handleUpdateReport(IOReportChannelList
*channelList
,
662 IOReportConfigureAction action
,
666 IOReturn res
= kIOReturnError
;
667 int *nElements
= (int *)result
;
668 int channel_index
= 0;
670 IOBufferMemoryDescriptor
*dest
;
672 if (!channelList
|| !result
|| !destination
) goto finish
;
674 dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
676 // Invalid destination
677 res
= kIOReturnBadArgument
;
685 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
687 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
688 &channel_index
) == kIOReturnSuccess
) {
690 //IORLOG("%s - found channel_id %llx @ index %d", __func__,
691 // channelList->channels[chIdx].channel_id,
696 case kIOReportCopyChannelData
:
697 res
= updateChannelValues(channel_index
);
699 IORLOG("ERROR: updateChannelValues() failed: %x", res
);
703 res
= updateReportChannel(channel_index
, nElements
, dest
);
705 IORLOG("ERROR: updateReportChannel() failed: %x", res
);
711 IORLOG("ERROR updateReport unknown action!");
712 res
= kIOReturnError
;
719 res
= kIOReturnSuccess
;
727 IOReporter::handleCreateLegend(void)
729 IOReportLegendEntry
*legendEntry
= NULL
;
732 channelIDs
= copyChannelIDs();
735 legendEntry
= IOReporter::legendWith(channelIDs
, _channelNames
, _channelType
, _unit
);
736 channelIDs
->release();
744 IOReporter::setElementValues(int element_index
,
745 IOReportElementValues
*values
,
746 uint64_t record_time
/* = 0 */)
748 IOReturn res
= kIOReturnError
;
750 IOREPORTER_CHECK_LOCK();
752 if (record_time
== 0) {
753 record_time
= mach_absolute_time();
756 if (element_index
>= _nElements
|| values
== NULL
) {
757 res
= kIOReturnBadArgument
;
761 memcpy(&_elements
[element_index
].values
, values
, sizeof(IOReportElementValues
));
763 _elements
[element_index
].timestamp
= record_time
;
765 //IOREPORTER_DEBUG_ELEMENT(index);
767 res
= kIOReturnSuccess
;
774 const IOReportElementValues
*
775 IOReporter::getElementValues(int element_index
)
777 IOReportElementValues
*elementValues
= NULL
;
779 IOREPORTER_CHECK_LOCK();
781 if (element_index
< 0 || element_index
>= _nElements
) {
782 IORLOG("ERROR getElementValues out of bounds!");
786 elementValues
= &_elements
[element_index
].values
;
789 return elementValues
;
794 IOReporter::updateChannelValues(int channel_index
)
796 return kIOReturnSuccess
;
801 IOReporter::updateReportChannel(int channel_index
,
803 IOBufferMemoryDescriptor
*destination
)
805 IOReturn res
= kIOReturnError
;
806 int start_element_idx
, chElems
;
809 res
= kIOReturnBadArgument
;
810 if (!nElements
|| !destination
) {
813 if (channel_index
> _nChannels
) {
817 IOREPORTER_CHECK_LOCK();
819 res
= kIOReturnOverrun
;
821 start_element_idx
= channel_index
* _channelDimension
;
822 if (start_element_idx
>= _nElements
) goto finish
;
824 chElems
= _elements
[start_element_idx
].channel_type
.nelements
;
826 // make sure we don't go beyond the end of _elements[_nElements-1]
827 if (start_element_idx
+ chElems
> _nElements
) {
831 PREFL_MEMOP_FAIL(chElems
, IOReportElement
);
832 size2cpy
= (size_t)chElems
* sizeof(IOReportElement
);
834 // make sure there's space in the destination
835 if (size2cpy
> (destination
->getCapacity() - destination
->getLength())) {
836 IORLOG("CRITICAL ERROR: Report Buffer Overflow (buffer cap %luB, length %luB, size2cpy %luB",
837 (unsigned long)destination
->getCapacity(),
838 (unsigned long)destination
->getLength(),
839 (unsigned long)size2cpy
);
843 destination
->appendBytes(&_elements
[start_element_idx
], size2cpy
);
844 *nElements
+= chElems
;
846 res
= kIOReturnSuccess
;
854 IOReporter::copyElementValues(int element_index
,
855 IOReportElementValues
*elementValues
)
857 IOReturn res
= kIOReturnError
;
859 if (!elementValues
) goto finish
;
861 IOREPORTER_CHECK_LOCK();
863 if (element_index
>= _nElements
) {
864 IORLOG("ERROR getElementValues out of bounds!");
865 res
= kIOReturnBadArgument
;
869 memcpy(elementValues
, &_elements
[element_index
].values
, sizeof(IOReportElementValues
));
870 res
= kIOReturnSuccess
;
878 IOReporter::getFirstElementIndex(uint64_t channel_id
,
881 IOReturn res
= kIOReturnError
;
882 int channel_index
= 0, element_index
= 0;
884 if (!index
) goto finish
;
886 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
888 if (res
== kIOReturnSuccess
) {
889 *index
= element_index
;
898 IOReporter::getChannelIndex(uint64_t channel_id
,
901 IOReturn res
= kIOReturnError
;
902 int channel_index
= 0, element_index
= 0;
904 if (!index
) goto finish
;
906 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
908 if (res
== kIOReturnSuccess
) {
909 *index
= channel_index
;
918 IOReporter::getChannelIndices(uint64_t channel_id
,
922 IOReturn res
= kIOReturnNotFound
;
925 if (!channel_index
|| !element_index
) goto finish
;
927 for (chIdx
= 0; chIdx
< _nChannels
; chIdx
++) {
929 elemIdx
= chIdx
* _channelDimension
;
930 if (elemIdx
>= _nElements
) {
931 IORLOG("ERROR getChannelIndices out of bounds!");
932 res
= kIOReturnOverrun
;
936 if (channel_id
== _elements
[elemIdx
].channel_id
) {
938 // The channel index does not care about the depth of elements...
939 *channel_index
= chIdx
;
940 *element_index
= elemIdx
;
942 res
= kIOReturnSuccess
;
951 /********************************/
952 /*** PRIVATE METHODS ***/
953 /********************************/
956 // copyChannelIDs relies on the caller to take lock
958 IOReporter::copyChannelIDs()
961 OSArray
*channelIDs
= NULL
;
964 channelIDs
= OSArray::withCapacity((unsigned)_nChannels
);
966 if (!channelIDs
) goto finish
;
968 for (cnt
= 0; cnt
< _nChannels
; cnt
++) {
970 cnt2
= cnt
* _channelDimension
;
972 // Encapsulate the Channel ID in OSNumber
973 tmpNum
= OSNumber::withNumber(_elements
[cnt2
].channel_id
, 64);
975 IORLOG("ERROR: Could not create array of channelIDs");
976 channelIDs
->release();
981 channelIDs
->setObject((unsigned)cnt
, tmpNum
);
990 // DO NOT REMOVE THIS METHOD WHICH IS THE MAIN LEGEND CREATION FUNCTION
991 /*static */ IOReportLegendEntry
*
992 IOReporter::legendWith(OSArray
*channelIDs
,
993 OSArray
*channelNames
,
994 IOReportChannelType channelType
,
997 unsigned int cnt
, chCnt
;
1000 const OSSymbol
*tmpSymbol
;
1001 OSArray
*channelLegendArray
= NULL
, *tmpChannelArray
= NULL
;
1002 OSDictionary
*channelInfoDict
= NULL
;
1003 IOReportLegendEntry
*legendEntry
= NULL
;
1005 // No need to check validity of channelNames because param is optional
1006 if (!channelIDs
) goto finish
;
1007 chCnt
= channelIDs
->getCount();
1009 channelLegendArray
= OSArray::withCapacity(chCnt
);
1011 for (cnt
= 0; cnt
< chCnt
; cnt
++) {
1013 tmpChannelArray
= OSArray::withCapacity(3);
1015 // Encapsulate the Channel ID in OSNumber
1016 tmpChannelArray
->setObject(kIOReportChannelIDIdx
, channelIDs
->getObject(cnt
));
1018 // Encapsulate the Channel Type in OSNumber
1019 memcpy(&type64
, &channelType
, sizeof(type64
));
1020 tmpNum
= OSNumber::withNumber(type64
, 64);
1024 tmpChannelArray
->setObject(kIOReportChannelTypeIdx
, tmpNum
);
1027 // Encapsulate the Channel Name in OSSymbol
1028 // Use channelNames if provided
1029 if (channelNames
!= NULL
) {
1030 tmpSymbol
= OSDynamicCast(OSSymbol
, channelNames
->getObject(cnt
));
1031 if (tmpSymbol
&& tmpSymbol
!= gIOReportNoChannelName
) {
1032 tmpChannelArray
->setObject(kIOReportChannelNameIdx
, tmpSymbol
);
1033 } // Else, skip and leave name field empty
1036 channelLegendArray
->setObject(cnt
, tmpChannelArray
);
1037 tmpChannelArray
->release();
1038 tmpChannelArray
= NULL
;
1041 // Stuff the legend entry only if we have channels...
1042 if (channelLegendArray
->getCount() != 0) {
1044 channelInfoDict
= OSDictionary::withCapacity(1);
1046 if (!channelInfoDict
) {
1050 tmpNum
= OSNumber::withNumber(unit
, 64);
1052 channelInfoDict
->setObject(kIOReportLegendUnitKey
, tmpNum
);
1056 legendEntry
= OSDictionary::withCapacity(1);
1059 legendEntry
->setObject(kIOReportLegendChannelsKey
, channelLegendArray
);
1060 legendEntry
->setObject(kIOReportLegendInfoKey
, channelInfoDict
);
1065 if (tmpChannelArray
) tmpChannelArray
->release();
1066 if (channelInfoDict
) channelInfoDict
->release();
1067 if (channelLegendArray
) channelLegendArray
->release();