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
;
63 case kIOReportGetDimensions
:
65 case kIOReportDisable
:
68 iterator
= OSCollectionIterator::withCollection(reporters
);
70 while ((object
= iterator
->getNextObject())) {
71 IOReporter
*rep
= OSDynamicCast(IOReporter
, object
);
74 (void)rep
->configureReport(channelList
, action
, result
, destination
);
76 rval
= kIOReturnUnsupported
; // kIOReturnNotFound?
84 case kIOReportTraceOnChange
:
85 case kIOReportNotifyHubOnChange
:
87 rval
= kIOReturnUnsupported
;
91 rval
= kIOReturnSuccess
;
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
;
121 case kIOReportCopyChannelData
:
124 iterator
= OSCollectionIterator::withCollection(reporters
);
126 while ((object
= iterator
->getNextObject())) {
127 IOReporter
*rep
= OSDynamicCast(IOReporter
, object
);
130 (void)rep
->updateReport(channelList
, action
, result
, destination
);
132 rval
= kIOReturnUnsupported
; // kIOReturnNotFound?
140 case kIOReportTraceChannelData
:
142 rval
= kIOReturnUnsupported
;
146 rval
= kIOReturnSuccess
;
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()) {
190 _channelDimension
= channelType
.nelements
;
191 _channelType
= channelType
;
192 // FIXME: need to look up dynamically
193 if (unit
== kIOReportUnitHWTicks
) {
194 #if defined(__arm__) || defined(__arm64__)
195 unit
= kIOReportUnit24MHzTicks
;
196 #elif defined(__i386__) || defined(__x86_64__)
197 // Most, but not all Macs use 1GHz
198 unit
= kIOReportUnit1GHzTicks
;
200 #error kIOReportUnitHWTicks not defined
205 // Allocate a reporter (data) lock
206 _reporterLock
= IOSimpleLockAlloc();
207 if (!_reporterLock
) {
210 _reporterIsLocked
= false;
212 // Allocate a config lock
213 _configLock
= IOLockAlloc();
217 _reporterConfigIsLocked
= false;
219 // Allocate channel names array
220 _channelNames
= OSArray::withCapacity(1);
221 if (!_channelNames
) {
233 /*******************************/
234 /*** PUBLIC METHODS ***/
235 /*******************************/
237 // init() [possibly via init*()] must be called before free()
238 // to ensure that _<var> = NULL
240 IOReporter::free(void)
242 OSSafeReleaseNULL(_channelNames
);
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 const OSSymbol
*symChannelName
= NULL
;
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
;
309 symChannelName
->retain();
312 // allocate new buffers into _swap* variables
313 if ((kerr
= handleSwapPrepare(newNChannels
))) {
314 // on error, channels are *not* swapped
315 res
= kerr
; goto finish
;
318 // exchange main and _swap* buffers with buffer contents protected
319 // IOReporter::handleAddChannelSwap() also increments _nElements, etc
321 res
= handleAddChannelSwap(channelID
, symChannelName
);
323 // On failure, handleAddChannelSwap() leaves *new* buffers in _swap*.
324 // On success, it's the old buffers, so we put the right size in here.
325 if (res
== kIOReturnSuccess
) {
326 freeNChannels
= oldNChannels
;
330 // free up not-in-use buffers (tracked by _swap*)
331 handleSwapCleanup(freeNChannels
);
332 if (symChannelName
) {
333 symChannelName
->release();
335 unlockReporterConfig();
342 IOReporter::createLegend(void)
344 IOReportLegendEntry
*legendEntry
= NULL
;
346 lockReporterConfig();
348 legendEntry
= handleCreateLegend();
350 unlockReporterConfig();
357 IOReporter::configureReport(IOReportChannelList
*channelList
,
358 IOReportConfigureAction action
,
362 IOReturn res
= kIOReturnError
;
364 lockReporterConfig();
366 res
= handleConfigureReport(channelList
, action
, result
, destination
);
368 unlockReporterConfig();
375 IOReporter::updateReport(IOReportChannelList
*channelList
,
376 IOReportConfigureAction action
,
380 IOReturn res
= kIOReturnError
;
384 res
= handleUpdateReport(channelList
, action
, result
, destination
);
392 /*******************************/
393 /*** PROTECTED METHODS ***/
394 /*******************************/
398 IOReporter::lockReporter()
400 _interruptState
= IOSimpleLockLockDisableInterrupt(_reporterLock
);
401 _reporterIsLocked
= true;
406 IOReporter::unlockReporter()
408 _reporterIsLocked
= false;
409 IOSimpleLockUnlockEnableInterrupt(_reporterLock
, _interruptState
);
413 IOReporter::lockReporterConfig()
415 IOLockLock(_configLock
);
416 _reporterConfigIsLocked
= true;
420 IOReporter::unlockReporterConfig()
422 _reporterConfigIsLocked
= false;
423 IOLockUnlock(_configLock
);
428 IOReporter::handleSwapPrepare(int newNChannels
)
430 IOReturn res
= kIOReturnError
;
432 size_t newElementsSize
, newECSize
;
434 // analyzer appeasement
435 newElementsSize
= newECSize
= 0;
437 //IORLOG("IOReporter::handleSwapPrepare");
439 IOREPORTER_CHECK_CONFIG_LOCK();
441 if (newNChannels
< _nChannels
) {
442 panic("%s doesn't support shrinking", __func__
);
444 if (newNChannels
<= 0 || _channelDimension
<= 0) {
445 res
= kIOReturnUnderrun
;
448 if (_swapElements
|| _swapEnableCounts
) {
449 panic("IOReporter::_swap* already in use");
452 // calculate the number of elements given #ch & the dimension of each
453 if (newNChannels
< 0 || newNChannels
> INT_MAX
/ _channelDimension
) {
454 res
= kIOReturnOverrun
;
457 newNElements
= newNChannels
* _channelDimension
;
459 // Allocate memory for the new array of report elements
460 PREFL_MEMOP_FAIL(newNElements
, IOReportElement
);
461 newElementsSize
= (size_t)newNElements
* sizeof(IOReportElement
);
462 _swapElements
= (IOReportElement
*)IOMalloc(newElementsSize
);
463 if (_swapElements
== NULL
) {
464 res
= kIOReturnNoMemory
; goto finish
;
466 memset(_swapElements
, 0, newElementsSize
);
468 // Allocate memory for the new array of channel watch counts
469 PREFL_MEMOP_FAIL(newNChannels
, int);
470 newECSize
= (size_t)newNChannels
* sizeof(int);
471 _swapEnableCounts
= (int *)IOMalloc(newECSize
);
472 if (_swapEnableCounts
== NULL
) {
473 res
= kIOReturnNoMemory
; goto finish
;
475 memset(_swapEnableCounts
, 0, newECSize
);
478 res
= kIOReturnSuccess
;
483 IOFree(_swapElements
, newElementsSize
);
484 _swapElements
= NULL
;
486 if (_swapEnableCounts
) {
487 IOFree(_swapEnableCounts
, newECSize
);
488 _swapEnableCounts
= NULL
;
497 IOReporter::handleAddChannelSwap(uint64_t channel_id
,
498 const OSSymbol
*symChannelName
)
500 IOReturn res
= kIOReturnError
;
502 int *tmpWatchCounts
= NULL
;
503 IOReportElement
*tmpElements
= NULL
;
504 bool swapComplete
= false;
506 //IORLOG("IOReporter::handleSwap");
508 IOREPORTER_CHECK_CONFIG_LOCK();
509 IOREPORTER_CHECK_LOCK();
511 if (!_swapElements
|| !_swapEnableCounts
) {
512 IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!");
516 // Copy any existing elements to the new location
517 //IORLOG("handleSwap (base) -> copying %u elements over...", _nChannels);
519 PREFL_MEMOP_PANIC(_nElements
, IOReportElement
);
520 memcpy(_swapElements
, _elements
,
521 (size_t)_nElements
* sizeof(IOReportElement
));
523 PREFL_MEMOP_PANIC(_nElements
, int);
524 memcpy(_swapEnableCounts
, _enableCounts
,
525 (size_t)_nChannels
* sizeof(int));
528 // Update principal instance variables, keep old buffers for cleanup
529 tmpElements
= _elements
;
530 _elements
= _swapElements
;
531 _swapElements
= tmpElements
;
533 tmpWatchCounts
= _enableCounts
;
534 _enableCounts
= _swapEnableCounts
;
535 _swapEnableCounts
= tmpWatchCounts
;
539 // but _nChannels & _nElements is still the old (one smaller) size
541 // Initialize new element metadata (existing elements copied above)
542 for (cnt
= 0; cnt
< _channelDimension
; cnt
++) {
543 _elements
[_nElements
+ cnt
].channel_id
= channel_id
;
544 _elements
[_nElements
+ cnt
].provider_id
= _driver_id
;
545 _elements
[_nElements
+ cnt
].channel_type
= _channelType
;
546 _elements
[_nElements
+ cnt
].channel_type
.element_idx
= cnt
;
548 //IOREPORTER_DEBUG_ELEMENT(_swapNElements + cnt);
551 // Store a channel name at the end
552 if (!_channelNames
->setObject((unsigned)_nChannels
, symChannelName
)) {
553 // Should never happen because we ensured capacity in addChannel()
554 res
= kIOReturnNoMemory
;
558 // And update the metadata: addChannel() always adds just one channel
560 _nElements
+= _channelDimension
;
563 res
= kIOReturnSuccess
;
566 if (res
&& swapComplete
) {
567 // unswap so new buffers get cleaned up instead of old
568 tmpElements
= _elements
;
569 _elements
= _swapElements
;
570 _swapElements
= tmpElements
;
572 tmpWatchCounts
= _enableCounts
;
573 _enableCounts
= _swapEnableCounts
;
574 _swapEnableCounts
= tmpWatchCounts
;
580 IOReporter::handleSwapCleanup(int swapNChannels
)
584 if (!_channelDimension
|| swapNChannels
> INT_MAX
/ _channelDimension
) {
585 panic("%s - can't free %d channels of dimension %d", __func__
,
586 swapNChannels
, _channelDimension
);
588 swapNElements
= swapNChannels
* _channelDimension
;
590 IOREPORTER_CHECK_CONFIG_LOCK();
592 // release buffers no longer used after swapping
594 PREFL_MEMOP_PANIC(swapNElements
, IOReportElement
);
595 IOFree(_swapElements
, (size_t)swapNElements
* sizeof(IOReportElement
));
596 _swapElements
= NULL
;
598 if (_swapEnableCounts
) {
599 PREFL_MEMOP_PANIC(swapNChannels
, int);
600 IOFree(_swapEnableCounts
, (size_t)swapNChannels
* sizeof(int));
601 _swapEnableCounts
= NULL
;
606 // The reporter wants to know if its channels have observers.
607 // Eventually we'll add some sort of bool ::anyChannelsInUse() which
608 // clients can use to cull unused reporters after configureReport(disable).
610 IOReporter::handleConfigureReport(IOReportChannelList
*channelList
,
611 IOReportConfigureAction action
,
615 IOReturn res
= kIOReturnError
;
616 int channel_index
= 0;
618 int *nElements
, *nChannels
;
620 // Check on channelList and result because used below
621 if (!channelList
|| !result
) {
625 //IORLOG("IOReporter::configureReport action %u for %u channels",
626 // action, channelList->nchannels);
628 // Make sure channel is present, increase matching watch count, 'result'
629 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
630 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
631 &channel_index
) == kIOReturnSuccess
) {
632 // IORLOG("reporter %p recognizes channel %lld", this, channelList->channels[chIdx].channel_id);
635 case kIOReportEnable
:
636 nChannels
= (int*)result
;
638 _enableCounts
[channel_index
]++;
642 case kIOReportDisable
:
643 nChannels
= (int*)result
;
645 _enableCounts
[channel_index
]--;
649 case kIOReportGetDimensions
:
650 nElements
= (int *)result
;
651 *nElements
+= _channelDimension
;
655 IORLOG("ERROR configureReport unknown action!");
662 res
= kIOReturnSuccess
;
670 IOReporter::handleUpdateReport(IOReportChannelList
*channelList
,
671 IOReportConfigureAction action
,
675 IOReturn res
= kIOReturnError
;
676 int *nElements
= (int *)result
;
677 int channel_index
= 0;
679 IOBufferMemoryDescriptor
*dest
;
681 if (!channelList
|| !result
|| !destination
) {
685 dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
687 // Invalid destination
688 res
= kIOReturnBadArgument
;
696 for (chIdx
= 0; chIdx
< channelList
->nchannels
; chIdx
++) {
697 if (getChannelIndex(channelList
->channels
[chIdx
].channel_id
,
698 &channel_index
) == kIOReturnSuccess
) {
699 //IORLOG("%s - found channel_id %llx @ index %d", __func__,
700 // channelList->channels[chIdx].channel_id,
704 case kIOReportCopyChannelData
:
705 res
= updateChannelValues(channel_index
);
707 IORLOG("ERROR: updateChannelValues() failed: %x", res
);
711 res
= updateReportChannel(channel_index
, nElements
, dest
);
713 IORLOG("ERROR: updateReportChannel() failed: %x", res
);
719 IORLOG("ERROR updateReport unknown action!");
720 res
= kIOReturnError
;
727 res
= kIOReturnSuccess
;
735 IOReporter::handleCreateLegend(void)
737 IOReportLegendEntry
*legendEntry
= NULL
;
740 channelIDs
= copyChannelIDs();
743 legendEntry
= IOReporter::legendWith(channelIDs
, _channelNames
, _channelType
, _unit
);
744 channelIDs
->release();
752 IOReporter::setElementValues(int element_index
,
753 IOReportElementValues
*values
,
754 uint64_t record_time
/* = 0 */)
756 IOReturn res
= kIOReturnError
;
758 IOREPORTER_CHECK_LOCK();
760 if (record_time
== 0) {
761 record_time
= mach_absolute_time();
764 if (element_index
>= _nElements
|| values
== NULL
) {
765 res
= kIOReturnBadArgument
;
769 memcpy(&_elements
[element_index
].values
, values
, sizeof(IOReportElementValues
));
771 _elements
[element_index
].timestamp
= record_time
;
773 //IOREPORTER_DEBUG_ELEMENT(index);
775 res
= kIOReturnSuccess
;
782 const IOReportElementValues
*
783 IOReporter::getElementValues(int element_index
)
785 IOReportElementValues
*elementValues
= NULL
;
787 IOREPORTER_CHECK_LOCK();
789 if (element_index
< 0 || element_index
>= _nElements
) {
790 IORLOG("ERROR getElementValues out of bounds!");
794 elementValues
= &_elements
[element_index
].values
;
797 return elementValues
;
802 IOReporter::updateChannelValues(int channel_index
)
804 return kIOReturnSuccess
;
809 IOReporter::updateReportChannel(int channel_index
,
811 IOBufferMemoryDescriptor
*destination
)
813 IOReturn res
= kIOReturnError
;
814 int start_element_idx
, chElems
;
817 res
= kIOReturnBadArgument
;
818 if (!nElements
|| !destination
) {
821 if (channel_index
> _nChannels
) {
825 IOREPORTER_CHECK_LOCK();
827 res
= kIOReturnOverrun
;
829 start_element_idx
= channel_index
* _channelDimension
;
830 if (start_element_idx
>= _nElements
) {
834 chElems
= _elements
[start_element_idx
].channel_type
.nelements
;
836 // make sure we don't go beyond the end of _elements[_nElements-1]
837 if (start_element_idx
+ chElems
> _nElements
) {
841 PREFL_MEMOP_FAIL(chElems
, IOReportElement
);
842 size2cpy
= (size_t)chElems
* sizeof(IOReportElement
);
844 // make sure there's space in the destination
845 if (size2cpy
> (destination
->getCapacity() - destination
->getLength())) {
846 IORLOG("CRITICAL ERROR: Report Buffer Overflow (buffer cap %luB, length %luB, size2cpy %luB",
847 (unsigned long)destination
->getCapacity(),
848 (unsigned long)destination
->getLength(),
849 (unsigned long)size2cpy
);
853 destination
->appendBytes(&_elements
[start_element_idx
], size2cpy
);
854 *nElements
+= chElems
;
856 res
= kIOReturnSuccess
;
864 IOReporter::copyElementValues(int element_index
,
865 IOReportElementValues
*elementValues
)
867 IOReturn res
= kIOReturnError
;
869 if (!elementValues
) {
873 IOREPORTER_CHECK_LOCK();
875 if (element_index
>= _nElements
) {
876 IORLOG("ERROR getElementValues out of bounds!");
877 res
= kIOReturnBadArgument
;
881 memcpy(elementValues
, &_elements
[element_index
].values
, sizeof(IOReportElementValues
));
882 res
= kIOReturnSuccess
;
890 IOReporter::getFirstElementIndex(uint64_t channel_id
,
893 IOReturn res
= kIOReturnError
;
894 int channel_index
= 0, element_index
= 0;
900 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
902 if (res
== kIOReturnSuccess
) {
903 *index
= element_index
;
912 IOReporter::getChannelIndex(uint64_t channel_id
,
915 IOReturn res
= kIOReturnError
;
916 int channel_index
= 0, element_index
= 0;
922 res
= getChannelIndices(channel_id
, &channel_index
, &element_index
);
924 if (res
== kIOReturnSuccess
) {
925 *index
= channel_index
;
934 IOReporter::getChannelIndices(uint64_t channel_id
,
938 IOReturn res
= kIOReturnNotFound
;
941 if (!channel_index
|| !element_index
) {
945 for (chIdx
= 0; chIdx
< _nChannels
; chIdx
++) {
946 elemIdx
= chIdx
* _channelDimension
;
947 if (elemIdx
>= _nElements
) {
948 IORLOG("ERROR getChannelIndices out of bounds!");
949 res
= kIOReturnOverrun
;
953 if (channel_id
== _elements
[elemIdx
].channel_id
) {
954 // The channel index does not care about the depth of elements...
955 *channel_index
= chIdx
;
956 *element_index
= elemIdx
;
958 res
= kIOReturnSuccess
;
967 /********************************/
968 /*** PRIVATE METHODS ***/
969 /********************************/
972 // copyChannelIDs relies on the caller to take lock
974 IOReporter::copyChannelIDs()
977 OSArray
*channelIDs
= NULL
;
980 channelIDs
= OSArray::withCapacity((unsigned)_nChannels
);
986 for (cnt
= 0; cnt
< _nChannels
; cnt
++) {
987 cnt2
= cnt
* _channelDimension
;
989 // Encapsulate the Channel ID in OSNumber
990 tmpNum
= OSNumber::withNumber(_elements
[cnt2
].channel_id
, 64);
992 IORLOG("ERROR: Could not create array of channelIDs");
993 channelIDs
->release();
998 channelIDs
->setObject((unsigned)cnt
, tmpNum
);
1007 // DO NOT REMOVE THIS METHOD WHICH IS THE MAIN LEGEND CREATION FUNCTION
1008 /*static */ IOReportLegendEntry
*
1009 IOReporter::legendWith(OSArray
*channelIDs
,
1010 OSArray
*channelNames
,
1011 IOReportChannelType channelType
,
1014 unsigned int cnt
, chCnt
;
1017 const OSSymbol
*tmpSymbol
;
1018 OSArray
*channelLegendArray
= NULL
, *tmpChannelArray
= NULL
;
1019 OSDictionary
*channelInfoDict
= NULL
;
1020 IOReportLegendEntry
*legendEntry
= NULL
;
1022 // No need to check validity of channelNames because param is optional
1026 chCnt
= channelIDs
->getCount();
1028 channelLegendArray
= OSArray::withCapacity(chCnt
);
1030 for (cnt
= 0; cnt
< chCnt
; cnt
++) {
1031 tmpChannelArray
= OSArray::withCapacity(3);
1033 // Encapsulate the Channel ID in OSNumber
1034 tmpChannelArray
->setObject(kIOReportChannelIDIdx
, channelIDs
->getObject(cnt
));
1036 // Encapsulate the Channel Type in OSNumber
1037 memcpy(&type64
, &channelType
, sizeof(type64
));
1038 tmpNum
= OSNumber::withNumber(type64
, 64);
1042 tmpChannelArray
->setObject(kIOReportChannelTypeIdx
, tmpNum
);
1045 // Encapsulate the Channel Name in OSSymbol
1046 // Use channelNames if provided
1047 if (channelNames
!= NULL
) {
1048 tmpSymbol
= OSDynamicCast(OSSymbol
, channelNames
->getObject(cnt
));
1049 if (tmpSymbol
&& tmpSymbol
!= gIOReportNoChannelName
) {
1050 tmpChannelArray
->setObject(kIOReportChannelNameIdx
, tmpSymbol
);
1051 } // Else, skip and leave name field empty
1054 channelLegendArray
->setObject(cnt
, tmpChannelArray
);
1055 tmpChannelArray
->release();
1056 tmpChannelArray
= NULL
;
1059 // Stuff the legend entry only if we have channels...
1060 if (channelLegendArray
->getCount() != 0) {
1061 channelInfoDict
= OSDictionary::withCapacity(1);
1063 if (!channelInfoDict
) {
1067 tmpNum
= OSNumber::withNumber(unit
, 64);
1069 channelInfoDict
->setObject(kIOReportLegendUnitKey
, tmpNum
);
1073 legendEntry
= OSDictionary::withCapacity(1);
1076 legendEntry
->setObject(kIOReportLegendChannelsKey
, channelLegendArray
);
1077 legendEntry
->setObject(kIOReportLegendInfoKey
, channelInfoDict
);
1082 if (tmpChannelArray
) {
1083 tmpChannelArray
->release();
1085 if (channelInfoDict
) {
1086 channelInfoDict
->release();
1088 if (channelLegendArray
) {
1089 channelLegendArray
->release();