freebsd-dev/sys/dev/acpica/acpi_resource.c
msmith 49d56dc77b - Convert a lot of homebrew debugging output to use the ACPI CA debugging
infrastructure.  It's not perfect, but it's a lot better than what
   we've been using so far.  The following rules apply to this:
    o BSD component names should be capitalised
    o Layer names should be taken from the non-CA set for now.  We
      may elect to add some new BSD-specific layers later.

 - Make it possible to turn off selective debugging flags or layers
   by listing them in debug.acpi.layer or debug.acpi.level prefixed
   with !.

 - Fully implement support for avoiding nodes in the ACPI namespace.
   Nodes may be listed in the debug.acpi.avoid environment variable;
   these nodes and all their children will be ignored (although still
   scanned over) by ACPI functions which scan the namespace.  Multiple
   nodes can be specified, separated by whitespace.

 - Implement support for selectively disabling ACPI subsystem components
   via the debug.acpi.disable environment variable.  The following
   components can be disabled:
    o bus	creation/scanning of the ACPI 'bus'
    o children	attachment of children to the ACPI 'bus'
    o button	the acpi_button control-method button driver
    o ec	the acpi_ec embedded-controller driver
    o isa	acpi replacement of PnP BIOS for ISA device discovery
    o lid	the control-method lid switch driver
    o pci	pci root-bus discovery
    o processor CPU power/speed management
    o thermal	system temperature detection and control
    o timer	ACPI timecounter
   Multiple components may be disabled by specifying their name(s)
   separated by whitespace.

 - Add support for ioctl registration.  ACPI subsystem components may
   register ioctl handlers with the /dev/acpi generic ioctl handler,
   allowing us to avoid the need for a multitude of /dev/acpi* control
   devices, etc.
2000-12-08 09:16:20 +00:00

323 lines
10 KiB
C

/*-
* Copyright (c) 2000 Michael Smith
* Copyright (c) 2000 BSDi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include "acpi.h"
#include <dev/acpica/acpivar.h>
/*
* Hooks for the ACPI CA debugging infrastructure
*/
#define _COMPONENT BUS_MANAGER
MODULE_NAME("RESOURCE")
/*
* Fetch a device's resources and associate them with the device.
*
* Note that it might be nice to also locate ACPI-specific resource items, such
* as GPE bits.
*/
ACPI_STATUS
acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set)
{
ACPI_BUFFER buf;
RESOURCE *res;
char *curr, *last;
ACPI_STATUS status;
int i;
void *context;
FUNCTION_TRACE(__FUNCTION__);
/*
* Fetch the device resources
*/
if (((status = acpi_GetIntoBuffer(handle, AcpiGetPossibleResources, &buf)) != AE_OK) &&
((status = acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf)) != AE_OK)) {
device_printf(dev, "can't fetch ACPI resources - %s\n", acpi_strerror(status));
return_ACPI_STATUS(status);
}
DEBUG_PRINT(TRACE_RESOURCES, ("got %d bytes of resources\n", buf.Length));
set->set_init(dev, &context);
/*
* Iterate through the resources
*/
curr = buf.Pointer;
last = (char *)buf.Pointer + buf.Length;
while (curr < last) {
res = (RESOURCE *)curr;
curr += res->Length;
/*
* Handle the individual resource types
*/
switch(res->Id) {
case EndTag:
DEBUG_PRINT(TRACE_RESOURCES, ("EndTag\n"));
curr = last;
break;
case FixedIo:
DEBUG_PRINT(TRACE_RESOURCES, ("FixedIo 0x%x/%d\n", res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength));
set->set_ioport(dev, context, res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength);
break;
case Io:
if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
DEBUG_PRINT(TRACE_RESOURCES, ("Io 0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength));
set->set_ioport(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength);
} else {
DEBUG_PRINT(TRACE_RESOURCES, ("Io 0x%x-0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
res->Data.Io.RangeLength));
set->set_iorange(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
res->Data.Io.RangeLength, res->Data.Io.Alignment);
}
break;
case FixedMemory32:
DEBUG_PRINT(TRACE_RESOURCES, ("FixedMemory32 0x%x/%d\n", res->Data.FixedMemory32.RangeBaseAddress,
res->Data.FixedMemory32.RangeLength));
set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress,
res->Data.FixedMemory32.RangeLength);
break;
case Memory32:
if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) {
DEBUG_PRINT(TRACE_RESOURCES, ("Memory32 0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
res->Data.Memory32.RangeLength));
set->set_memory(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.RangeLength);
} else {
DEBUG_PRINT(TRACE_RESOURCES, ("Memory32 0x%x-0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
res->Data.Memory32.MaxBaseAddress, res->Data.Memory32.RangeLength));
set->set_memoryrange(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.MaxBaseAddress,
res->Data.Memory32.RangeLength, res->Data.Memory32.Alignment);
}
break;
case Memory24:
if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) {
DEBUG_PRINT(TRACE_RESOURCES, ("Memory24 0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
res->Data.Memory24.RangeLength));
set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.RangeLength);
} else {
DEBUG_PRINT(TRACE_RESOURCES, ("Memory24 0x%x-0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
res->Data.Memory24.MaxBaseAddress, res->Data.Memory24.RangeLength));
set->set_memoryrange(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.MaxBaseAddress,
res->Data.Memory24.RangeLength, res->Data.Memory24.Alignment);
}
break;
case Irq:
for (i = 0; i < res->Data.Irq.NumberOfInterrupts; i++) {
DEBUG_PRINT(TRACE_RESOURCES, ("Irq %d\n", res->Data.Irq.Interrupts[i]));
set->set_irq(dev, context, res->Data.Irq.Interrupts[i]);
}
break;
case Dma:
for (i = 0; i < res->Data.Dma.NumberOfChannels; i++) {
DEBUG_PRINT(TRACE_RESOURCES, ("Drq %d\n", res->Data.Dma.Channels[i]));
set->set_drq(dev, context, res->Data.Dma.Channels[i]);
}
break;
case StartDependentFunctions:
DEBUG_PRINT(TRACE_RESOURCES, ("start dependant functions"));
set->set_start_dependant(dev, context, res->Data.StartDependentFunctions.CompatibilityPriority);
break;
case EndDependentFunctions:
DEBUG_PRINT(TRACE_RESOURCES, ("end dependant functions"));
set->set_end_dependant(dev, context);
break;
case Address32:
DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented Address32 resource\n"));
break;
case Address16:
DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented Address16 resource\n"));
break;
case ExtendedIrq:
DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented ExtendedIrq resource\n"));
break;
case VendorSpecific:
DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented VendorSpecific resource\n"));
break;
default:
break;
}
}
AcpiOsFree(buf.Pointer);
set->set_done(dev, context);
return_ACPI_STATUS(AE_OK);
}
static void acpi_res_set_init(device_t dev, void **context);
static void acpi_res_set_done(device_t dev, void *context);
static void acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
static void acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
u_int32_t length, u_int32_t align);
static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
static void acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
u_int32_t length, u_int32_t align);
static void acpi_res_set_irq(device_t dev, void *context, u_int32_t irq);
static void acpi_res_set_drq(device_t dev, void *context, u_int32_t drq);
static void acpi_res_set_start_dependant(device_t dev, void *context, int preference);
static void acpi_res_set_end_dependant(device_t dev, void *context);
struct acpi_parse_resource_set acpi_res_parse_set = {
acpi_res_set_init,
acpi_res_set_done,
acpi_res_set_ioport,
acpi_res_set_iorange,
acpi_res_set_memory,
acpi_res_set_memoryrange,
acpi_res_set_irq,
acpi_res_set_drq,
acpi_res_set_start_dependant,
acpi_res_set_end_dependant
};
struct acpi_res_context {
int ar_nio;
int ar_nmem;
int ar_nirq;
};
static void
acpi_res_set_init(device_t dev, void **context)
{
struct acpi_res_context *cp;
if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
bzero(cp, sizeof(*cp));
*context = cp;
}
}
static void
acpi_res_set_done(device_t dev, void *context)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
AcpiOsFree(cp);
}
static void
acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
}
static void
acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
device_printf(dev, "I/O range not supported\n");
}
static void
acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
}
static void
acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
device_printf(dev, "memory range not supported\n");
}
static void
acpi_res_set_irq(device_t dev, void *context, u_int32_t irq)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq, 1);
}
static void
acpi_res_set_drq(device_t dev, void *context, u_int32_t drq)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
device_printf(dev, "DRQ not supported\n");
}
static void
acpi_res_set_start_dependant(device_t dev, void *context, int preference)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
device_printf(dev, "dependant functions not supported");
}
static void
acpi_res_set_end_dependant(device_t dev, void *context)
{
struct acpi_res_context *cp = (struct acpi_res_context *)context;
if (cp == NULL)
return;
}