1/*
2 * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <IOKit/IOKernelReportStructs.h>
30#include <IOKit/IOKernelReporters.h>
31
32
33//#define IORDEBUG_LEGEND 1
34
35#ifdef IORDEBUG_LEGEND
36 #define IORLEGENDLOG(fmt, args...) \
37 do { \
38 IOLog("IOReportLegend | "); \
39 IOLog(fmt, ##args); \
40 IOLog("\n"); \
41 } while(0)
42#else
43 #define IORLEGENDLOG(fmt, args...)
44#endif
45
46
47#define super OSObject
48OSDefineMetaClassAndStructors(IOReportLegend, OSObject);
49
50IOReportLegend*
51IOReportLegend::with(OSArray *legend)
52{
53 IOReportLegend *iorLegend = new IOReportLegend;
54
55 if (iorLegend) {
56
57 if (legend != NULL) {
58 if (iorLegend->initWith(legend) != kIOReturnSuccess) {
59 OSSafeReleaseNULL(iorLegend);
60 return NULL;
61 }
62 }
63
64 return iorLegend;
65 }
66
67 else return NULL;
68}
69
70/* must clean up everything if it fails */
71IOReturn
72IOReportLegend::initWith(OSArray *legend)
73{
74 if (legend) _reportLegend = OSArray::withArray(legend);
75
76 if (_reportLegend == NULL)
77 return kIOReturnError;
78
79 else return kIOReturnSuccess;
80}
81
82
83void
84IOReportLegend::free(void)
85{
86 if (_reportLegend) _reportLegend->release();
87 super::free();
88}
89
90
91OSArray*
92IOReportLegend::getLegend(void)
93{
94 return _reportLegend;
95}
96
97IOReturn
98IOReportLegend::addReporterLegend(IOService *reportingService,
99 IOReporter *reporter,
100 const char *groupName,
101 const char *subGroupName)
102{
103 IOReturn res = kIOReturnError;
104 IOReportLegend *legend = NULL;
105 OSObject *curLegend = NULL;
106
107 // No need to check groupName and subGroupName because optional params
108 if (!reportingService || !reporter) {
109 goto finish;
110 }
111
112 // It's fine if the legend doesn't exist (IOReportLegend::with(NULL)
113 // is how you make an empty legend). If it's not an array, then
114 // we're just going to replace it.
115 curLegend = reportingService->copyProperty(kIOReportLegendKey);
116 legend = IOReportLegend::with(OSDynamicCast(OSArray, curLegend));
117 if (!legend) goto finish;
118
119 // Add the reporter's entries and update the service property.
120 // The overwrite triggers a release of the old legend array.
121 legend->addReporterLegend(reporter, groupName, subGroupName);
122 reportingService->setProperty(kIOReportLegendKey, legend->getLegend());
123 reportingService->setProperty(kIOReportLegendPublicKey, true);
124
125 res = kIOReturnSuccess;
126
127finish:
128 if (legend) legend->release();
129 if (curLegend) curLegend->release();
130
131 return res;
132}
133
134
135IOReturn
136IOReportLegend::addLegendEntry(IOReportLegendEntry *legendEntry,
137 const char *groupName,
138 const char *subGroupName)
139{
140 kern_return_t res = kIOReturnError;
141 const OSSymbol *tmpGroupName = NULL;
142 const OSSymbol *tmpSubGroupName = NULL;
143
144 if (!legendEntry) goto finish;
145
146 if (groupName) {
147 tmpGroupName = OSSymbol::withCString(groupName);
148 }
149
150 if (subGroupName) {
151 tmpSubGroupName = OSSymbol::withCString(subGroupName);
152 }
153
154 // It is ok to call appendLegendWith() if tmpGroups are NULL
155 if (legendEntry) {
156 res = organizeLegend(legendEntry, tmpGroupName, tmpSubGroupName);
157
158 if (tmpGroupName) tmpGroupName->release();
159 if (tmpSubGroupName) tmpSubGroupName->release();
160 }
161
162finish:
163 return res;
164}
165
166
167IOReturn
168IOReportLegend::addReporterLegend(IOReporter *reporter,
169 const char *groupName,
170 const char *subGroupName)
171{
172 IOReturn res = kIOReturnError;
173 IOReportLegendEntry *legendEntry = NULL;
174
175 if (reporter) {
176
177 legendEntry = reporter->createLegend();
178
179 if (legendEntry) {
180
181 res = addLegendEntry(legendEntry, groupName, subGroupName);
182 legendEntry->release();
183 }
184 }
185
186 return res;
187}
188
189
190IOReturn
191IOReportLegend::organizeLegend(IOReportLegendEntry *legendEntry,
192 const OSSymbol *groupName,
193 const OSSymbol *subGroupName)
194{
195 IOReturn res = kIOReturnError;
196
197 if (!legendEntry)
198 return res = kIOReturnBadArgument;
199
200 if (!groupName && subGroupName)
201 return res = kIOReturnBadArgument;
202
203 IORLEGENDLOG("IOReportLegend::organizeLegend");
204 // Legend is empty, enter first node
205 if (_reportLegend == NULL) {
206 IORLEGENDLOG("IOReportLegend::new legend creation");
207 _reportLegend = OSArray::withCapacity(1);
208
209 if (!_reportLegend)
210 return kIOReturnNoMemory;
211 }
212
213 if (groupName)
214 legendEntry->setObject(kIOReportLegendGroupNameKey, groupName);
215
216 if (subGroupName)
217 legendEntry->setObject(kIOReportLegendSubGroupNameKey, subGroupName);
218
219 _reportLegend->setObject(legendEntry);
220
221 // callers can now safely release legendEntry (it is part of _reportLegend)
222
223 return res = kIOReturnSuccess;
224}
225
226