acpi_enum.c revision 12f7d0bd7debcebd2530b87d591f183ba5136537
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012 Gary Mills
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* ACPI enumerator
*/
static char keyboard_alias[] = "keyboard";
static char mouse_alias[] = "mouse";
#define ACPI_ENUM_DEBUG "acpi_enum_debug"
#define PARSE_RESOURCES_DEBUG 0x0001
#define MASTER_LOOKUP_DEBUG 0x0002
#define DEVICES_NOT_ENUMED 0x0004
#define PARSE_RES_IRQ 0x0008
#define PARSE_RES_DMA 0x0010
#define PARSE_RES_MEMORY 0x0020
#define PARSE_RES_IO 0x0040
#define PARSE_RES_ADDRESS 0x0080
#define ISA_DEVICE_ENUM 0x1000
#define PROCESS_CIDS 0x2000
static unsigned long acpi_enum_debug = 0x00;
static char USED_RESOURCES[] = "used-resources";
static unsigned short used_interrupts = 0;
static unsigned short used_dmas = 0;
typedef struct used_io_mem {
unsigned int start_addr;
unsigned int length;
struct used_io_mem *next;
static int used_io_count = 0;
static int used_mem_count = 0;
#define MAX_PARSED_ACPI_RESOURCES 255
#define ACPI_ISA_LIMIT 16
#define ACPI_ELEMENT_PACKAGE_LIMIT 32
#define EISA_ID_SIZE 7
/*
*/
static void
{
(*used_count)++;
return;
}
/* find a place to insert */
}
/* head */
return;
} else {
}
}
static void
{
int i;
for (i = 0; i < io_count; i++) {
KM_SLEEP);
&used_io_head);
} else {
}
}
}
static void
{
int i;
interrupt[(*interrupt_count)++] =
if (acpi_enum_debug & PARSE_RES_IRQ) {
"IRQ num %u, intr # = %u",
}
}
}
static void
{
int i;
if (acpi_enum_debug & PARSE_RES_DMA) {
"DMA num %u, channel # = %u",
}
}
}
static void
int *io_count)
{
if (acpi_io.AddressLength == 0)
return;
if (acpi_enum_debug & PARSE_RES_IO) {
"IO min 0x%X, max 0x%X, length: 0x%X",
}
(*io_count)++;
}
static void
int *io_count)
{
if (fixed_io.AddressLength == 0)
return;
if (acpi_enum_debug & PARSE_RES_IO) {
"Fixed IO 0x%X, length: 0x%X",
}
(*io_count)++;
}
static void
int *io_count)
{
if (fixed_mem32.AddressLength == 0)
return;
if (acpi_enum_debug & PARSE_RES_MEMORY) {
"Fixed Mem 32 %ul, length: %ul",
}
(*io_count)++;
}
static void
int *io_count)
{
if (mem32.AddressLength == 0)
return;
(*io_count)++;
if (acpi_enum_debug & PARSE_RES_MEMORY) {
"Mem 32 0x%X, length: 0x%X",
}
return;
}
if (acpi_enum_debug & PARSE_RES_MEMORY) {
"MEM32 Min Max not equal!");
"Mem 32 Minimum 0x%X, Maximum: 0x%X",
}
}
static void
int *io_count)
{
if (addr16.AddressLength == 0)
return;
if (acpi_enum_debug & PARSE_RES_ADDRESS) {
"ADDRESS 16 MEMORY RANGE");
} else
"ADDRESS 16 IO RANGE");
} else {
"ADDRESS 16 OTHER");
}
"%s "\
"MinAddressFixed 0x%X, "\
"MaxAddressFixed 0x%X, "\
"Minimum 0x%X, "\
"Maximum 0x%X, "\
"length: 0x%X\n",
"CONSUMER" : "PRODUCER",
}
return;
}
if (addr16.AddressLength > 0) {
/* memory */
} else {
/* io */
}
(*io_count)++;
}
}
static void
int *io_count)
{
if (addr32.AddressLength == 0)
return;
if (acpi_enum_debug & PARSE_RES_ADDRESS) {
"ADDRESS 32 MEMORY RANGE");
} else
"ADDRESS 32 IO RANGE");
} else {
"ADDRESS 32 OTHER");
}
"%s "\
"MinAddressFixed 0x%X, "\
"MaxAddressFixed 0x%X, "\
"Minimum 0x%X, "\
"Maximum 0x%X, "\
"length: 0x%X\n",
"CONSUMER" : "PRODUCER",
}
return;
}
if (addr32.AddressLength > 0) {
/* memory */
} else {
/* io */
}
(*io_count)++;
}
}
static void
int *io_count)
{
if (addr64.AddressLength == 0)
return;
if (acpi_enum_debug & PARSE_RES_ADDRESS) {
"ADDRESS 64 MEMORY RANGE");
} else
"ADDRESS 64 IO RANGE");
} else {
"ADDRESS 64 OTHER");
}
#ifdef _LP64
"%s "\
"MinAddressFixed 0x%X, "\
"MaxAddressFixed 0x%X, "\
"Minimum 0x%lX, "\
"Maximum 0x%lX, "\
"length: 0x%lX\n",
"CONSUMER" : "PRODUCER",
#else
"%s "\
"MinAddressFixed 0x%X, "\
"MaxAddressFixed 0x%X, "\
"Minimum 0x%llX, "\
"Maximum 0x%llX, "\
"length: 0x%llX\n",
"CONSUMER" : "PRODUCER",
#endif
}
return;
}
if (addr64.AddressLength > 0) {
/* memory */
} else {
/* io */
}
(*io_count)++;
}
}
static ACPI_STATUS
{
char *current_ptr, *last_ptr;
int i;
switch (status) {
case AE_OK:
break;
case AE_NOT_FOUND:
/*
* Workaround for faulty DSDT tables that omit the _CRS
* method for the UAR3 device but have a valid _PRS method
* for that device.
*/
return (status);
}
break;
default:
"!AcpiGetCurrentResources failed for %s, exception: %s",
return (status);
break;
}
while (current_ptr < last_ptr) {
if (io_count >= MAX_PARSED_ACPI_RESOURCES) {
break;
}
switch (resource_ptr->Type) {
break;
case ACPI_RESOURCE_TYPE_IO:
break;
break;
&io_count);
break;
break;
break;
break;
break;
case ACPI_RESOURCE_TYPE_IRQ:
break;
case ACPI_RESOURCE_TYPE_DMA:
break;
"!ACPI source type"
" ACPI_RESOURCE_TYPE_START_DEPENDENT"
" not supported");
break;
"!ACPI source type"
" ACPI_RESOURCE_TYPE_END_DEPENDENT"
" not supported");
break;
"!ACPI source type"
" ACPI_RESOURCE_TYPE_VENDOR"
" not supported");
break;
"!ACPI source type"
" ACPI_RESOURCE_TYPE_MEMORY24"
" not supported");
break;
"!ACPI source type"
" ACPI_RESOURCE_TYPE_EXT_IRQ"
" not supported");
break;
default:
/* Some types are not yet implemented (See CA 6.4) */
"!ACPI resource type (0X%X) not yet supported",
resource_ptr->Type);
break;
}
}
if (io_count) {
/*
* on LX50, you get interrupts of mouse and keyboard
* from separate PNP id...
*/
if (io_count == 2) {
interrupt[0] = 0x1;
interrupt_count = 2;
1 << interrupt[0];
}
}
}
}
}
}
return (status);
}
/* keyboard mouse is under i8042, everything else under isa */
static dev_info_t *
{
struct regspec i8042_regs[] = {
{1, 0x60, 0x1},
{1, 0x64, 0x1}
};
return (isa_dip);
if (i8042_dip)
return (i8042_dip);
&i8042_dip);
"unit-address", "1,60");
(void) ndi_devi_bind_driver(i8042_dip, 0);
return (i8042_dip);
}
/*
* put content of properties (if any) to dev info tree at branch xdip
* return non-zero if a "compatible" property was processed, zero otherwise
*
*/
static int
{
int rv = 0;
while (properties != NULL) {
rv = 1;
}
return (rv);
}
void
{
static const char hextab[] = "0123456789ABCDEF";
/*
* Expand an EISA device name:
*
* This routine converts a 32-bit EISA device "id" to a
* 7-byte ASCII device name, which is stored at "np".
*/
*np = 0;
}
/*
* process_cids() -- process multiple CIDs in a package
*/
static void
{
device_id_t *d;
int i;
return; /* empty package */
/*
* Work the package 'backwards' so the resulting list is
* in original order of preference.
*/
/* get the actual acpi_object */
case ACPI_TYPE_INTEGER:
d = mf_alloc_device_id();
*dd = d;
break;
case ACPI_TYPE_STRING:
d = mf_alloc_device_id();
*dd = d;
break;
default:
if (acpi_enum_debug & PROCESS_CIDS) {
}
break;
}
}
}
/*
* Convert "raw" PNP and ACPI IDs to IEEE 1275-compliant form.
* Some liberty is taken here, treating "ACPI" as a special form
* of PNP vendor ID. strsize specifies size of buffer.
*/
static void
{
char vendor[5];
/* Assume ACPI ID: ACPIxxxx */
} else {
/* Assume PNP ID: aaaxxxx */
}
}
/*
* Given a list of device ID elements in most-to-least-specific
* order, create a "compatible" property.
*/
static void
{
char **strs;
int list_len, i;
device_id_t *d;
/* count list length */
list_len = 0;
d = ids;
while (d != NULL) {
list_len++;
d = d->next;
}
/* create string array */
i = 0;
d = ids;
while (d != NULL) {
/* strlen("pnpXXXX,xxxx") + 1 = 13 */
d = d->next;
}
/* update property */
/* free memory */
for (i = 0; i < list_len; i++)
}
/*
* isa_acpi_callback()
*/
static ACPI_STATUS
void **b)
{
const master_rec_t *m;
int compatible_present = 0;
/*
* get full ACPI pathname for object
*/
goto done;
}
/*
* Get device info object
*/
" info for %s", path);
goto done;
}
/*
* If device isn't present, we don't enumerate
* NEEDSWORK: what about docking bays and the like?
*/
/*
* CA 6.3.6 _STA method
* Bit 0 -- device is present
* Bit 1 -- device is enabled
* Bit 2 -- device is shown in UI
*/
if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
"Bad status 0x%x for %s",
}
goto done;
}
} else {
goto done;
}
/*
* Keep track of _HID value
*/
/* No _HID, we skip this node */
if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
"No _HID for %s", path);
}
goto done;
}
/*
* Attempt to get _CID value
*/
case ACPI_TYPE_INTEGER:
d = mf_alloc_device_id();
d->next = device_ids;
device_ids = d;
break;
case ACPI_TYPE_STRING:
d = mf_alloc_device_id();
d->next = device_ids;
device_ids = d;
break;
case ACPI_TYPE_PACKAGE:
break;
default:
break;
}
}
/*
* Add _HID last so it's at the head of the list
*/
d = mf_alloc_device_id();
d->next = device_ids;
device_ids = d;
/*
* master_file_lookup() expects _HID first in device_ids
*/
/* PNP description found in master table */
dip = ddi_root_node();
} else {
}
"model", m->description);
} else {
/* for ISA devices not known to the master file */
/* a keyboard device includes PNP03xx */
"compatible", "pnpPNP,303");
"model", "PNP03xx keyboard");
} else {
/* a mouse device include PNP0Fxx */
(void) ndi_prop_update_string(DDI_DEV_T_NONE,
(void) ndi_prop_update_string(DDI_DEV_T_NONE,
} else {
goto done;
}
}
}
path);
/* Special processing for mouse and keyboard devices per IEEE 1275 */
/* if master entry doesn't contain "compatible" then we add default */
"device-type", keyboard_alias);
if (!compatible_present)
"compatible", "pnpPNP,303");
"device-type", mouse_alias);
if (!compatible_present)
"compatible", "pnpPNP,f03");
}
/*
* Create default "compatible" property if required
*/
DDI_PROP_DONTPASS, "compatible"))
(void) ndi_devi_bind_driver(xdip, 0);
done:
/* discard _HID/_CID list */
d = device_ids;
while (d != NULL) {
d = next;
}
return (AE_OK);
}
static void
used_res_interrupts(void)
{
int intr[ACPI_ISA_LIMIT];
int count = 0;
int i;
for (i = 0; i < ACPI_ISA_LIMIT; i++) {
if ((used_interrupts >> i) & 1) {
}
}
}
static void
used_res_dmas(void)
{
int dma[ACPI_ISA_LIMIT];
int count = 0;
int i;
for (i = 0; i < ACPI_ISA_LIMIT; i++) {
if ((used_dmas >> i) & 1) {
}
}
}
static void
{
int *io;
int i;
*count *= 2;
for (i = 0; i < *count; i += 2) {
}
}
}
/*
* acpi_isa_device_enum() -- call from isa nexus driver
* returns 1 if deviced enumeration is successful
* 0 if deviced enumeration fails
*/
int
{
char *acpi_prop;
long data;
acpi_enum_debug = (unsigned long)data;
}
}
if (acpi_enum_debug & ISA_DEVICE_ENUM) {
}
if (acpica_init() != AE_OK) {
/* Note, pickup by i8042 nexus */
return (0);
}
}
/*
* Do the actual enumeration. Avoid AcpiGetDevices because it
* has an unnecessary internal callback that duplicates
* determining if the device is present.
*/
(void) ndi_devi_bind_driver(usedrdip, 0);
return (1);
}