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(__arm__) || defined(__arm64__)
193 unit
= kIOReportUnit24MHzTicks
;
194 #elif defined(__i386__) || defined(__x86_64__)
195 // Most, but not all Macs use 1GHz
196 unit
= kIOReportUnit1GHzTicks
;
198 #error kIOReportUnitHWTicks not defined
203 // Allocate a reporter (data) lock
204 _reporterLock
= IOSimpleLockAlloc();
205 if (!_reporterLock
) goto finish
;
206 _reporterIsLocked
= false;
208 // Allocate a config lock
209 _configLock
= IOLockAlloc();
210 if (!_configLock
) goto finish
;
211 _reporterConfigIsLocked
= false;
213 // Allocate channel names array
214 _channelNames
= OSArray::withCapacity(1);
215 if (!_channelNames
) goto finish
;
225 /*******************************/
226 /*** PUBLIC METHODS ***/
227 /*******************************/
229 // init() [possibly via init*()] must be called before free()
230 // to ensure that _<var> = NULL
232 IOReporter::free(void)
234 OSSafeReleaseNULL(_channelNames
);
236 if (_configLock
) IOLockFree(_configLock
);
237 if (_reporterLock
) IOSimpleLockFree(_reporterLock
);
240 PREFL_MEMOP_PANIC(_nElements
, IOReportElement
);
241 IOFree(_elements
, (size_t)_nElements
* sizeof(IOReportElement
));
244 PREFL_MEMOP_PANIC(_nChannels
, int);
245 IOFree(_enableCounts
, (size_t)_nChannels
* sizeof(int));
252 #define TESTALLOC() do { \
254 tbuf = IOMalloc(10); \
256 IORLOG("%s:%d - _reporterIsLocked = %d & allocation successful", \
257 __PRETTY_FUNCTION__, __LINE__, _reporterIsLocked); \
261 IOReporter::addChannel(uint64_t channelID
,
262 const char *channelName
/* = NULL */)
264 IOReturn res
= kIOReturnError
, kerr
;
265 const OSSymbol
*symChannelName
= NULL
;
266 int oldNChannels
, newNChannels
= 0, freeNChannels
= 0;
268 IORLOG("IOReporter::addChannel %llx", channelID
);
270 // protect instance variables (but not contents)
271 lockReporterConfig();
273 // FIXME: Check if any channel is already present and return error
275 // addChannel() always adds one channel
276 oldNChannels
= _nChannels
;
277 if (oldNChannels
< 0 || oldNChannels
> INT_MAX
- 1) {
278 res
= kIOReturnOverrun
;
281 newNChannels
= oldNChannels
+ 1;
282 freeNChannels
= newNChannels
; // until swap success
284 // Expand addChannel()-specific data structure
285 if (_channelNames
->ensureCapacity((unsigned)newNChannels
) <
286 (unsigned)newNChannels
) {
287 res
= kIOReturnNoMemory
; goto finish
;
290 symChannelName
= OSSymbol::withCString(channelName
);
291 if (!symChannelName
) {
292 res
= kIOReturnNoMemory
; goto finish
;
295 // grab a reference to our shared global
296 symChannelName
= gIOReportNoChannelName
;
297 symChannelName
->retain();
300 // allocate new buffers into _swap* variables
301 if ((kerr
= handleSwapPrepare(newNChannels
))) {
302 // on error, channels are *not* swapped
303 res
= kerr
; goto finish
;
306 // exchange main and _swap* buffers with buffer contents protected
307 // IOReporter::handleAddChannelSwap() also increments _nElements, etc
309 res
= handleAddChannelSwap(channelID
, symChannelName
);
311 // On failure, handleAddChannelSwap() leaves *new* buffers in _swap*.
312 // On success, it's the old buffers, so we put the right size in here.
313 if (res
== kIOReturnSuccess
) {
314 freeNChannels
= oldNChannels
;
318 // free up not-in-use buffers (tracked by _swap*)
319 handleSwapCleanup(freeNChannels
);
320 if (symChannelName
) symChannelName
->release();
321 unlockReporterConfig();
328 IOReporter::createLegend(void)
330 IOReportLegendEntry
*legendEntry
= NULL
;
332 lockReporterConfig();
334 legendEntry
= handleCreateLegend();
336 unlockReporterConfig();
343 IOReporter::configureReport(IOReportChannelList
*channelList
,
344 IOReportConfigureAction action
,
348 IOReturn res
= kIOReturnError
;
350 lockReporterConfig();
352 res
= handleConfigureReport(channelList
, action
, result
, destination
);
354 unlockReporterConfig();
362 IOReporter::updateReport(IOReportChannelList
*channelList
,
363 IOReportConfigureAction action
,
367 IOReturn res
= kIOReturnError
;
371 res
= handleUpdateReport(channelList
, action
, result
, destination
);
380 /*******************************/
381 /*** PROTECTED METHODS ***/
382 /*******************************/
386 IOReporter::lockReporter()
388 _interruptState
= IOSimpleLockLockDisableInterrupt(_reporterLock
);
389 _reporterIsLocked
= true;
394 IOReporter::unlockReporter()
396 _reporterIsLocked
= false;
397 IOSimpleLockUnlockEnableInterrupt(_reporterLock
, _interruptState
);
401 IOReporter::lockReporterConfig()
403 IOLockLock(_configLock
);
404 _reporterConfigIsLocked
= true;
408 IOReporter::unlockReporterConfig()
410 _reporterConfigIsLocked
= false;
411 IOLockUnlock(_configLock
);
416 IOReporter::handleSwapPrepare(int newNChannels
)
418 IOReturn res
= kIOReturnError
;
420 size_t newElementsSize
, newECSize
;
422 // analyzer appeasement
423 newElementsSize
= newECSize
= 0;
425 //IORLOG("IOReporter::handleSwapPrepare");
427 IOREPORTER_CHECK_CONFIG_LOCK();
429 if (newNChannels
< _nChannels
) {
430 panic("%s doesn't support shrinking", __func__
);
432 if (newNChannels
<= 0 || _channelDimension
<= 0) {
433 res
= kIOReturnUnderrun
;
436 if (_swapElements
|| _swapEnableCounts
) {
437 panic("IOReporter::_swap* already in use");
440 // calculate the number of elements given #ch & the dimension of each
441 if (newNChannels
< 0 || newNChannels
> INT_MAX
/ _channelDimension
) {
442 res
= kIOReturnOverrun
;
445 newNElements
= newNChannels
* _channelDimension
;
447 // Allocate memory for the new array of report elements
448 PREFL_MEMOP_FAIL(newNElements
, IOReportElement
);
449 newElementsSize
= (size_t)newNElements
* sizeof(IOReportElement
);
450 _swapElements
= (IOReportElement
*)IOMalloc(newElementsSize
);
451 if (_swapElements
== NULL
) {
452 res
= kIOReturnNoMemory
; goto finish
;
454 memset(_swapElements
, 0, newElementsSize
);
456 // Allocate memory for the new array of channel watch counts
457 PREFL_MEMOP_FAIL(newNChannels
, int);
458 newECSize
= (size_t)newNChannels
* sizeof(int);
459 _swapEnableCounts
= (int *)IOMalloc(newECSize
);
460 if (_swapEnableCounts
== NULL
){
461 res
= kIOReturnNoMemory
; goto finish
;
463 memset(_swapEnableCounts
, 0, newECSize
);
466 res
= kIOReturnSuccess
;
471 IOFree(_swapElements
, newElementsSize
);
472 _swapElements
= NULL
;
474 if (_swapEnableCounts
) {
475 IOFree(_swapEnableCounts
, newECSize
);
476 _swapEnableCounts
= NULL
;
485 IOReporter::handleAddChannelSwap(uint64_t channel_id
,
486 const OSSymbol
*symChannelName
)
488 IOReturn res
= kIOReturnError
;
490 int *tmpWatchCounts
= NULL
;
491 IOReportElement
*tmpElements
= NULL
;
492 bool swapComplete
= false;
494 //IORLOG("IOReporter::handleSwap");
496 IOREPORTER_CHECK_CONFIG_LOCK();
497 IOREPORTER_CHECK_LOCK();
499 if (!_swapElements
|| !_swapEnableCounts
) {
500 IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!");
504 // Copy any existing elements to the new location
505 //IORLOG("handleSwap (base) -> copying %u elements over...", _nChannels);
507 PREFL_MEMOP_PANIC(_nElements
, IOReportElement
);
508 memcpy(_swapElements
, _elements
,
509 (size_t)_nElements
* sizeof(IOReportElement
));
511 PREFL_MEMOP_PANIC(_nElements
, int);
512 memcpy(_swapEnableCounts
, _enableCounts
,
513 (size_t)_nChannels
* sizeof(int));
516 // Update principal instance variables, keep old buffers for cleanup
517 tmpElements
= _elements
;
518 _elements
= _swapElements
;
519 _swapElements
= tmpElements
;
521 tmpWatchCounts
= _enableCounts
;
522 _enableCounts
= _swapEnableCounts
;
523 _swapEnableCounts
= tmpWatchCounts
;
527 // but _nChannels & _nElements is still the old (one smaller) size
529 // Initialize new element metadata (existing elements copied above)
530 for (cnt
= 0; cnt
< _channelDimension
; cnt
++) {
532 _elements
[_nElements
+ cnt
].channel_id
= channel_id
;
533 _elements
[_nElements
+ cnt
].provider_id
= _driver_id
;
534 _elements
[_nElements
+ cnt
].channel_type
= _channelType
;
535 _elements
[_nElements
+ cnt
].channel_type
.element_idx
= cnt
;
537 //IOREPORTER_DEBUG_ELEMENT(_swapNElements + cnt);
540 // Store a channel name at the end
541 if (!_channelNames
->setObject((unsigned)_nChannels
, symChannelName
)) {
542 // Should never happen because we ensured capacity in addChannel()
543 res
= kIOReturnNoMemory
;
547 // And update the metadata: addChannel() always adds just one channel
549 _nElements
+= _channelDimension
;
552 res
= kIOReturnSuccess
;
555 if (res
&& swapComplete
) {
556 // unswap so new buffers get cleaned up instead of old
557 tmpElements
= _elements
;
558 _elements
= _swapElements
;
559 _swapElements
= tmpElements
;
561 tmpWatchCounts
= _enableCounts
;
562 _enableCounts
= _swapEnableCounts
;
563 _swapEnableCounts
= tmpWatchCounts
;
569 IOReporter::handleSwapCleanup(int swapNChannels
)
573 if (!_channelDimension
|| swapNChannels
> INT_MAX
/ _channelDimension
) {
574 panic("%s - can't free %d channels of dimension %d", __func__
,
575 swapNChannels
, _channelDimension
);
577 swapNElements
= swapNChannels
* _channelDimension
;
579 IOREPORTER_CHECK_CONFIG_LOCK();
581 // release buffers no longer used after swapping
583 PREFL_MEMOP_PANIC(swapNElements
, IOReportElement
);
584 IOFree(_swapElements
, (size_t)swapNElements
* sizeof(IOReportElement
));
585 _swapElements
= NULL
;
587 if (_swapEnableCounts
) {
588 PREFL_MEMOP_PANIC(swapNChannels
, int);
589 IOFree(_swapEnableCounts
, (size_t)swapNChannels
* sizeof(int));
590 _swapEnableCounts
= NULL
;
595 // The reporter wants to know if its channels have observers.
596 // Eventually we'll add some sort of bool ::anyChannelsInUse() which
597 // clients can use to cull unused reporters after configureReport(disable).
599 IOReporter::handleConfigureReport(IOReportChannelList
*channelList
,
600 IOReportConfigureAction action
,
604 IOReturn res
= kIOReturnError
;
605 int channel_index
= 0;
607 int *nElements
, *nChannels
;
609 // Check on channelList and result because used below
610 if (!channelList
|| !result
) goto finish
;
612 //IORLOG("IOReporter::configureReport action %u for %u channels",
613 // action, channelList->nchannels);
615 // Make sure channel is present, increase matching watch count, 'result'
616 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
618 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
619 &channel_index
) == kIOReturnSuccess
) {
620 // IORLOG("reporter %p recognizes channel %lld", this, channelList->channels[chIdx].channel_id);
624 case kIOReportEnable
:
625 nChannels
= (int*)result
;
627 _enableCounts
[channel_index
]++;
631 case kIOReportDisable
:
632 nChannels
= (int*)result
;
634 _enableCounts
[channel_index
]--;
638 case kIOReportGetDimensions
:
639 nElements
= (int *)result
;
640 *nElements
+= _channelDimension
;
644 IORLOG("ERROR configureReport unknown action!");
651 res
= kIOReturnSuccess
;
659 IOReporter::handleUpdateReport(IOReportChannelList
*channelList
,
660 IOReportConfigureAction action
,
664 IOReturn res
= kIOReturnError
;
665 int *nElements
= (int *)result
;
666 int channel_index
= 0;
668 IOBufferMemoryDescriptor
*dest
;
670 if (!channelList
|| !result
|| !destination
) goto finish
;
672 dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
674 // Invalid destination
675 res
= kIOReturnBadArgument
;
683 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
685 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
686 &channel_index
) == kIOReturnSuccess
) {
688 //IORLOG("%s - found channel_id %llx @ index %d", __func__,
689 // channelList->channels[chIdx].channel_id,
694 case kIOReportCopyChannelData
:
695 res
= updateChannelValues(channel_index
);
697 IORLOG("ERROR: updateChannelValues() failed: %x", res
);
701 res
= updateReportChannel(channel_index
, nElements
, dest
);
703 IORLOG("ERROR: updateReportChannel() failed: %x", res
);
709 IORLOG("ERROR updateReport unknown action!");
710 res
= kIOReturnError
;
717 res
= kIOReturnSuccess
;
725 IOReporter::handleCreateLegend(void)
727 IOReportLegendEntry
*legendEntry
= NULL
;
730 channelIDs
= copyChannelIDs();
733 legendEntry
= IOReporter::legendWith(channelIDs
, _channelNames
, _channelType
, _unit
);
734 channelIDs
->release();
742 IOReporter::setElementValues(int element_index
,
743 IOReportElementValues
*values
,
744 uint64_t record_time
/* = 0 */)
746 IOReturn res
= kIOReturnError
;
748 IOREPORTER_CHECK_LOCK();
750 if (record_time
== 0) {
751 record_time
= mach_absolute_time();
754 if (element_index
>= _nElements
|| values
== NULL
) {
755 res
= kIOReturnBadArgument
;
759 memcpy(&_elements
[element_index
].values
, values
, sizeof(IOReportElementValues
));
761 _elements
[element_index
].timestamp
= record_time
;
763 //IOREPORTER_DEBUG_ELEMENT(index);
765 res
= kIOReturnSuccess
;
772 const IOReportElementValues
*
773 IOReporter::getElementValues(int element_index
)
775 IOReportElementValues
*elementValues
= NULL
;
777 IOREPORTER_CHECK_LOCK();
779 if (element_index
< 0 || element_index
>= _nElements
) {
780 IORLOG("ERROR getElementValues out of bounds!");
784 elementValues
= &_elements
[element_index
].values
;
787 return elementValues
;
792 IOReporter::updateChannelValues(int channel_index
)
794 return kIOReturnSuccess
;
799 IOReporter::updateReportChannel(int channel_index
,
801 IOBufferMemoryDescriptor
*destination
)
803 IOReturn res
= kIOReturnError
;
804 int start_element_idx
, chElems
;
807 res
= kIOReturnBadArgument
;
808 if (!nElements
|| !destination
) {
811 if (channel_index
> _nChannels
) {
815 IOREPORTER_CHECK_LOCK();
817 res
= kIOReturnOverrun
;
819 start_element_idx
= channel_index
* _channelDimension
;
820 if (start_element_idx
>= _nElements
) goto finish
;
822 chElems
= _elements
[start_element_idx
].channel_type
.nelements
;
824 // make sure we don't go beyond the end of _elements[_nElements-1]
825 if (start_element_idx
+ chElems
> _nElements
) {
829 PREFL_MEMOP_FAIL(chElems
, IOReportElement
);
830 size2cpy
= (size_t)chElems
* sizeof(IOReportElement
);
832 // make sure there's space in the destination
833 if (size2cpy
> (destination
->getCapacity() - destination
->getLength())) {
834 IORLOG("CRITICAL ERROR: Report Buffer Overflow (buffer cap %luB, length %luB, size2cpy %luB",
835 (unsigned long)destination
->getCapacity(),
836 (unsigned long)destination
->getLength(),
837 (unsigned long)size2cpy
);
841 destination
->appendBytes(&_elements
[start_element_idx
], size2cpy
);
842 *nElements
+= chElems
;
844 res
= kIOReturnSuccess
;
852 IOReporter::copyElementValues(int element_index
,
853 IOReportElementValues
*elementValues
)
855 IOReturn res
= kIOReturnError
;
857 if (!elementValues
) goto finish
;
859 IOREPORTER_CHECK_LOCK();
861 if (element_index
>= _nElements
) {
862 IORLOG("ERROR getElementValues out of bounds!");
863 res
= kIOReturnBadArgument
;
867 memcpy(elementValues
, &_elements
[element_index
].values
, sizeof(IOReportElementValues
));
868 res
= kIOReturnSuccess
;
876 IOReporter::getFirstElementIndex(uint64_t channel_id
,
879 IOReturn res
= kIOReturnError
;
880 int channel_index
= 0, element_index
= 0;
882 if (!index
) goto finish
;
884 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
886 if (res
== kIOReturnSuccess
) {
887 *index
= element_index
;
896 IOReporter::getChannelIndex(uint64_t channel_id
,
899 IOReturn res
= kIOReturnError
;
900 int channel_index
= 0, element_index
= 0;
902 if (!index
) goto finish
;
904 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
906 if (res
== kIOReturnSuccess
) {
907 *index
= channel_index
;
916 IOReporter::getChannelIndices(uint64_t channel_id
,
920 IOReturn res
= kIOReturnNotFound
;
923 if (!channel_index
|| !element_index
) goto finish
;
925 for (chIdx
= 0; chIdx
< _nChannels
; chIdx
++) {
927 elemIdx
= chIdx
* _channelDimension
;
928 if (elemIdx
>= _nElements
) {
929 IORLOG("ERROR getChannelIndices out of bounds!");
930 res
= kIOReturnOverrun
;
934 if (channel_id
== _elements
[elemIdx
].channel_id
) {
936 // The channel index does not care about the depth of elements...
937 *channel_index
= chIdx
;
938 *element_index
= elemIdx
;
940 res
= kIOReturnSuccess
;
949 /********************************/
950 /*** PRIVATE METHODS ***/
951 /********************************/
954 // copyChannelIDs relies on the caller to take lock
956 IOReporter::copyChannelIDs()
959 OSArray
*channelIDs
= NULL
;
962 channelIDs
= OSArray::withCapacity((unsigned)_nChannels
);
964 if (!channelIDs
) goto finish
;
966 for (cnt
= 0; cnt
< _nChannels
; cnt
++) {
968 cnt2
= cnt
* _channelDimension
;
970 // Encapsulate the Channel ID in OSNumber
971 tmpNum
= OSNumber::withNumber(_elements
[cnt2
].channel_id
, 64);
973 IORLOG("ERROR: Could not create array of channelIDs");
974 channelIDs
->release();
979 channelIDs
->setObject((unsigned)cnt
, tmpNum
);
988 // DO NOT REMOVE THIS METHOD WHICH IS THE MAIN LEGEND CREATION FUNCTION
989 /*static */ IOReportLegendEntry
*
990 IOReporter::legendWith(OSArray
*channelIDs
,
991 OSArray
*channelNames
,
992 IOReportChannelType channelType
,
995 unsigned int cnt
, chCnt
;
998 const OSSymbol
*tmpSymbol
;
999 OSArray
*channelLegendArray
= NULL
, *tmpChannelArray
= NULL
;
1000 OSDictionary
*channelInfoDict
= NULL
;
1001 IOReportLegendEntry
*legendEntry
= NULL
;
1003 // No need to check validity of channelNames because param is optional
1004 if (!channelIDs
) goto finish
;
1005 chCnt
= channelIDs
->getCount();
1007 channelLegendArray
= OSArray::withCapacity(chCnt
);
1009 for (cnt
= 0; cnt
< chCnt
; cnt
++) {
1011 tmpChannelArray
= OSArray::withCapacity(3);
1013 // Encapsulate the Channel ID in OSNumber
1014 tmpChannelArray
->setObject(kIOReportChannelIDIdx
, channelIDs
->getObject(cnt
));
1016 // Encapsulate the Channel Type in OSNumber
1017 memcpy(&type64
, &channelType
, sizeof(type64
));
1018 tmpNum
= OSNumber::withNumber(type64
, 64);
1022 tmpChannelArray
->setObject(kIOReportChannelTypeIdx
, tmpNum
);
1025 // Encapsulate the Channel Name in OSSymbol
1026 // Use channelNames if provided
1027 if (channelNames
!= NULL
) {
1028 tmpSymbol
= OSDynamicCast(OSSymbol
, channelNames
->getObject(cnt
));
1029 if (tmpSymbol
&& tmpSymbol
!= gIOReportNoChannelName
) {
1030 tmpChannelArray
->setObject(kIOReportChannelNameIdx
, tmpSymbol
);
1031 } // Else, skip and leave name field empty
1034 channelLegendArray
->setObject(cnt
, tmpChannelArray
);
1035 tmpChannelArray
->release();
1036 tmpChannelArray
= NULL
;
1039 // Stuff the legend entry only if we have channels...
1040 if (channelLegendArray
->getCount() != 0) {
1042 channelInfoDict
= OSDictionary::withCapacity(1);
1044 if (!channelInfoDict
) {
1048 tmpNum
= OSNumber::withNumber(unit
, 64);
1050 channelInfoDict
->setObject(kIOReportLegendUnitKey
, tmpNum
);
1054 legendEntry
= OSDictionary::withCapacity(1);
1057 legendEntry
->setObject(kIOReportLegendChannelsKey
, channelLegendArray
);
1058 legendEntry
->setObject(kIOReportLegendInfoKey
, channelInfoDict
);
1063 if (tmpChannelArray
) tmpChannelArray
->release();
1064 if (channelInfoDict
) channelInfoDict
->release();
1065 if (channelLegendArray
) channelLegendArray
->release();