Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_drv.c
+++ new/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_drv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2009-2010, Intel Corporation.
23 23 * All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Platform specific device enumerator for ACPI specific devices.
28 28 * "x86 system devices" refers to the suite of hardware components which are
29 29 * common to the x86 platform and play important roles in the system
30 30 * architecture but can't be enumerated/discovered through industry-standard
31 31 * bus specifications. Examples of these x86 system devices include:
32 32 * * Logical processor/CPU
33 33 * * Memory device
34 34 * * Non-PCI discoverable IOMMU or DMA Remapping Engine
35 35 * * Non-PCI discoverable IOxAPIC
36 36 * * Non-PCI discoverable HPET (High Precision Event Timer)
37 37 * * ACPI defined devices, including power button, sleep button, battery etc.
38 38 *
39 39 * X86 system devices may be discovered through BIOS/Firmware interfaces, such
40 40 * as SMBIOS tables, MPS tables and ACPI tables since their discovery isn't
41 41 * covered by any industry-standard bus specifications.
42 42 *
43 43 * In order to aid Solaris in flexibly managing x86 system devices,
44 44 * x86 system devices are placed into a specific firmware device
45 45 * subtree whose device path is '/devices/fw'.
46 46 *
47 47 * This driver populates the firmware device subtree with ACPI-discoverable
48 48 * system devices if possible. To achieve that, the ACPI object
49 49 * namespace is abstracted as ACPI virtual buses which host system devices.
50 50 * Another nexus driver for the ACPI virtual bus will manage all devices
51 51 * connected to it.
52 52 *
53 53 * For more detailed information, please refer to PSARC/2009/104.
54 54 */
55 55
56 56 #include <sys/types.h>
57 57 #include <sys/bitmap.h>
58 58 #include <sys/cmn_err.h>
59 59 #include <sys/ddi_subrdefs.h>
60 60 #include <sys/errno.h>
61 61 #include <sys/modctl.h>
62 62 #include <sys/mutex.h>
63 63 #include <sys/note.h>
64 64 #include <sys/obpdefs.h>
65 65 #include <sys/sunddi.h>
66 66 #include <sys/sunndi.h>
67 67 #include <sys/acpi/acpi.h>
68 68 #include <sys/acpica.h>
69 69 #include <sys/acpidev.h>
70 70 #include <sys/acpidev_dr.h>
71 71 #include <sys/acpidev_impl.h>
72 72
73 73 /* Patchable through /etc/system */
74 74 int acpidev_options = 0;
75 75 int acpidev_debug = 0;
76 76
77 77 krwlock_t acpidev_class_lock;
78 78 acpidev_class_list_t *acpidev_class_list_root = NULL;
79 79 ulong_t acpidev_object_type_mask[BT_BITOUL(ACPI_TYPE_NS_NODE_MAX + 1)];
80 80
81 81 /* ACPI device autoconfig global status */
82 82 typedef enum acpidev_status {
83 83 ACPIDEV_STATUS_FAILED = -2, /* ACPI device autoconfig failed */
84 84 ACPIDEV_STATUS_DISABLED = -1, /* ACPI device autoconfig disabled */
85 85 ACPIDEV_STATUS_UNKNOWN = 0, /* initial status */
86 86 ACPIDEV_STATUS_INITIALIZED, /* ACPI device autoconfig initialized */
87 87 ACPIDEV_STATUS_FIRST_PASS, /* first probing finished */
88 88 ACPIDEV_STATUS_READY /* second probing finished */
89 89 } acpidev_status_t;
90 90
91 91 static acpidev_status_t acpidev_status = ACPIDEV_STATUS_UNKNOWN;
92 92 static kmutex_t acpidev_drv_lock;
93 93 static dev_info_t *acpidev_root_dip = NULL;
94 94
95 95 /* Boot time ACPI device enumerator. */
96 96 static void acpidev_boot_probe(int type);
97 97
↓ open down ↓ |
97 lines elided |
↑ open up ↑ |
98 98 /* DDI module auto configuration interface */
99 99 extern struct mod_ops mod_miscops;
100 100
101 101 static struct modlmisc modlmisc = {
102 102 &mod_miscops,
103 103 "ACPI device enumerator"
104 104 };
105 105
106 106 static struct modlinkage modlinkage = {
107 107 MODREV_1,
108 - (void *)&modlmisc,
109 - NULL
108 + { (void *)&modlmisc, NULL }
110 109 };
111 110
112 111 int
113 112 _init(void)
114 113 {
115 114 int err;
116 115
117 116 if ((err = mod_install(&modlinkage)) == 0) {
118 117 bzero(acpidev_object_type_mask,
119 118 sizeof (acpidev_object_type_mask));
120 119 mutex_init(&acpidev_drv_lock, NULL, MUTEX_DRIVER, NULL);
121 120 rw_init(&acpidev_class_lock, NULL, RW_DEFAULT, NULL);
122 121 acpidev_dr_init();
123 122 impl_bus_add_probe(acpidev_boot_probe);
124 123 } else {
125 124 cmn_err(CE_WARN, "!acpidev: failed to install driver.");
126 125 }
127 126
128 127 return (err);
129 128 }
130 129
131 130 int
132 131 _fini(void)
133 132 {
134 133 /* No support for module unload. */
135 134 return (EBUSY);
136 135 }
137 136
138 137 int
139 138 _info(struct modinfo *modinfop)
140 139 {
141 140 return (mod_info(&modlinkage, modinfop));
142 141 }
143 142
144 143 /* Check blacklists and load platform specific driver modules. */
145 144 static ACPI_STATUS
146 145 acpidev_load_plat_modules(void)
147 146 {
148 147 return (AE_OK);
149 148 }
150 149
151 150 /* Unload platform specific driver modules. */
152 151 static void
153 152 acpidev_unload_plat_modules(void)
154 153 {
155 154 }
156 155
157 156 /* Unregister all device class drivers from the device driver lists. */
158 157 static void
159 158 acpidev_class_list_fini(void)
160 159 {
161 160 acpidev_unload_plat_modules();
162 161
163 162 if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
164 163 (void) acpidev_unregister_class(&acpidev_class_list_scope,
165 164 &acpidev_class_pci);
166 165 (void) acpidev_unregister_class(&acpidev_class_list_device,
167 166 &acpidev_class_pci);
168 167 }
169 168
170 169 if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
171 170 (void) acpidev_unregister_class(&acpidev_class_list_device,
172 171 &acpidev_class_memory);
173 172 }
174 173
175 174 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
176 175 (void) acpidev_unregister_class(&acpidev_class_list_device,
177 176 &acpidev_class_cpu);
178 177 (void) acpidev_unregister_class(&acpidev_class_list_scope,
179 178 &acpidev_class_cpu);
180 179 (void) acpidev_unregister_class(&acpidev_class_list_root,
181 180 &acpidev_class_cpu);
182 181 }
183 182
184 183 if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
185 184 (void) acpidev_unregister_class(&acpidev_class_list_device,
186 185 &acpidev_class_container);
187 186 }
188 187
189 188 (void) acpidev_unregister_class(&acpidev_class_list_device,
190 189 &acpidev_class_device);
191 190 (void) acpidev_unregister_class(&acpidev_class_list_root,
192 191 &acpidev_class_device);
193 192
194 193 (void) acpidev_unregister_class(&acpidev_class_list_root,
195 194 &acpidev_class_scope);
196 195 }
197 196
198 197 /* Register all device class drivers onto the driver lists. */
199 198 static ACPI_STATUS
200 199 acpidev_class_list_init(uint64_t *fp)
201 200 {
202 201 ACPI_STATUS rc = AE_OK;
203 202
204 203 /* Set bit in mask for supported object types. */
205 204 BT_SET(acpidev_object_type_mask, ACPI_TYPE_LOCAL_SCOPE);
206 205 BT_SET(acpidev_object_type_mask, ACPI_TYPE_DEVICE);
207 206
208 207 /*
209 208 * Register the ACPI scope class driver onto the class driver lists.
210 209 * Currently only ACPI scope objects under ACPI root node, such as _PR,
211 210 * _SB, _TZ etc, need to be handled, so only register the scope class
212 211 * driver onto the root list.
213 212 */
214 213 if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
215 214 &acpidev_class_scope, B_FALSE))) {
216 215 goto error_out;
217 216 }
218 217
219 218 /*
220 219 * Register the ACPI device class driver onto the class driver lists.
221 220 * The ACPI device class driver should be registered at the tail to
222 221 * handle all device objects which haven't been handled by other
223 222 * HID/CID specific device class drivers.
224 223 */
225 224 if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
226 225 &acpidev_class_device, B_TRUE))) {
227 226 goto error_root_device;
228 227 }
229 228 if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_device,
230 229 &acpidev_class_device, B_TRUE))) {
231 230 goto error_device_device;
232 231 }
233 232
234 233 /* Check and register support for ACPI container device. */
235 234 if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
236 235 if (ACPI_FAILURE(acpidev_register_class(
237 236 &acpidev_class_list_device, &acpidev_class_container,
238 237 B_FALSE))) {
239 238 goto error_device_container;
240 239 }
241 240 *fp |= ACPI_DEVCFG_CONTAINER;
242 241 }
243 242
244 243 /* Check and register support for ACPI CPU device. */
245 244 if ((acpidev_options & ACPIDEV_OUSER_NO_CPU) == 0) {
246 245 /* Handle ACPI CPU Device */
247 246 if (ACPI_FAILURE(acpidev_register_class(
248 247 &acpidev_class_list_device, &acpidev_class_cpu, B_FALSE))) {
249 248 goto error_device_cpu;
250 249 }
251 250 /* Handle ACPI Processor under _PR */
252 251 if (ACPI_FAILURE(acpidev_register_class(
253 252 &acpidev_class_list_scope, &acpidev_class_cpu, B_FALSE))) {
254 253 goto error_scope_cpu;
255 254 }
256 255 /* House-keeping for CPU scan */
257 256 if (ACPI_FAILURE(acpidev_register_class(
258 257 &acpidev_class_list_root, &acpidev_class_cpu, B_FALSE))) {
259 258 goto error_root_cpu;
260 259 }
261 260 BT_SET(acpidev_object_type_mask, ACPI_TYPE_PROCESSOR);
262 261 *fp |= ACPI_DEVCFG_CPU;
263 262 }
264 263
265 264 /* Check support of ACPI memory devices. */
266 265 if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
267 266 /*
268 267 * Register the ACPI memory class driver onto the
269 268 * acpidev_class_list_device list because ACPI module
270 269 * class driver uses that list.
271 270 */
272 271 if (ACPI_FAILURE(acpidev_register_class(
273 272 &acpidev_class_list_device, &acpidev_class_memory,
274 273 B_FALSE))) {
275 274 goto error_device_memory;
276 275 }
277 276 *fp |= ACPI_DEVCFG_MEMORY;
278 277 }
279 278
280 279 /* Check support of PCI/PCIex Host Bridge devices. */
281 280 if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
282 281 /*
283 282 * Register pci/pciex class drivers onto
284 283 * the acpidev_class_list_device class list because ACPI
285 284 * module class driver uses that list.
286 285 */
287 286 if (ACPI_FAILURE(acpidev_register_class(
288 287 &acpidev_class_list_device, &acpidev_class_pci,
289 288 B_FALSE))) {
290 289 goto error_device_pci;
291 290 }
292 291
293 292 /*
294 293 * Register pci/pciex class drivers onto the
295 294 * acpidev_class_list_scope class list.
296 295 */
297 296 if (ACPI_FAILURE(acpidev_register_class(
298 297 &acpidev_class_list_scope, &acpidev_class_pci,
299 298 B_FALSE))) {
300 299 goto error_scope_pci;
301 300 }
302 301
303 302 *fp |= ACPI_DEVCFG_PCI;
304 303 }
305 304
306 305 /* Check blacklist and load platform specific modules. */
307 306 rc = acpidev_load_plat_modules();
308 307 if (ACPI_FAILURE(rc)) {
309 308 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to check blacklist "
310 309 "or load pratform modules.");
311 310 goto error_plat;
312 311 }
313 312
314 313 return (AE_OK);
315 314
316 315 error_plat:
317 316 if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
318 317 (void) acpidev_unregister_class(&acpidev_class_list_scope,
319 318 &acpidev_class_pci);
320 319 }
321 320 error_scope_pci:
322 321 if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
323 322 (void) acpidev_unregister_class(&acpidev_class_list_device,
324 323 &acpidev_class_pci);
325 324 }
326 325 error_device_pci:
327 326 if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
328 327 (void) acpidev_unregister_class(&acpidev_class_list_device,
329 328 &acpidev_class_memory);
330 329 }
331 330 error_device_memory:
332 331 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
333 332 (void) acpidev_unregister_class(&acpidev_class_list_root,
334 333 &acpidev_class_cpu);
335 334 }
336 335 error_root_cpu:
337 336 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
338 337 (void) acpidev_unregister_class(&acpidev_class_list_scope,
339 338 &acpidev_class_cpu);
340 339 }
341 340 error_scope_cpu:
342 341 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
343 342 (void) acpidev_unregister_class(&acpidev_class_list_device,
344 343 &acpidev_class_cpu);
345 344 }
346 345 error_device_cpu:
347 346 if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
348 347 (void) acpidev_unregister_class(&acpidev_class_list_device,
349 348 &acpidev_class_container);
350 349 }
351 350 error_device_container:
352 351 (void) acpidev_unregister_class(&acpidev_class_list_device,
353 352 &acpidev_class_device);
354 353 error_device_device:
355 354 (void) acpidev_unregister_class(&acpidev_class_list_root,
356 355 &acpidev_class_device);
357 356 error_root_device:
358 357 (void) acpidev_unregister_class(&acpidev_class_list_root,
359 358 &acpidev_class_scope);
360 359 error_out:
361 360 ACPIDEV_DEBUG(CE_WARN,
362 361 "!acpidev: failed to register built-in class drivers.");
363 362 *fp = 0;
364 363
365 364 return (AE_ERROR);
366 365 }
367 366
368 367 /*
369 368 * Called in single threaded context during boot, no protection for
370 369 * reentrance.
371 370 */
372 371 static ACPI_STATUS
373 372 acpidev_create_root_node(void)
374 373 {
375 374 int circ, rv = AE_OK;
376 375 dev_info_t *dip = NULL;
377 376 acpidev_data_handle_t objhdl;
378 377 char *compatibles[] = {
379 378 ACPIDEV_HID_ROOTNEX,
380 379 ACPIDEV_TYPE_ROOTNEX,
381 380 ACPIDEV_HID_VIRTNEX,
382 381 ACPIDEV_TYPE_VIRTNEX,
383 382 };
384 383
385 384 ndi_devi_enter(ddi_root_node(), &circ);
386 385 ASSERT(acpidev_root_dip == NULL);
387 386
388 387 /* Query whether device node already exists. */
389 388 dip = ddi_find_devinfo(ACPIDEV_NODE_NAME_ROOT, -1, 0);
390 389 if (dip != NULL && ddi_get_parent(dip) == ddi_root_node()) {
391 390 ndi_devi_exit(ddi_root_node(), circ);
392 391 cmn_err(CE_WARN, "!acpidev: node /devices/%s already exists, "
393 392 "disable driver.", ACPIDEV_NODE_NAME_ROOT);
394 393 return (AE_ALREADY_EXISTS);
395 394 }
396 395
397 396 /* Create the device node if it doesn't exist. */
398 397 rv = ndi_devi_alloc(ddi_root_node(), ACPIDEV_NODE_NAME_ROOT,
399 398 (pnode_t)DEVI_SID_NODEID, &dip);
400 399 if (rv != NDI_SUCCESS) {
401 400 ndi_devi_exit(ddi_root_node(), circ);
402 401 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to create device node "
403 402 "for ACPI root with errcode %d.", rv);
404 403 return (AE_ERROR);
405 404 }
406 405
407 406 /* Build cross reference between dip and ACPI object. */
408 407 if (ACPI_FAILURE(acpica_tag_devinfo(dip, ACPI_ROOT_OBJECT))) {
409 408 (void) ddi_remove_child(dip, 0);
410 409 ndi_devi_exit(ddi_root_node(), circ);
411 410 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to tag object %s.",
412 411 ACPIDEV_OBJECT_NAME_SB);
413 412 return (AE_ERROR);
414 413 }
415 414
416 415 /* Set device properties. */
417 416 rv = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
418 417 OBP_COMPATIBLE, ACPIDEV_ARRAY_PARAM(compatibles));
419 418 if (rv == NDI_SUCCESS) {
420 419 rv = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
421 420 OBP_DEVICETYPE, ACPIDEV_TYPE_ROOTNEX);
422 421 }
423 422 if (rv != DDI_SUCCESS) {
424 423 ACPIDEV_DEBUG(CE_WARN,
425 424 "!acpidev: failed to set device property for /devices/%s.",
426 425 ACPIDEV_NODE_NAME_ROOT);
427 426 goto error_out;
428 427 }
429 428
430 429 /* Manually create an object handle for the root node */
431 430 objhdl = acpidev_data_create_handle(ACPI_ROOT_OBJECT);
432 431 if (objhdl == NULL) {
433 432 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to create object "
434 433 "handle for the root node.");
435 434 goto error_out;
436 435 }
437 436 objhdl->aod_level = 0;
438 437 objhdl->aod_hdl = ACPI_ROOT_OBJECT;
439 438 objhdl->aod_dip = dip;
440 439 objhdl->aod_class = &acpidev_class_scope;
441 440 objhdl->aod_status = acpidev_query_device_status(ACPI_ROOT_OBJECT);
442 441 objhdl->aod_iflag = ACPIDEV_ODF_STATUS_VALID |
443 442 ACPIDEV_ODF_DEVINFO_CREATED | ACPIDEV_ODF_DEVINFO_TAGGED;
444 443
445 444 /* Bind device driver. */
446 445 (void) ndi_devi_bind_driver(dip, 0);
447 446
448 447 acpidev_root_dip = dip;
449 448 ndi_devi_exit(ddi_root_node(), circ);
450 449
451 450 return (AE_OK);
452 451
453 452 error_out:
454 453 (void) acpica_untag_devinfo(dip, ACPI_ROOT_OBJECT);
455 454 (void) ddi_remove_child(dip, 0);
456 455 ndi_devi_exit(ddi_root_node(), circ);
457 456 return (AE_ERROR);
458 457 }
459 458
460 459 static void
461 460 acpidev_initialize(void)
462 461 {
463 462 int rc;
464 463 char *str = NULL;
465 464 uint64_t features = 0;
466 465
467 466 /* Check whether it has already been initialized. */
468 467 if (acpidev_status == ACPIDEV_STATUS_DISABLED) {
469 468 cmn_err(CE_CONT, "?acpidev: ACPI device autoconfig "
470 469 "disabled by user.\n");
471 470 return;
472 471 } else if (acpidev_status != ACPIDEV_STATUS_UNKNOWN) {
473 472 ACPIDEV_DEBUG(CE_NOTE,
474 473 "!acpidev: initialization called more than once.");
475 474 return;
476 475 }
477 476
478 477 /* Check whether ACPI device autoconfig has been disabled by user. */
479 478 rc = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
480 479 DDI_PROP_DONTPASS, "acpidev-autoconfig", &str);
481 480 if (rc == DDI_SUCCESS) {
482 481 if (strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0) {
483 482 cmn_err(CE_CONT, "?acpidev: ACPI device autoconfig "
484 483 "disabled by user.\n");
485 484 ddi_prop_free(str);
486 485 acpidev_status = ACPIDEV_STATUS_DISABLED;
487 486 return;
488 487 }
489 488 ddi_prop_free(str);
490 489 }
491 490
492 491 /* Initialize acpica subsystem. */
493 492 if (ACPI_FAILURE(acpica_init())) {
494 493 cmn_err(CE_WARN,
495 494 "!acpidev: failed to initialize acpica subsystem.");
496 495 acpidev_status = ACPIDEV_STATUS_FAILED;
497 496 return;
498 497 }
499 498
500 499 /* Check ACPICA subsystem status. */
501 500 if (!acpica_get_core_feature(ACPI_FEATURE_FULL_INIT)) {
502 501 cmn_err(CE_WARN, "!acpidev: ACPICA hasn't been fully "
503 502 "initialized, ACPI device autoconfig will be disabled.");
504 503 acpidev_status = ACPIDEV_STATUS_DISABLED;
505 504 return;
506 505 }
507 506
508 507 /* Converts acpidev-options from type string to int, if any */
509 508 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
510 509 DDI_PROP_DONTPASS, "acpidev-options", &str) == DDI_PROP_SUCCESS) {
511 510 long data;
512 511 rc = ddi_strtol(str, NULL, 0, &data);
513 512 if (rc == 0) {
514 513 (void) e_ddi_prop_remove(DDI_DEV_T_NONE,
515 514 ddi_root_node(), "acpidev-options");
516 515 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE,
517 516 ddi_root_node(), "acpidev-options", data);
518 517 }
519 518 ddi_prop_free(str);
520 519 }
521 520 /* Get acpidev_options user options. */
522 521 acpidev_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
523 522 DDI_PROP_DONTPASS, "acpidev-options", acpidev_options);
524 523
525 524 /* Check whether ACPI based DR has been disabled by user. */
526 525 rc = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
527 526 DDI_PROP_DONTPASS, "acpidev-dr", &str);
528 527 if (rc == DDI_SUCCESS) {
529 528 if (strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0) {
530 529 cmn_err(CE_CONT, "?acpidev: ACPI based DR has been "
531 530 "disabled by user.\n");
532 531 acpidev_dr_enable = 0;
533 532 }
534 533 ddi_prop_free(str);
535 534 }
536 535
537 536 /* Register all device class drivers. */
538 537 if (ACPI_FAILURE(acpidev_class_list_init(&features))) {
539 538 cmn_err(CE_WARN,
540 539 "!acpidev: failed to initalize class driver lists.");
541 540 acpidev_status = ACPIDEV_STATUS_FAILED;
542 541 return;
543 542 }
544 543
545 544 /* Create root node for ACPI/firmware device subtree. */
546 545 if (ACPI_FAILURE(acpidev_create_root_node())) {
547 546 cmn_err(CE_WARN, "!acpidev: failed to create root node "
548 547 "for acpi device tree.");
549 548 acpidev_class_list_fini();
550 549 acpidev_status = ACPIDEV_STATUS_FAILED;
551 550 return;
552 551 }
553 552
554 553 /* Notify acpica to enable ACPI device auto configuration. */
555 554 acpica_set_core_feature(ACPI_FEATURE_DEVCFG);
556 555 acpica_set_devcfg_feature(features);
557 556
558 557 ACPIDEV_DEBUG(CE_NOTE, "!acpidev: ACPI device autoconfig initialized.");
559 558 acpidev_status = ACPIDEV_STATUS_INITIALIZED;
560 559 }
561 560
562 561 /*
563 562 * Probe devices in ACPI namespace which can't be enumerated by other methods
564 563 * at boot time.
565 564 */
566 565 static ACPI_STATUS
567 566 acpidev_boot_probe_device(acpidev_op_type_t op_type)
568 567 {
569 568 ACPI_STATUS rc = AE_OK;
570 569 acpidev_walk_info_t *infop;
571 570
572 571 ASSERT(acpidev_root_dip != NULL);
573 572 ASSERT(op_type == ACPIDEV_OP_BOOT_PROBE ||
574 573 op_type == ACPIDEV_OP_BOOT_REPROBE);
575 574
576 575 infop = acpidev_alloc_walk_info(op_type, 0, ACPI_ROOT_OBJECT,
577 576 &acpidev_class_list_root, NULL);
578 577 if (infop == NULL) {
579 578 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to allocate walk info "
580 579 "object in acpi_boot_probe_device().");
581 580 return (AE_ERROR);
582 581 }
583 582 /* Enumerate ACPI devices. */
584 583 rc = acpidev_probe_child(infop);
585 584 if (ACPI_FAILURE(rc)) {
586 585 cmn_err(CE_WARN, "!acpidev: failed to probe child object "
587 586 "under ACPI root node.");
588 587 }
589 588 acpidev_free_walk_info(infop);
590 589
591 590 return (rc);
592 591 }
593 592
594 593 /*
595 594 * Platform specific device prober for ACPI virtual bus.
596 595 * It will be called in single-threaded environment to enumerate devices in
597 596 * ACPI namespace at boot time.
598 597 */
599 598 static void
600 599 acpidev_boot_probe(int type)
601 600 {
602 601 ACPI_STATUS rc;
603 602
604 603 /* Initialize subsystem on first pass. */
605 604 mutex_enter(&acpidev_drv_lock);
606 605 if (type == 0) {
607 606 acpidev_initialize();
608 607 if (acpidev_status != ACPIDEV_STATUS_INITIALIZED &&
609 608 acpidev_status != ACPIDEV_STATUS_DISABLED) {
610 609 cmn_err(CE_WARN, "!acpidev: driver disabled due to "
611 610 "initalization failure.");
612 611 }
613 612 }
614 613
615 614 /* Probe ACPI devices */
616 615 if (type == 0 && acpidev_status == ACPIDEV_STATUS_INITIALIZED) {
617 616 rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_PROBE);
618 617 if (ACPI_SUCCESS(rc)) {
619 618 /*
620 619 * Support of DR operations will be disabled
621 620 * if failed to initialize DR subsystem.
622 621 */
623 622 rc = acpidev_dr_initialize(acpidev_root_dip);
624 623 if (ACPI_FAILURE(rc) && rc != AE_SUPPORT) {
625 624 cmn_err(CE_CONT, "?acpidev: failed to "
626 625 "initialize DR subsystem.");
627 626 }
628 627 acpidev_status = ACPIDEV_STATUS_FIRST_PASS;
629 628 } else {
630 629 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to probe ACPI "
631 630 "devices during boot.");
632 631 acpidev_status = ACPIDEV_STATUS_FAILED;
633 632 }
634 633 } else if (type != 0 && acpidev_status == ACPIDEV_STATUS_FIRST_PASS) {
635 634 rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_REPROBE);
636 635 if (ACPI_SUCCESS(rc)) {
637 636 acpidev_status = ACPIDEV_STATUS_READY;
638 637 } else {
639 638 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to reprobe "
640 639 "ACPI devices during boot.");
641 640 acpidev_status = ACPIDEV_STATUS_FAILED;
642 641 }
643 642 } else if (acpidev_status != ACPIDEV_STATUS_FAILED &&
644 643 acpidev_status != ACPIDEV_STATUS_DISABLED &&
645 644 acpidev_status != ACPIDEV_STATUS_READY) {
646 645 cmn_err(CE_WARN,
647 646 "!acpidev: invalid ACPI device autoconfig global status.");
648 647 }
649 648 mutex_exit(&acpidev_drv_lock);
650 649 }
651 650
652 651 ACPI_STATUS
653 652 acpidev_probe_child(acpidev_walk_info_t *infop)
654 653 {
655 654 int circ;
656 655 dev_info_t *pdip;
657 656 ACPI_STATUS res, rc = AE_OK;
658 657 ACPI_HANDLE child;
659 658 ACPI_OBJECT_TYPE type;
660 659 acpidev_class_list_t *it;
661 660 acpidev_walk_info_t *cinfop;
662 661 acpidev_data_handle_t datap;
663 662
664 663 /* Validate parameter first. */
665 664 ASSERT(infop != NULL);
666 665 if (infop == NULL) {
667 666 ACPIDEV_DEBUG(CE_WARN,
668 667 "!acpidev: infop is NULL in acpidev_probe_child().");
669 668 return (AE_BAD_PARAMETER);
670 669 }
671 670 ASSERT(infop->awi_level < ACPIDEV_MAX_ENUM_LEVELS - 1);
672 671 if (infop->awi_level >= ACPIDEV_MAX_ENUM_LEVELS - 1) {
673 672 ACPIDEV_DEBUG(CE_WARN, "!acpidev: recursive level is too deep "
674 673 "in acpidev_probe_child().");
675 674 return (AE_BAD_PARAMETER);
676 675 }
677 676 ASSERT(infop->awi_class_list != NULL);
678 677 ASSERT(infop->awi_hdl != NULL);
679 678 ASSERT(infop->awi_info != NULL);
680 679 ASSERT(infop->awi_name != NULL);
681 680 ASSERT(infop->awi_data != NULL);
682 681 if (infop->awi_class_list == NULL || infop->awi_hdl == NULL ||
683 682 infop->awi_info == NULL || infop->awi_name == NULL ||
684 683 infop->awi_data == NULL) {
685 684 ACPIDEV_DEBUG(CE_WARN, "!acpidev: infop has NULL fields in "
686 685 "acpidev_probe_child().");
687 686 return (AE_BAD_PARAMETER);
688 687 }
689 688 pdip = acpidev_walk_info_get_pdip(infop);
690 689 if (pdip == NULL) {
691 690 ACPIDEV_DEBUG(CE_WARN,
692 691 "!acpidev: pdip is NULL in acpidev_probe_child().");
693 692 return (AE_BAD_PARAMETER);
694 693 }
695 694
696 695 ndi_devi_enter(pdip, &circ);
697 696 rw_enter(&acpidev_class_lock, RW_READER);
698 697
699 698 /* Call pre-probe callback functions. */
700 699 for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
701 700 if (it->acl_class->adc_pre_probe == NULL) {
702 701 continue;
703 702 }
704 703 infop->awi_class_curr = it->acl_class;
705 704 if (ACPI_FAILURE(it->acl_class->adc_pre_probe(infop))) {
706 705 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to pre-probe "
707 706 "device of type %s under %s.",
708 707 it->acl_class->adc_class_name, infop->awi_name);
709 708 }
710 709 }
711 710
712 711 /* Walk child objects. */
713 712 child = NULL;
714 713 while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_ANY,
715 714 infop->awi_hdl, child, &child))) {
716 715 /* Skip object if we're not interested in it. */
717 716 if (ACPI_FAILURE(AcpiGetType(child, &type)) ||
718 717 type > ACPI_TYPE_NS_NODE_MAX ||
719 718 BT_TEST(acpidev_object_type_mask, type) == 0) {
720 719 continue;
721 720 }
722 721
723 722 /* It's another hotplug-capable board, skip it. */
724 723 if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE &&
725 724 acpidev_dr_device_is_board(child)) {
726 725 continue;
727 726 }
728 727
729 728 /* Allocate the walk info structure. */
730 729 cinfop = acpidev_alloc_walk_info(infop->awi_op_type,
731 730 infop->awi_level + 1, child, NULL, infop);
732 731 if (cinfop == NULL) {
733 732 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to allocate "
734 733 "walk info child object of %s.",
735 734 infop->awi_name);
736 735 /* Mark error and continue to handle next child. */
737 736 rc = AE_ERROR;
738 737 continue;
739 738 }
740 739
741 740 /*
742 741 * Remember the class list used to handle this object.
743 742 * It should be the same list for different passes of scans.
744 743 */
745 744 ASSERT(cinfop->awi_data != NULL);
746 745 datap = cinfop->awi_data;
747 746 if (cinfop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
748 747 datap->aod_class_list = infop->awi_class_list;
749 748 }
750 749
751 750 /* Call registered process callbacks. */
752 751 for (it = *(infop->awi_class_list); it != NULL;
753 752 it = it->acl_next) {
754 753 if (it->acl_class->adc_probe == NULL) {
755 754 continue;
756 755 }
757 756 cinfop->awi_class_curr = it->acl_class;
758 757 res = it->acl_class->adc_probe(cinfop);
759 758 if (ACPI_FAILURE(res)) {
760 759 rc = res;
761 760 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
762 761 "process object of type %s under %s.",
763 762 it->acl_class->adc_class_name,
764 763 infop->awi_name);
765 764 }
766 765 }
767 766
768 767 /* Free resources. */
769 768 acpidev_free_walk_info(cinfop);
770 769 }
771 770
772 771 /* Call post-probe callback functions. */
773 772 for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
774 773 if (it->acl_class->adc_post_probe == NULL) {
775 774 continue;
776 775 }
777 776 infop->awi_class_curr = it->acl_class;
778 777 if (ACPI_FAILURE(it->acl_class->adc_post_probe(infop))) {
779 778 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to post-probe "
780 779 "device of type %s under %s.",
781 780 it->acl_class->adc_class_name, infop->awi_name);
782 781 }
783 782 }
784 783
785 784 rw_exit(&acpidev_class_lock);
786 785 ndi_devi_exit(pdip, circ);
787 786
788 787 return (rc);
789 788 }
790 789
791 790 ACPI_STATUS
792 791 acpidev_process_object(acpidev_walk_info_t *infop, int flags)
793 792 {
794 793 ACPI_STATUS rc = AE_OK;
795 794 char *devname;
796 795 dev_info_t *dip, *pdip;
797 796 ACPI_HANDLE hdl;
798 797 ACPI_DEVICE_INFO *adip;
799 798 acpidev_class_t *clsp;
800 799 acpidev_data_handle_t datap;
801 800 acpidev_filter_result_t res;
802 801
803 802 /* Validate parameters first. */
804 803 ASSERT(infop != NULL);
805 804 if (infop == NULL) {
806 805 ACPIDEV_DEBUG(CE_WARN,
807 806 "!acpidev: infop is NULL in acpidev_process_object().");
808 807 return (AE_BAD_PARAMETER);
809 808 }
810 809 ASSERT(infop->awi_hdl != NULL);
811 810 ASSERT(infop->awi_info != NULL);
812 811 ASSERT(infop->awi_data != NULL);
813 812 ASSERT(infop->awi_class_curr != NULL);
814 813 ASSERT(infop->awi_class_curr->adc_filter != NULL);
815 814 hdl = infop->awi_hdl;
816 815 adip = infop->awi_info;
817 816 datap = infop->awi_data;
818 817 clsp = infop->awi_class_curr;
819 818 if (hdl == NULL || datap == NULL || adip == NULL || clsp == NULL ||
820 819 clsp->adc_filter == NULL) {
821 820 ACPIDEV_DEBUG(CE_WARN, "!acpidev: infop has NULL pointer in "
822 821 "acpidev_process_object().");
823 822 return (AE_BAD_PARAMETER);
824 823 }
825 824 pdip = acpidev_walk_info_get_pdip(infop);
826 825 if (pdip == NULL) {
827 826 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to get pdip for %s "
828 827 "in acpidev_process_object().", infop->awi_name);
829 828 return (AE_BAD_PARAMETER);
830 829 }
831 830
832 831 /*
833 832 * Check whether the object has already been handled.
834 833 * Tag and child dip pointer are used to indicate the object has been
835 834 * handled by the ACPI auto configure driver. It has the
836 835 * following usages:
837 836 * 1) Prevent creating dip for objects which already have a dip
838 837 * when reloading the ACPI auto configure driver.
839 838 * 2) Prevent creating multiple dips for ACPI objects with ACPI
840 839 * aliases. Currently ACPICA framework has no way to tell whether
841 840 * an object is an alias or not for some types of object. So tag
842 841 * is used to indicate that the object has been handled.
843 842 * 3) Prevent multiple class drivers from creating multiple devices for
844 843 * the same ACPI object.
845 844 */
846 845 if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
847 846 (flags & ACPIDEV_PROCESS_FLAG_CHECK) &&
848 847 !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
849 848 (infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED)) {
850 849 ASSERT(infop->awi_dip != NULL);
851 850 ACPIDEV_DEBUG(CE_NOTE,
852 851 "!acpidev: device has already been created for object %s.",
853 852 infop->awi_name);
854 853 return (AE_ALREADY_EXISTS);
855 854 }
856 855
857 856 /*
858 857 * Determine action according to following rules based on device
859 858 * status returned by _STA method. Please refer to ACPI3.0b section
860 859 * 6.3.1 and 6.5.1.
861 860 * present functioning enabled Action
862 861 * 0 0 x Do nothing
863 862 * 1 x 0 Do nothing
864 863 * 1 x 1 Create node and scan child
865 864 * x 1 0 Do nothing
866 865 * x 1 1 Create node and scan child
867 866 */
868 867 if ((datap->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0 ||
869 868 (flags & ACPIDEV_PROCESS_FLAG_SYNCSTATUS)) {
870 869 if (adip->Valid & ACPI_VALID_STA) {
871 870 datap->aod_status = adip->CurrentStatus;
872 871 } else {
873 872 datap->aod_status = acpidev_query_device_status(hdl);
874 873 }
875 874 datap->aod_iflag |= ACPIDEV_ODF_STATUS_VALID;
876 875 }
877 876 if (!acpidev_check_device_enabled(datap->aod_status)) {
878 877 ACPIDEV_DEBUG(CE_NOTE, "!acpidev: object %s doesn't exist.",
879 878 infop->awi_name);
880 879 /*
881 880 * Need to scan for hotplug-capable boards even if object
882 881 * doesn't exist or has been disabled during the first pass.
883 882 * So just disable creating device node and keep on scanning.
884 883 */
885 884 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
886 885 flags &= ~ACPIDEV_PROCESS_FLAG_CREATE;
887 886 } else {
888 887 return (AE_NOT_EXIST);
889 888 }
890 889 }
891 890
892 891 ASSERT(infop->awi_data != NULL);
893 892 ASSERT(infop->awi_parent != NULL);
894 893 ASSERT(infop->awi_parent->awi_data != NULL);
895 894 if (flags & ACPIDEV_PROCESS_FLAG_CREATE) {
896 895 mutex_enter(&(DEVI(pdip)->devi_lock));
897 896 /*
898 897 * Put the device into offline state if its parent is in
899 898 * offline state.
900 899 */
901 900 if (DEVI_IS_DEVICE_OFFLINE(pdip)) {
902 901 flags |= ACPIDEV_PROCESS_FLAG_OFFLINE;
903 902 }
904 903 mutex_exit(&(DEVI(pdip)->devi_lock));
905 904 }
906 905
907 906 /* Evaluate filtering rules and generate device name. */
908 907 devname = kmem_zalloc(ACPIDEV_MAX_NAMELEN + 1, KM_SLEEP);
909 908 (void) memcpy(devname, (char *)&adip->Name, sizeof (adip->Name));
910 909 if (flags & ACPIDEV_PROCESS_FLAG_CREATE) {
911 910 res = clsp->adc_filter(infop, devname, ACPIDEV_MAX_NAMELEN);
912 911 } else {
913 912 res = clsp->adc_filter(infop, NULL, 0);
914 913 }
915 914
916 915 /* Create device if requested. */
917 916 if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
918 917 !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
919 918 !(infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED) &&
920 919 (res == ACPIDEV_FILTER_DEFAULT || res == ACPIDEV_FILTER_CREATE)) {
921 920 int ret;
922 921
923 922 /*
924 923 * Allocate dip and set default properties.
925 924 * Properties can be overriden in class specific init routines.
926 925 */
927 926 ASSERT(infop->awi_dip == NULL);
928 927 ndi_devi_alloc_sleep(pdip, devname, (pnode_t)DEVI_SID_NODEID,
929 928 &dip);
930 929 infop->awi_dip = dip;
931 930 ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
932 931 OBP_DEVICETYPE, clsp->adc_dev_type);
933 932 if (ret != NDI_SUCCESS) {
934 933 ACPIDEV_DEBUG(CE_WARN,
935 934 "!acpidev: failed to set device property for %s.",
936 935 infop->awi_name);
937 936 (void) ddi_remove_child(dip, 0);
938 937 infop->awi_dip = NULL;
939 938 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
940 939 return (AE_ERROR);
941 940 }
942 941
943 942 /* Build cross reference between dip and ACPI object. */
944 943 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0 &&
945 944 ACPI_FAILURE(acpica_tag_devinfo(dip, hdl))) {
946 945 cmn_err(CE_WARN,
947 946 "!acpidev: failed to tag object %s.",
948 947 infop->awi_name);
949 948 (void) ddi_remove_child(dip, 0);
950 949 infop->awi_dip = NULL;
951 950 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
952 951 return (AE_ERROR);
953 952 }
954 953
955 954 /* Call class specific initialization callback. */
956 955 if (clsp->adc_init != NULL &&
957 956 ACPI_FAILURE(clsp->adc_init(infop))) {
958 957 ACPIDEV_DEBUG(CE_WARN,
959 958 "!acpidev: failed to initialize device %s.",
960 959 infop->awi_name);
961 960 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
962 961 (void) acpica_untag_devinfo(dip, hdl);
963 962 }
964 963 (void) ddi_remove_child(dip, 0);
965 964 infop->awi_dip = NULL;
966 965 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
967 966 return (AE_ERROR);
968 967 }
969 968
970 969 /* Set device into offline state if requested. */
971 970 if (flags & ACPIDEV_PROCESS_FLAG_OFFLINE) {
972 971 mutex_enter(&(DEVI(dip)->devi_lock));
973 972 DEVI_SET_DEVICE_OFFLINE(dip);
974 973 mutex_exit(&(DEVI(dip)->devi_lock));
975 974 }
976 975
977 976 /* Mark status */
978 977 infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED;
979 978 datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_CREATED;
980 979 datap->aod_dip = dip;
981 980 datap->aod_class = clsp;
982 981 /* Hold reference count on class driver. */
983 982 atomic_inc_32(&clsp->adc_refcnt);
984 983 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
985 984 datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_TAGGED;
986 985 }
987 986
988 987 /* Bind device driver. */
989 988 if ((flags & ACPIDEV_PROCESS_FLAG_NOBIND) != 0) {
990 989 mutex_enter(&(DEVI(dip)->devi_lock));
991 990 DEVI(dip)->devi_flags |= DEVI_NO_BIND;
992 991 mutex_exit(&(DEVI(dip)->devi_lock));
993 992 } else {
994 993 (void) ndi_devi_bind_driver(dip, 0);
995 994 }
996 995
997 996 /* Hold reference on branch when hot-adding devices. */
998 997 if (flags & ACPIDEV_PROCESS_FLAG_HOLDBRANCH) {
999 998 e_ddi_branch_hold(dip);
1000 999 }
1001 1000 }
1002 1001
1003 1002 /* Free resources */
1004 1003 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
1005 1004 rc = AE_OK;
1006 1005
1007 1006 /* Recursively scan child objects if requested. */
1008 1007 switch (res) {
1009 1008 case ACPIDEV_FILTER_DEFAULT:
1010 1009 /* FALLTHROUGH */
1011 1010 case ACPIDEV_FILTER_SCAN:
1012 1011 /* Check if we need to scan child. */
1013 1012 if ((flags & ACPIDEV_PROCESS_FLAG_SCAN) &&
1014 1013 !(infop->awi_flags & ACPIDEV_WI_DISABLE_SCAN) &&
1015 1014 !(infop->awi_flags & ACPIDEV_WI_CHILD_SCANNED)) {
1016 1015 /* probe child object. */
1017 1016 rc = acpidev_probe_child(infop);
1018 1017 if (ACPI_FAILURE(rc)) {
1019 1018 ACPIDEV_DEBUG(CE_WARN,
1020 1019 "!acpidev: failed to probe subtree of %s.",
1021 1020 infop->awi_name);
1022 1021 rc = AE_ERROR;
1023 1022 }
1024 1023 /* Mark object as scanned. */
1025 1024 infop->awi_flags |= ACPIDEV_WI_CHILD_SCANNED;
1026 1025 }
1027 1026 break;
1028 1027
1029 1028 case ACPIDEV_FILTER_CREATE:
1030 1029 /* FALLTHROUGH */
1031 1030 case ACPIDEV_FILTER_CONTINUE:
1032 1031 /* FALLTHROUGH */
1033 1032 case ACPIDEV_FILTER_SKIP:
1034 1033 break;
1035 1034
1036 1035 case ACPIDEV_FILTER_FAILED:
1037 1036 ACPIDEV_DEBUG(CE_WARN,
1038 1037 "!acpidev: failed to probe device for %s.",
1039 1038 infop->awi_name);
1040 1039 rc = AE_ERROR;
1041 1040 break;
1042 1041
1043 1042 default:
1044 1043 cmn_err(CE_WARN,
1045 1044 "!acpidev: unknown filter result code %d.", res);
1046 1045 rc = AE_ERROR;
1047 1046 break;
1048 1047 }
1049 1048
1050 1049 return (rc);
1051 1050 }
1052 1051
1053 1052 acpidev_filter_result_t
1054 1053 acpidev_filter_default(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
1055 1054 acpidev_filter_rule_t *afrp, char *devname, int len)
1056 1055 {
1057 1056 _NOTE(ARGUNUSED(hdl));
1058 1057
1059 1058 ASSERT(afrp != NULL);
1060 1059 ASSERT(devname == NULL || len >= ACPIDEV_MAX_NAMELEN);
1061 1060 if (infop->awi_level < afrp->adf_minlvl ||
1062 1061 infop->awi_level > afrp->adf_maxlvl) {
1063 1062 return (ACPIDEV_FILTER_CONTINUE);
1064 1063 } else if (afrp->adf_pattern != NULL &&
1065 1064 strncmp(afrp->adf_pattern,
1066 1065 (char *)&infop->awi_info->Name,
1067 1066 sizeof (infop->awi_info->Name))) {
1068 1067 return (ACPIDEV_FILTER_CONTINUE);
1069 1068 }
1070 1069 if (afrp->adf_replace != NULL && devname != NULL) {
1071 1070 (void) strlcpy(devname, afrp->adf_replace, len);
1072 1071 }
1073 1072
1074 1073 return (afrp->adf_retcode);
1075 1074 }
1076 1075
1077 1076 acpidev_filter_result_t
1078 1077 acpidev_filter_device(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
1079 1078 acpidev_filter_rule_t *afrp, int entries, char *devname, int len)
1080 1079 {
1081 1080 acpidev_filter_result_t res;
1082 1081
1083 1082 /* Evaluate filtering rules. */
1084 1083 for (; entries > 0; entries--, afrp++) {
1085 1084 if (afrp->adf_filter_func != NULL) {
1086 1085 res = afrp->adf_filter_func(infop, hdl, afrp,
1087 1086 devname, len);
1088 1087 } else {
1089 1088 res = acpidev_filter_default(infop, hdl, afrp,
1090 1089 devname, len);
1091 1090 }
1092 1091 if (res == ACPIDEV_FILTER_DEFAULT ||
1093 1092 res == ACPIDEV_FILTER_SCAN) {
1094 1093 infop->awi_class_list = afrp->adf_class_list;
1095 1094 break;
1096 1095 }
1097 1096 }
1098 1097
1099 1098 return (res);
1100 1099 }
1101 1100
1102 1101 dev_info_t *
1103 1102 acpidev_root_node(void)
1104 1103 {
1105 1104 return (acpidev_root_dip);
1106 1105 }
1107 1106
1108 1107 ACPI_STATUS
1109 1108 acpidev_register_class(acpidev_class_list_t **listpp, acpidev_class_t *clsp,
1110 1109 boolean_t tail)
1111 1110 {
1112 1111 ACPI_STATUS rc;
1113 1112 acpidev_class_list_t *item;
1114 1113 acpidev_class_list_t *temp;
1115 1114
1116 1115 ASSERT(clsp != NULL);
1117 1116 ASSERT(listpp != NULL);
1118 1117 if (listpp == NULL || clsp == NULL) {
1119 1118 ACPIDEV_DEBUG(CE_WARN,
1120 1119 "!acpidev: invalid parameter in acpidev_register_class().");
1121 1120 return (AE_BAD_PARAMETER);
1122 1121 } else if (clsp->adc_version != ACPIDEV_CLASS_REV) {
1123 1122 cmn_err(CE_WARN,
1124 1123 "!acpidev: class driver %s version mismatch.",
1125 1124 clsp->adc_class_name);
1126 1125 return (AE_BAD_DATA);
1127 1126 }
1128 1127
1129 1128 rc = AE_OK;
1130 1129 item = kmem_zalloc(sizeof (*item), KM_SLEEP);
1131 1130 item->acl_class = clsp;
1132 1131 rw_enter(&acpidev_class_lock, RW_WRITER);
1133 1132 /* Check for duplicated item. */
1134 1133 for (temp = *listpp; temp != NULL; temp = temp->acl_next) {
1135 1134 if (temp->acl_class == clsp) {
1136 1135 cmn_err(CE_WARN,
1137 1136 "!acpidev: register duplicate class driver %s.",
1138 1137 clsp->adc_class_name);
1139 1138 rc = AE_ALREADY_EXISTS;
1140 1139 break;
1141 1140 }
1142 1141 }
1143 1142 if (ACPI_SUCCESS(rc)) {
1144 1143 if (tail) {
1145 1144 while (*listpp) {
1146 1145 listpp = &(*listpp)->acl_next;
1147 1146 }
1148 1147 }
1149 1148 item->acl_next = *listpp;
1150 1149 *listpp = item;
1151 1150 }
1152 1151 rw_exit(&acpidev_class_lock);
1153 1152 if (ACPI_FAILURE(rc)) {
1154 1153 kmem_free(item, sizeof (*item));
1155 1154 }
1156 1155
1157 1156 return (rc);
1158 1157 }
1159 1158
1160 1159 ACPI_STATUS
1161 1160 acpidev_unregister_class(acpidev_class_list_t **listpp,
1162 1161 acpidev_class_t *clsp)
1163 1162 {
1164 1163 ACPI_STATUS rc = AE_NOT_FOUND;
1165 1164 acpidev_class_list_t *temp;
1166 1165
1167 1166 ASSERT(clsp != NULL);
1168 1167 ASSERT(listpp != NULL);
1169 1168 if (listpp == NULL || clsp == NULL) {
1170 1169 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameter "
1171 1170 "in acpidev_unregister_class().");
1172 1171 return (AE_BAD_PARAMETER);
1173 1172 }
1174 1173
1175 1174 rw_enter(&acpidev_class_lock, RW_WRITER);
1176 1175 for (temp = NULL; *listpp; listpp = &(*listpp)->acl_next) {
1177 1176 if ((*listpp)->acl_class == clsp) {
1178 1177 temp = *listpp;
1179 1178 *listpp = (*listpp)->acl_next;
1180 1179 break;
1181 1180 }
1182 1181 }
1183 1182 if (temp == NULL) {
1184 1183 ACPIDEV_DEBUG(CE_WARN, "!acpidev: class %p(%s) doesn't exist "
1185 1184 "in acpidev_unregister_class().",
1186 1185 (void *)clsp, clsp->adc_class_name);
1187 1186 rc = AE_NOT_FOUND;
1188 1187 } else if (temp->acl_class->adc_refcnt != 0) {
1189 1188 ACPIDEV_DEBUG(CE_WARN, "!acpidev: class %p(%s) is still in use "
1190 1189 "in acpidev_unregister_class()..",
1191 1190 (void *)clsp, clsp->adc_class_name);
1192 1191 rc = AE_ERROR;
1193 1192 } else {
1194 1193 kmem_free(temp, sizeof (*temp));
1195 1194 rc = AE_OK;
1196 1195 }
1197 1196 rw_exit(&acpidev_class_lock);
1198 1197
1199 1198 return (rc);
1200 1199 }
↓ open down ↓ |
1081 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX