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