110394SMichael.Corcoran@Sun.COM /*
210394SMichael.Corcoran@Sun.COM * CDDL HEADER START
310394SMichael.Corcoran@Sun.COM *
410394SMichael.Corcoran@Sun.COM * The contents of this file are subject to the terms of the
510394SMichael.Corcoran@Sun.COM * Common Development and Distribution License (the "License").
610394SMichael.Corcoran@Sun.COM * You may not use this file except in compliance with the License.
710394SMichael.Corcoran@Sun.COM *
810394SMichael.Corcoran@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910394SMichael.Corcoran@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010394SMichael.Corcoran@Sun.COM * See the License for the specific language governing permissions
1110394SMichael.Corcoran@Sun.COM * and limitations under the License.
1210394SMichael.Corcoran@Sun.COM *
1310394SMichael.Corcoran@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410394SMichael.Corcoran@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510394SMichael.Corcoran@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610394SMichael.Corcoran@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710394SMichael.Corcoran@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810394SMichael.Corcoran@Sun.COM *
1910394SMichael.Corcoran@Sun.COM * CDDL HEADER END
2010394SMichael.Corcoran@Sun.COM */
2110394SMichael.Corcoran@Sun.COM /*
22*12004Sjiang.liu@intel.com * Copyright (c) 2009-2010, Intel Corporation.
2310394SMichael.Corcoran@Sun.COM * All rights reserved.
2410394SMichael.Corcoran@Sun.COM */
2510394SMichael.Corcoran@Sun.COM
2610394SMichael.Corcoran@Sun.COM #include <sys/types.h>
2710394SMichael.Corcoran@Sun.COM #include <sys/atomic.h>
2810394SMichael.Corcoran@Sun.COM #include <sys/sunddi.h>
2910394SMichael.Corcoran@Sun.COM #include <sys/sunndi.h>
3010394SMichael.Corcoran@Sun.COM #include <sys/acpi/acpi.h>
3110394SMichael.Corcoran@Sun.COM #include <sys/acpica.h>
3210394SMichael.Corcoran@Sun.COM #include <sys/acpidev.h>
3310394SMichael.Corcoran@Sun.COM #include <sys/acpidev_impl.h>
3410394SMichael.Corcoran@Sun.COM
3510394SMichael.Corcoran@Sun.COM static ACPI_STATUS acpidev_device_probe(acpidev_walk_info_t *infop);
3610394SMichael.Corcoran@Sun.COM static acpidev_filter_result_t acpidev_device_filter(acpidev_walk_info_t *infop,
3710394SMichael.Corcoran@Sun.COM char *devname, int maxlen);
3810394SMichael.Corcoran@Sun.COM static ACPI_STATUS acpidev_device_init(acpidev_walk_info_t *infop);
3910394SMichael.Corcoran@Sun.COM
4010394SMichael.Corcoran@Sun.COM static uint32_t acpidev_device_unitaddr = 0;
4110394SMichael.Corcoran@Sun.COM
4210394SMichael.Corcoran@Sun.COM /*
4310394SMichael.Corcoran@Sun.COM * Default class driver for ACPI DEVICE objects.
4410394SMichael.Corcoran@Sun.COM * The default policy for DEVICE objects is to scan child objects without
4510394SMichael.Corcoran@Sun.COM * creating device nodes. But some special DEVICE objects will have device
4610394SMichael.Corcoran@Sun.COM * nodes created for them.
4710394SMichael.Corcoran@Sun.COM */
4810394SMichael.Corcoran@Sun.COM acpidev_class_t acpidev_class_device = {
4910394SMichael.Corcoran@Sun.COM 0, /* adc_refcnt */
5010394SMichael.Corcoran@Sun.COM ACPIDEV_CLASS_REV1, /* adc_version */
5110394SMichael.Corcoran@Sun.COM ACPIDEV_CLASS_ID_DEVICE, /* adc_class_id */
5210394SMichael.Corcoran@Sun.COM "ACPI Device", /* adc_class_name */
5310394SMichael.Corcoran@Sun.COM ACPIDEV_TYPE_DEVICE, /* adc_dev_type */
5410394SMichael.Corcoran@Sun.COM NULL, /* adc_private */
5510394SMichael.Corcoran@Sun.COM NULL, /* adc_pre_probe */
5610394SMichael.Corcoran@Sun.COM NULL, /* adc_post_probe */
5710394SMichael.Corcoran@Sun.COM acpidev_device_probe, /* adc_probe */
5810394SMichael.Corcoran@Sun.COM acpidev_device_filter, /* adc_filter */
5910394SMichael.Corcoran@Sun.COM acpidev_device_init, /* adc_init */
6010394SMichael.Corcoran@Sun.COM NULL, /* adc_fini */
6110394SMichael.Corcoran@Sun.COM };
6210394SMichael.Corcoran@Sun.COM
6310394SMichael.Corcoran@Sun.COM /*
6410394SMichael.Corcoran@Sun.COM * List of class drivers which will be called in order when handling
6510394SMichael.Corcoran@Sun.COM * children of ACPI DEVICE objects.
6610394SMichael.Corcoran@Sun.COM */
6710394SMichael.Corcoran@Sun.COM acpidev_class_list_t *acpidev_class_list_device = NULL;
6810394SMichael.Corcoran@Sun.COM
6910394SMichael.Corcoran@Sun.COM /* Filter rule table for boot. */
7010394SMichael.Corcoran@Sun.COM static acpidev_filter_rule_t acpidev_device_filters[] = {
7110394SMichael.Corcoran@Sun.COM { /* _SB_ object type is hardcoded to DEVICE by acpica */
7210394SMichael.Corcoran@Sun.COM NULL,
7310394SMichael.Corcoran@Sun.COM 0,
7410394SMichael.Corcoran@Sun.COM ACPIDEV_FILTER_DEFAULT,
7510394SMichael.Corcoran@Sun.COM &acpidev_class_list_device,
7610394SMichael.Corcoran@Sun.COM 1,
7710394SMichael.Corcoran@Sun.COM 1,
7810394SMichael.Corcoran@Sun.COM ACPIDEV_OBJECT_NAME_SB,
7910394SMichael.Corcoran@Sun.COM ACPIDEV_NODE_NAME_MODULE_SBD,
8010394SMichael.Corcoran@Sun.COM },
8110394SMichael.Corcoran@Sun.COM { /* Ignore other device objects under ACPI root object */
8210394SMichael.Corcoran@Sun.COM NULL,
8310394SMichael.Corcoran@Sun.COM 0,
8410394SMichael.Corcoran@Sun.COM ACPIDEV_FILTER_SKIP,
8510394SMichael.Corcoran@Sun.COM NULL,
8610394SMichael.Corcoran@Sun.COM 1,
8710394SMichael.Corcoran@Sun.COM 1,
8810394SMichael.Corcoran@Sun.COM NULL,
8910394SMichael.Corcoran@Sun.COM NULL,
9010394SMichael.Corcoran@Sun.COM },
9110394SMichael.Corcoran@Sun.COM { /* Scan other device objects not directly under ACPI root */
9210394SMichael.Corcoran@Sun.COM NULL,
9310394SMichael.Corcoran@Sun.COM 0,
9410394SMichael.Corcoran@Sun.COM ACPIDEV_FILTER_SKIP,
9510394SMichael.Corcoran@Sun.COM &acpidev_class_list_device,
9610394SMichael.Corcoran@Sun.COM 2,
9710394SMichael.Corcoran@Sun.COM INT_MAX,
9810394SMichael.Corcoran@Sun.COM NULL,
9910394SMichael.Corcoran@Sun.COM NULL,
10010394SMichael.Corcoran@Sun.COM }
10110394SMichael.Corcoran@Sun.COM };
10210394SMichael.Corcoran@Sun.COM
10310394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_device_probe(acpidev_walk_info_t * infop)10410394SMichael.Corcoran@Sun.COM acpidev_device_probe(acpidev_walk_info_t *infop)
10510394SMichael.Corcoran@Sun.COM {
106*12004Sjiang.liu@intel.com ACPI_STATUS rc = AE_OK;
10710394SMichael.Corcoran@Sun.COM int flags;
10810394SMichael.Corcoran@Sun.COM
10910394SMichael.Corcoran@Sun.COM ASSERT(infop != NULL);
11010394SMichael.Corcoran@Sun.COM ASSERT(infop->awi_hdl != NULL);
11110394SMichael.Corcoran@Sun.COM ASSERT(infop->awi_info != NULL);
11210394SMichael.Corcoran@Sun.COM
11310394SMichael.Corcoran@Sun.COM if (infop->awi_info->Type != ACPI_TYPE_DEVICE) {
11410394SMichael.Corcoran@Sun.COM return (AE_OK);
11510394SMichael.Corcoran@Sun.COM }
11610394SMichael.Corcoran@Sun.COM
117*12004Sjiang.liu@intel.com flags = ACPIDEV_PROCESS_FLAG_SCAN;
118*12004Sjiang.liu@intel.com switch (infop->awi_op_type) {
119*12004Sjiang.liu@intel.com case ACPIDEV_OP_BOOT_PROBE:
120*12004Sjiang.liu@intel.com flags |= ACPIDEV_PROCESS_FLAG_CREATE;
121*12004Sjiang.liu@intel.com break;
122*12004Sjiang.liu@intel.com
123*12004Sjiang.liu@intel.com case ACPIDEV_OP_BOOT_REPROBE:
124*12004Sjiang.liu@intel.com break;
125*12004Sjiang.liu@intel.com
126*12004Sjiang.liu@intel.com case ACPIDEV_OP_HOTPLUG_PROBE:
127*12004Sjiang.liu@intel.com flags |= ACPIDEV_PROCESS_FLAG_CREATE |
128*12004Sjiang.liu@intel.com ACPIDEV_PROCESS_FLAG_SYNCSTATUS |
129*12004Sjiang.liu@intel.com ACPIDEV_PROCESS_FLAG_HOLDBRANCH;
130*12004Sjiang.liu@intel.com break;
131*12004Sjiang.liu@intel.com
132*12004Sjiang.liu@intel.com default:
13310394SMichael.Corcoran@Sun.COM ACPIDEV_DEBUG(CE_WARN,
134*12004Sjiang.liu@intel.com "!acpidev: unknown operation type %u in "
13510394SMichael.Corcoran@Sun.COM "acpi_device_probe().", infop->awi_op_type);
13610394SMichael.Corcoran@Sun.COM rc = AE_BAD_PARAMETER;
137*12004Sjiang.liu@intel.com break;
138*12004Sjiang.liu@intel.com }
139*12004Sjiang.liu@intel.com
140*12004Sjiang.liu@intel.com if (rc == AE_OK) {
141*12004Sjiang.liu@intel.com rc = acpidev_process_object(infop, flags);
14210394SMichael.Corcoran@Sun.COM }
14310394SMichael.Corcoran@Sun.COM if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
14410394SMichael.Corcoran@Sun.COM cmn_err(CE_WARN,
14510394SMichael.Corcoran@Sun.COM "!acpidev: failed to process device object %s.",
14610394SMichael.Corcoran@Sun.COM infop->awi_name);
14710394SMichael.Corcoran@Sun.COM } else {
14810394SMichael.Corcoran@Sun.COM rc = AE_OK;
14910394SMichael.Corcoran@Sun.COM }
15010394SMichael.Corcoran@Sun.COM
15110394SMichael.Corcoran@Sun.COM return (rc);
15210394SMichael.Corcoran@Sun.COM }
15310394SMichael.Corcoran@Sun.COM
15410394SMichael.Corcoran@Sun.COM static acpidev_filter_result_t
acpidev_device_filter(acpidev_walk_info_t * infop,char * devname,int maxlen)15510394SMichael.Corcoran@Sun.COM acpidev_device_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
15610394SMichael.Corcoran@Sun.COM {
15710394SMichael.Corcoran@Sun.COM acpidev_filter_result_t res;
15810394SMichael.Corcoran@Sun.COM
15910394SMichael.Corcoran@Sun.COM ASSERT(infop != NULL);
16010394SMichael.Corcoran@Sun.COM if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
16110394SMichael.Corcoran@Sun.COM infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
16210394SMichael.Corcoran@Sun.COM infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
16310394SMichael.Corcoran@Sun.COM res = acpidev_filter_device(infop, infop->awi_hdl,
16410394SMichael.Corcoran@Sun.COM ACPIDEV_ARRAY_PARAM(acpidev_device_filters),
16510394SMichael.Corcoran@Sun.COM devname, maxlen);
16610394SMichael.Corcoran@Sun.COM } else {
167*12004Sjiang.liu@intel.com ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u "
16810394SMichael.Corcoran@Sun.COM "in acpidev_device_filter().", infop->awi_op_type);
16910394SMichael.Corcoran@Sun.COM res = ACPIDEV_FILTER_FAILED;
17010394SMichael.Corcoran@Sun.COM }
17110394SMichael.Corcoran@Sun.COM
17210394SMichael.Corcoran@Sun.COM return (res);
17310394SMichael.Corcoran@Sun.COM }
17410394SMichael.Corcoran@Sun.COM
17510394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_device_init(acpidev_walk_info_t * infop)17610394SMichael.Corcoran@Sun.COM acpidev_device_init(acpidev_walk_info_t *infop)
17710394SMichael.Corcoran@Sun.COM {
17810394SMichael.Corcoran@Sun.COM char unitaddr[32];
17910394SMichael.Corcoran@Sun.COM char *compatible[] = {
18010394SMichael.Corcoran@Sun.COM ACPIDEV_TYPE_DEVICE,
18110394SMichael.Corcoran@Sun.COM ACPIDEV_HID_VIRTNEX,
18210394SMichael.Corcoran@Sun.COM ACPIDEV_TYPE_VIRTNEX,
18310394SMichael.Corcoran@Sun.COM };
18410394SMichael.Corcoran@Sun.COM
18510394SMichael.Corcoran@Sun.COM if (ACPI_FAILURE(acpidev_set_compatible(infop,
18610394SMichael.Corcoran@Sun.COM ACPIDEV_ARRAY_PARAM(compatible)))) {
18710394SMichael.Corcoran@Sun.COM return (AE_ERROR);
18810394SMichael.Corcoran@Sun.COM }
18910394SMichael.Corcoran@Sun.COM (void) snprintf(unitaddr, sizeof (unitaddr), "%u",
19010394SMichael.Corcoran@Sun.COM atomic_inc_32_nv(&acpidev_device_unitaddr) - 1);
19110394SMichael.Corcoran@Sun.COM if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
19210394SMichael.Corcoran@Sun.COM return (AE_ERROR);
19310394SMichael.Corcoran@Sun.COM }
19410394SMichael.Corcoran@Sun.COM
19510394SMichael.Corcoran@Sun.COM return (AE_OK);
19610394SMichael.Corcoran@Sun.COM }
197