Initial FreeBSD OSPM (operating system power management) modules for

ACPICA.  Most of these are still works in progress.  Support exists for:

 - Fixed feature and control method power, lid and sleep buttons.
 - Detection of ISA PnP devices using ACPI namespace.
 - Detection of PCI root busses using ACPI namespace.
 - CPU throttling and sleep states (incomplete)
 - Thermal monitoring and cooling control (incomplete)
 - Interface to platform embedded controllers (mostly complete)
 - ACPI timer (incomplete)
 - Simple userland control of sleep states.
 - Shutdown and poweroff.
This commit is contained in:
Mike Smith 2000-10-28 06:59:48 +00:00
parent fd660059d9
commit 15e32d5d03
15 changed files with 4893 additions and 0 deletions

1124
sys/dev/acpica/acpi.c Normal file

File diff suppressed because it is too large Load Diff

159
sys/dev/acpica/acpi_apic.c Normal file
View File

@ -0,0 +1,159 @@
/*-
* 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$
*/
/*
* XXX This is all pretty dubious, since we really want the APIC and co.
* up and running long before attaching interrupts, etc.
*/
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include "acpi.h"
#include <dev/acpica/acpivar.h>
#define APIC_MAGIC 0x43495041 /* "APIC" */
struct acpi_apic_softc {
device_t apic_dev;
IO_APIC *apic_ioapic;
};
static void acpi_apic_identify(driver_t *driver, device_t bus);
static int acpi_apic_probe(device_t dev);
static int acpi_apic_attach(device_t dev);
static device_method_t acpi_apic_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, acpi_apic_identify),
DEVMETHOD(device_probe, acpi_apic_probe),
DEVMETHOD(device_attach, acpi_apic_attach),
{0, 0}
};
static driver_t acpi_apic_driver = {
"acpi_apic",
acpi_apic_methods,
sizeof(struct acpi_apic_softc),
};
devclass_t acpi_apic_devclass;
DRIVER_MODULE(acpi_apic, acpi, acpi_apic_driver, acpi_apic_devclass, 0, 0);
static void
acpi_apic_identify(driver_t *driver, device_t bus)
{
ACPI_BUFFER buf;
ACPI_STATUS status;
APIC_HEADER *hdr;
APIC_TABLE *tbl;
device_t child;
int len;
void *private;
/*
* Perform the tedious double-get to fetch the actual table.
*/
buf.Length = 0;
buf.Pointer = NULL;
if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_BUFFER_OVERFLOW) {
if (status != AE_NOT_EXIST)
device_printf(bus, "error sizing APIC table - %s\n", acpi_strerror(status));
return;
}
if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL)
return;
if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_OK) {
device_printf(bus, "error fetching APIC table - %s\n", acpi_strerror(status));
return;
}
/*
* Scan the tables, create child devices for each I/O APIC found
*/
tbl = (APIC_TABLE *)buf.Pointer;
len = tbl->header.Length - sizeof(APIC_TABLE);
hdr = (APIC_HEADER *)((char *)buf.Pointer + sizeof(APIC_TABLE));
while(len > 0) {
if (hdr->Length > len) {
device_printf(bus, "APIC header corrupt (claims %d bytes where only %d left in structure)\n",
hdr->Length, len);
break;
}
switch (hdr->Type) {
case APIC_IO:
if ((child = BUS_ADD_CHILD(bus, 0, "acpi_apic", -1)) == NULL) {
device_printf(bus, "could not create I/O APIC device");
break;
}
if ((private = AcpiOsAllocate(hdr->Length)) == NULL) {
device_printf(bus, "could not allocate memory for APIC child");
break;
}
bcopy(hdr, private, hdr->Length);
acpi_set_magic(child, APIC_MAGIC);
acpi_set_private(child, private);
device_set_desc(child, "I/O APIC");
break;
}
len -= hdr->Length;
hdr = (APIC_HEADER *)((char *)hdr + hdr->Length);
}
AcpiOsFree(buf.Pointer);
}
static int
acpi_apic_probe(device_t dev)
{
if (acpi_get_magic(dev) == APIC_MAGIC)
return(0);
return(ENXIO);
}
static int
acpi_apic_attach(device_t dev)
{
struct acpi_apic_softc *sc;
sc = device_get_softc(dev);
sc->apic_dev = dev;
/*
* Fetch our parameters.
*/
sc->apic_ioapic = acpi_get_private(dev);
device_printf(dev, "I/O APIC ID %d at 0x%08x vectors 0%x\n",
sc->apic_ioapic->IoApicId, sc->apic_ioapic->IoApicAddress, sc->apic_ioapic->Vector);
return(0);
}

View File

@ -0,0 +1,182 @@
/*-
* Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org>
* Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
* 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 "acpi.h"
#include <dev/acpica/acpivar.h>
struct acpi_button_softc {
device_t button_dev;
ACPI_HANDLE button_handle;
#define ACPI_POWER_BUTTON 0
#define ACPI_SLEEP_BUTTON 1
boolean_t button_type; /* Power or Sleep Button */
};
static int acpi_button_probe(device_t dev);
static int acpi_button_attach(device_t dev);
static void acpi_button_notify_handler(ACPI_HANDLE h,UINT32 notify, void *context);
static void acpi_button_notify_pressed_for_sleep(void *arg);
static void acpi_button_notify_pressed_for_wakeup(void *arg);
static device_method_t acpi_button_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, acpi_button_probe),
DEVMETHOD(device_attach, acpi_button_attach),
{0, 0}
};
static driver_t acpi_button_driver = {
"acpi_button",
acpi_button_methods,
sizeof(struct acpi_button_softc),
};
devclass_t acpi_button_devclass;
DRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 0, 0);
static int
acpi_button_probe(device_t dev)
{
struct acpi_button_softc *sc;
sc = device_get_softc(dev);
if (acpi_get_type(dev) == ACPI_TYPE_DEVICE) {
if (acpi_MatchHid(dev, "PNP0C0C")) {
device_set_desc(dev, "Control Method Power Button Device");
sc->button_type = ACPI_POWER_BUTTON;
return(0);
}
if (acpi_MatchHid(dev, "PNP0C0E")) {
device_set_desc(dev, "Control Method Sleep Button Device");
sc->button_type = ACPI_SLEEP_BUTTON;
return(0);
}
return(ENXIO);
}
return(ENXIO);
}
static int
acpi_button_attach(device_t dev)
{
struct acpi_button_softc *sc;
ACPI_STATUS status;
sc = device_get_softc(dev);
sc->button_dev = dev;
sc->button_handle = acpi_get_handle(dev);
if ((status = AcpiInstallNotifyHandler(sc->button_handle, ACPI_DEVICE_NOTIFY,
acpi_button_notify_handler, sc)) != AE_OK) {
device_printf(sc->button_dev, "couldn't install Notify handler - %s\n", acpi_strerror(status));
return(ENXIO);
}
return(0);
}
static void
acpi_button_notify_pressed_for_sleep(void *arg)
{
struct acpi_button_softc *sc;
struct acpi_softc *acpi_sc;
sc = (struct acpi_button_softc *)arg;
acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
if (acpi_sc == NULL) {
return;
}
switch (sc->button_type) {
case ACPI_POWER_BUTTON:
acpi_eventhandler_power_button_for_sleep((void *)acpi_sc);
break;
case ACPI_SLEEP_BUTTON:
acpi_eventhandler_sleep_button_for_sleep((void *)acpi_sc);
break;
default:
return; /* unknown button type */
}
}
static void
acpi_button_notify_pressed_for_wakeup(void *arg)
{
struct acpi_button_softc *sc;
struct acpi_softc *acpi_sc;
sc = (struct acpi_button_softc *)arg;
acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
if (acpi_sc == NULL) {
return;
}
switch (sc->button_type) {
case ACPI_POWER_BUTTON:
acpi_eventhandler_power_button_for_wakeup((void *)acpi_sc);
break;
case ACPI_SLEEP_BUTTON:
acpi_eventhandler_sleep_button_for_wakeup((void *)acpi_sc);
break;
default:
return; /* unknown button type */
}
}
/* XXX maybe not here */
#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP 0x80
#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP 0x02
static void
acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
{
struct acpi_button_softc *sc = (struct acpi_button_softc *)context;
switch (notify) {
case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP:
AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_sleep, sc);
device_printf(sc->button_dev, "pressed for sleep, button type: %d\n", sc->button_type);
break;
case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP:
AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_wakeup, sc);
device_printf(sc->button_dev, "pressed for wakeup, button type: %d\n", sc->button_type);
break;
default:
return; /* unknown notification value */
}
}

710
sys/dev/acpica/acpi_ec.c Normal file
View File

@ -0,0 +1,710 @@
/*-
* 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$
*/
/******************************************************************************
*
* 1. Copyright Notice
*
* Some or all of this work - Copyright (c) 1999, Intel Corp. All rights
* reserved.
*
* 2. License
*
* 2.1. This is your license from Intel Corp. under its intellectual property
* rights. You may have additional license terms from the party that provided
* you this software, covering your right to use that party's intellectual
* property rights.
*
* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
* copy of the source code appearing in this file ("Covered Code") an
* irrevocable, perpetual, worldwide license under Intel's copyrights in the
* base code distributed originally by Intel ("Original Intel Code") to copy,
* make derivatives, distribute, use and display any portion of the Covered
* Code in any form, with the right to sublicense such rights; and
*
* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
* license (with the right to sublicense), under only those claims of Intel
* patents that are infringed by the Original Intel Code, to make, use, sell,
* offer to sell, and import the Covered Code and derivative works thereof
* solely to the minimum extent necessary to exercise the above copyright
* license, and in no event shall the patent license extend to any additions
* to or modifications of the Original Intel Code. No other license or right
* is granted directly or by implication, estoppel or otherwise;
*
* The above copyright and patent license is granted only if the following
* conditions are met:
*
* 3. Conditions
*
* 3.1. Redistribution of Source with Rights to Further Distribute Source.
* Redistribution of source code of any substantial portion of the Covered
* Code or modification with rights to further distribute source must include
* the above Copyright Notice, the above License, this list of Conditions,
* and the following Disclaimer and Export Compliance provision. In addition,
* Licensee must cause all Covered Code to which Licensee contributes to
* contain a file documenting the changes Licensee made to create that Covered
* Code and the date of any change. Licensee must include in that file the
* documentation of any changes made by any predecessor Licensee. Licensee
* must include a prominent statement that the modification is derived,
* directly or indirectly, from Original Intel Code.
*
* 3.2. Redistribution of Source with no Rights to Further Distribute Source.
* Redistribution of source code of any substantial portion of the Covered
* Code or modification without rights to further distribute source must
* include the following Disclaimer and Export Compliance provision in the
* documentation and/or other materials provided with distribution. In
* addition, Licensee may not authorize further sublicense of source of any
* portion of the Covered Code, and must include terms to the effect that the
* license from Licensee to its licensee is limited to the intellectual
* property embodied in the software Licensee provides to its licensee, and
* not to intellectual property embodied in modifications its licensee may
* make.
*
* 3.3. Redistribution of Executable. Redistribution in executable form of any
* substantial portion of the Covered Code or modification must reproduce the
* above Copyright Notice, and the following Disclaimer and Export Compliance
* provision in the documentation and/or other materials provided with the
* distribution.
*
* 3.4. Intel retains all right, title, and interest in and to the Original
* Intel Code.
*
* 3.5. Neither the name Intel nor any other trademark owned or controlled by
* Intel shall be used in advertising or otherwise to promote the sale, use or
* other dealings in products derived from or relating to the Covered Code
* without prior written authorization from Intel.
*
* 4. Disclaimer and Export Compliance
*
* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
* LIMITED REMEDY.
*
* 4.3. Licensee shall not export, either directly or indirectly, any of this
* software or system incorporating such software without first obtaining any
* required license or other approval from the U. S. Department of Commerce or
* any other agency or department of the United States Government. In the
* event Licensee exports any such software from the United States or
* re-exports any such software from a foreign destination, Licensee shall
* ensure that the distribution and export/re-export of the software is in
* compliance with all laws, regulations, orders, or other restrictions of the
* U.S. Export Administration Regulations. Licensee agrees that neither it nor
* any of its subsidiaries will export/re-export any technical data, process,
* software, or service, directly or indirectly, to any country for which the
* United States government or any agency thereof requires an export license,
* other governmental approval, or letter of assurance, without first obtaining
* such license, approval or letter.
*
*****************************************************************************/
#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 <sys/rman.h>
#include "acpi.h"
#include <dev/acpica/acpivar.h>
#include <dev/acpica/acpi_ecreg.h>
struct acpi_ec_softc {
device_t ec_dev;
ACPI_HANDLE ec_handle;
ACPI_HANDLE ec_semaphore;
UINT32 ec_gpebit;
int ec_data_rid;
struct resource *ec_data_res;
bus_space_tag_t ec_data_tag;
bus_space_handle_t ec_data_handle;
int ec_csr_rid;
struct resource *ec_csr_res;
bus_space_tag_t ec_csr_tag;
bus_space_handle_t ec_csr_handle;
int ec_locked;
};
#define EC_LOCK_TIMEOUT 1000 /* 1ms */
static __inline ACPI_STATUS
EcLock(struct acpi_ec_softc *sc)
{
ACPI_STATUS status;
status = AcpiOsWaitSemaphore((sc)->ec_semaphore, 1, EC_LOCK_TIMEOUT);
(sc)->ec_locked = 1;
return(status);
}
static __inline void
EcUnlock(struct acpi_ec_softc *sc)
{
(sc)->ec_locked = 0;
AcpiOsSignalSemaphore((sc)->ec_semaphore, 1);
}
static __inline int
EcIsLocked(struct acpi_ec_softc *sc)
{
return((sc)->ec_locked != 0);
}
typedef struct
{
EC_COMMAND Command;
UINT8 Address;
UINT8 Data;
} EC_REQUEST;
static struct acpi_ec_softc acpi_ec_default; /* for the default EC handler */
static void EcGpeHandler(void *Context);
static ACPI_STATUS EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
void *Context, void **return_Context);
static ACPI_STATUS EcSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value,
void *Context, void *RegionContext);
static ACPI_STATUS EcDefaultSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value,
void *Context, void *RegionContext);
static ACPI_STATUS EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
static ACPI_STATUS EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
static ACPI_STATUS EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
static ACPI_STATUS EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
static ACPI_STATUS EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
static void acpi_ec_identify(driver_t driver, device_t bus);
static int acpi_ec_probe(device_t dev);
static int acpi_ec_attach(device_t dev);
static device_method_t acpi_ec_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, acpi_ec_identify),
DEVMETHOD(device_probe, acpi_ec_probe),
DEVMETHOD(device_attach, acpi_ec_attach),
{0, 0}
};
static driver_t acpi_ec_driver = {
"acpi_ec",
acpi_ec_methods,
sizeof(struct acpi_ec_softc),
};
devclass_t acpi_ec_devclass;
DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
/*
* Look for an ECDT table and if we find one, set up a default EC
* space handler to catch possible attempts to access EC space before
* we have a real driver instance in place.
* We're not really an identify routine, but because we get called
* before most other things, this works out OK.
*/
static void
acpi_ec_identify(driver_t driver, device_t bus)
{
ACPI_STATUS Status;
/* XXX implement - need an ACPI 2.0 system to test this */
/*
* XXX install a do-nothing handler at the top of the namespace to catch
* bogus accesses being made due to apparent interpreter bugs.
*/
acpi_ec_default.ec_dev = bus;
if ((Status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, ADDRESS_SPACE_EC,
&EcDefaultSpaceHandler, &EcSpaceSetup,
&acpi_ec_default)) != AE_OK) {
device_printf(acpi_ec_default.ec_dev, "can't install default EC address space handler - %s\n",
acpi_strerror(Status));
}
}
/*
* We could setup resources in the probe routine in order to have them printed
* when the device is attached.
*/
static int
acpi_ec_probe(device_t dev)
{
if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
acpi_MatchHid(dev, "PNP0C09")) {
/*
* Set device description
*/
device_set_desc(dev, "embedded controller");
return(0);
}
return(ENXIO);
}
static int
acpi_ec_attach(device_t dev)
{
struct acpi_ec_softc *sc;
ACPI_BUFFER *bufp;
UINT32 *param;
ACPI_STATUS Status;
struct acpi_object_list *args;
/*
* Fetch/initialise softc
*/
sc = device_get_softc(dev);
sc->ec_dev = dev;
sc->ec_handle = acpi_get_handle(dev);
/*
* Evaluate resources
*/
acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
/*
* Attach bus resources
*/
sc->ec_data_rid = 0;
if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
0, ~0, 1, RF_ACTIVE)) == NULL) {
device_printf(dev, "can't allocate data port\n");
return(ENXIO);
}
sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
sc->ec_csr_rid = 1;
if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
0, ~0, 1, RF_ACTIVE)) == NULL) {
device_printf(dev, "can't allocate command/status port\n");
return(ENXIO);
}
sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
/*
* Create serialisation semaphore
*/
if ((Status = AcpiOsCreateSemaphore(1, 1, &sc->ec_semaphore)) != AE_OK) {
device_printf(dev, "can't create semaphore - %s\n", acpi_strerror(Status));
return(ENXIO);
}
/*
* Install GPE handler
*
* Evaluate the _GPE method to find the GPE bit used by the EC to signal
* status (SCI).
*/
if ((bufp = acpi_AllocBuffer(16)) == NULL)
return(ENOMEM);
if ((Status = AcpiEvaluateObject(sc->ec_handle, "_GPE", NULL, bufp)) != AE_OK) {
device_printf(dev, "can't evaluate _GPE method - %s\n", acpi_strerror(Status));
return(ENXIO);
}
param = (UINT32 *)bufp->Pointer;
if (param[0] != ACPI_TYPE_NUMBER) {
device_printf(dev, "_GPE method returned bad result\n");
return(ENXIO);
}
sc->ec_gpebit = param[1];
AcpiOsFree(bufp);
/*
* Install a handler for this EC's GPE bit. Note that EC SCIs are
* treated as both edge- and level-triggered interrupts; in other words
* we clear the status bit immediately after getting an EC-SCI, then
* again after we're done processing the event. This guarantees that
* events we cause while performing a transaction (e.g. IBE/OBF) get
* cleared before re-enabling the GPE.
*/
if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
EcGpeHandler, sc)) != AE_OK) {
device_printf(dev, "can't install GPE handler - %s\n", acpi_strerror(Status));
return(ENXIO);
}
/*
* Install address space handler
*/
if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ADDRESS_SPACE_EC,
&EcSpaceHandler, &EcSpaceSetup, sc)) != AE_OK) {
device_printf(dev, "can't install address space handler - %s\n", acpi_strerror(Status));
return(ENXIO);
}
/*
* Evaluate _REG to indicate that the region is now available.
*/
if ((args = acpi_AllocObjectList(2)) == NULL)
return(ENOMEM);
args->object[0].Type = ACPI_TYPE_NUMBER;
args->object[0].Number.Value = ADDRESS_SPACE_EC;
args->object[1].Type = ACPI_TYPE_NUMBER;
args->object[1].Number.Value = 1;
Status = AcpiEvaluateObject(sc->ec_handle, "_REG", (ACPI_OBJECT_LIST *)args, NULL);
AcpiOsFree(args);
/*
* If evaluation failed for some reason other than that the method didn't
* exist, that's bad and we should not attach.
*/
if ((Status != AE_OK) && (Status != AE_NOT_FOUND)) {
device_printf(dev, "can't evaluate _REG method - %s\n", acpi_strerror(Status));
return(ENXIO);
}
return(0);
}
static void
EcGpeHandler(void *Context)
{
struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context;
UINT8 Data;
ACPI_STATUS Status;
char qxx[5];
for (;;) {
/*
* Check EC_SCI.
*
* Bail out if the EC_SCI bit of the status register is not set.
* Note that this function should only be called when
* this bit is set (polling is used to detect IBE/OBF events).
*
* It is safe to do this without locking the controller, as it's
* OK to call EcQuery when there's no data ready; in the worst
* case we should just find nothing waiting for us and bail.
*/
if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
break;
/*
* Find out why the EC is signalling us
*/
Status = EcQuery(sc, &Data);
/*
* If we failed to get anything from the EC, give up
*/
if (Status != AE_OK) {
device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status));
break;
}
/*
* Evaluate _Qxx to respond to the controller.
*/
sprintf(qxx, "_Q%02x", Data);
strupr(qxx);
if ((Status - AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL)) != AE_OK) {
device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
qxx, acpi_strerror(Status));
}
}
}
static ACPI_STATUS
EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
{
/*
* Just pass the context through, there's nothing to do here.
*/
*RegionContext = Context;
return(AE_OK);
}
static ACPI_STATUS
EcSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value, void *Context, void *RegionContext)
{
struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context;
ACPI_STATUS Status = AE_OK;
EC_REQUEST EcRequest;
if ((Address > 0xFF) || (width != 8) || (Value == NULL) || (Context == NULL))
return(AE_BAD_PARAMETER);
switch (Function) {
case ADDRESS_SPACE_READ:
EcRequest.Command = EC_COMMAND_READ;
EcRequest.Address = Address;
EcRequest.Data = 0;
break;
case ADDRESS_SPACE_WRITE:
EcRequest.Command = EC_COMMAND_WRITE;
EcRequest.Address = Address;
EcRequest.Data = (UINT8)(*Value);
break;
default:
device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
return(AE_BAD_PARAMETER);
}
/*
* Perform the transaction.
*/
if ((Status = EcTransaction(sc, &EcRequest)) == AE_OK)
(*Value) = (UINT32)EcRequest.Data;
return(Status);
}
static ACPI_STATUS
EcDefaultSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value, void *Context, void *RegionContext)
{
if ((Address > 0xFF) || (width != 8) || (Value == NULL) || (Context == NULL))
return(AE_BAD_PARAMETER);
switch (Function) {
case ADDRESS_SPACE_READ:
printf("ACPI: Illegal EC read from 0x%x\n", Address);
*Value = 0;
break;
case ADDRESS_SPACE_WRITE:
printf("ACPI: Illegal EC write 0x%x to 0x%x\n", *Value, Address);
break;
default:
printf("ACPI: Illegal EC unknown operation");
break;
}
/* let things keep going */
return(AE_OK);
}
static ACPI_STATUS
EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
{
EC_STATUS EcStatus;
UINT32 i = 0;
if (!EcIsLocked(sc))
device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
/*
* Stall 1us:
* ----------
* Stall for 1 microsecond before reading the status register
* for the first time. This allows the EC to set the IBF/OBF
* bit to its proper state.
*
* XXX it is not clear why we read the CSR twice.
*/
AcpiOsSleepUsec(1);
EcStatus = EC_GET_CSR(sc);
/*
* Wait For Event:
* ---------------
* Poll the EC status register to detect completion of the last
* command. Wait up to 10ms (in 100us chunks) for this to occur.
*/
for (i = 0; i < 100; i++) {
EcStatus = EC_GET_CSR(sc);
if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
(EcStatus & EC_FLAG_OUTPUT_BUFFER))
return(AE_OK);
if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
!(EcStatus & EC_FLAG_INPUT_BUFFER))
return(AE_OK);
AcpiOsSleepUsec(100);
}
return(AE_ERROR);
}
static ACPI_STATUS
EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
{
ACPI_STATUS Status;
if ((Status = EcLock(sc)) != AE_OK)
return(Status);
EC_SET_CSR(sc, EC_COMMAND_QUERY);
Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
if (Status == AE_OK)
*Data = EC_GET_DATA(sc);
EcUnlock(sc);
if (Status != AE_OK)
device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
return(Status);
}
static ACPI_STATUS
EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
{
ACPI_STATUS Status;
/*
* Lock the EC
*/
if ((Status = EcLock(sc)) != AE_OK)
return(Status);
/*
* Disable EC GPE:
* ---------------
* Disable EC interrupts (GPEs) from occuring during this transaction.
* This is done here as EcTransaction() is also called by the EC GPE
* handler -- where disabling/re-enabling the EC GPE is automatically
* handled by the ACPI Core Subsystem.
*/
if (AcpiDisableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
device_printf(sc->ec_dev, "EcRequest: Unable to disable the EC GPE.\n");
/*
* Perform the transaction.
*/
switch (EcRequest->Command) {
case EC_COMMAND_READ:
Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
break;
case EC_COMMAND_WRITE:
Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
break;
default:
Status = AE_SUPPORT;
break;
}
/*
* Clear & Re-Enable the EC GPE:
* -----------------------------
* 'Consume' any EC GPE events that we generated while performing
* the transaction (e.g. IBF/OBF). Clearing the GPE here shouldn't
* have an adverse affect on outstanding EC-SCI's, as the source
* (EC-SCI) will still be high and thus should trigger the GPE
* immediately after we re-enabling it.
*/
if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
/*
* Unlock the EC
*/
EcUnlock(sc);
return(Status);
}
static ACPI_STATUS
EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
{
ACPI_STATUS Status;
if (!EcIsLocked(sc))
device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
/*EcBurstEnable(EmbeddedController);*/
EC_SET_CSR(sc, EC_COMMAND_READ);
if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
return(Status);
}
EC_SET_DATA(sc, Address);
if ((Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
return(Status);
}
(*Data) = EC_GET_DATA(sc);
/*EcBurstDisable(EmbeddedController);*/
return(AE_OK);
}
static ACPI_STATUS
EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
{
ACPI_STATUS Status;
if (!EcIsLocked(sc))
device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
/*EcBurstEnable(EmbeddedController);*/
EC_SET_CSR(sc, EC_COMMAND_WRITE);
if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
return(Status);
}
EC_SET_DATA(sc, Address);
if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
return(Status);
}
EC_SET_DATA(sc, *Data);
if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
return(Status);
}
/*EcBurstDisable(EmbeddedController);*/
return(AE_OK);
}

196
sys/dev/acpica/acpi_ecreg.h Normal file
View File

@ -0,0 +1,196 @@
/*-
* 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$
*/
/******************************************************************************
*
* 1. Copyright Notice
*
* Some or all of this work - Copyright (c) 1999, Intel Corp. All rights
* reserved.
*
* 2. License
*
* 2.1. This is your license from Intel Corp. under its intellectual property
* rights. You may have additional license terms from the party that provided
* you this software, covering your right to use that party's intellectual
* property rights.
*
* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
* copy of the source code appearing in this file ("Covered Code") an
* irrevocable, perpetual, worldwide license under Intel's copyrights in the
* base code distributed originally by Intel ("Original Intel Code") to copy,
* make derivatives, distribute, use and display any portion of the Covered
* Code in any form, with the right to sublicense such rights; and
*
* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
* license (with the right to sublicense), under only those claims of Intel
* patents that are infringed by the Original Intel Code, to make, use, sell,
* offer to sell, and import the Covered Code and derivative works thereof
* solely to the minimum extent necessary to exercise the above copyright
* license, and in no event shall the patent license extend to any additions
* to or modifications of the Original Intel Code. No other license or right
* is granted directly or by implication, estoppel or otherwise;
*
* The above copyright and patent license is granted only if the following
* conditions are met:
*
* 3. Conditions
*
* 3.1. Redistribution of Source with Rights to Further Distribute Source.
* Redistribution of source code of any substantial portion of the Covered
* Code or modification with rights to further distribute source must include
* the above Copyright Notice, the above License, this list of Conditions,
* and the following Disclaimer and Export Compliance provision. In addition,
* Licensee must cause all Covered Code to which Licensee contributes to
* contain a file documenting the changes Licensee made to create that Covered
* Code and the date of any change. Licensee must include in that file the
* documentation of any changes made by any predecessor Licensee. Licensee
* must include a prominent statement that the modification is derived,
* directly or indirectly, from Original Intel Code.
*
* 3.2. Redistribution of Source with no Rights to Further Distribute Source.
* Redistribution of source code of any substantial portion of the Covered
* Code or modification without rights to further distribute source must
* include the following Disclaimer and Export Compliance provision in the
* documentation and/or other materials provided with distribution. In
* addition, Licensee may not authorize further sublicense of source of any
* portion of the Covered Code, and must include terms to the effect that the
* license from Licensee to its licensee is limited to the intellectual
* property embodied in the software Licensee provides to its licensee, and
* not to intellectual property embodied in modifications its licensee may
* make.
*
* 3.3. Redistribution of Executable. Redistribution in executable form of any
* substantial portion of the Covered Code or modification must reproduce the
* above Copyright Notice, and the following Disclaimer and Export Compliance
* provision in the documentation and/or other materials provided with the
* distribution.
*
* 3.4. Intel retains all right, title, and interest in and to the Original
* Intel Code.
*
* 3.5. Neither the name Intel nor any other trademark owned or controlled by
* Intel shall be used in advertising or otherwise to promote the sale, use or
* other dealings in products derived from or relating to the Covered Code
* without prior written authorization from Intel.
*
* 4. Disclaimer and Export Compliance
*
* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
* LIMITED REMEDY.
*
* 4.3. Licensee shall not export, either directly or indirectly, any of this
* software or system incorporating such software without first obtaining any
* required license or other approval from the U. S. Department of Commerce or
* any other agency or department of the United States Government. In the
* event Licensee exports any such software from the United States or
* re-exports any such software from a foreign destination, Licensee shall
* ensure that the distribution and export/re-export of the software is in
* compliance with all laws, regulations, orders, or other restrictions of the
* U.S. Export Administration Regulations. Licensee agrees that neither it nor
* any of its subsidiaries will export/re-export any technical data, process,
* software, or service, directly or indirectly, to any country for which the
* United States government or any agency thereof requires an export license,
* other governmental approval, or letter of assurance, without first obtaining
* such license, approval or letter.
*
*****************************************************************************/
/*
* EC_COMMAND:
* -----------
*/
typedef UINT8 EC_COMMAND;
#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00)
#define EC_COMMAND_READ ((EC_COMMAND) 0x80)
#define EC_COMMAND_WRITE ((EC_COMMAND) 0x81)
#define EC_COMMAND_BURST_ENABLE ((EC_COMMAND) 0x82)
#define EC_COMMAND_BURST_DISABLE ((EC_COMMAND) 0x83)
#define EC_COMMAND_QUERY ((EC_COMMAND) 0x84)
/*
* EC_STATUS:
* ----------
* The encoding of the EC status register is illustrated below.
* Note that a set bit (1) indicates the property is TRUE
* (e.g. if bit 0 is set then the output buffer is full).
* +-+-+-+-+-+-+-+-+
* |7|6|5|4|3|2|1|0|
* +-+-+-+-+-+-+-+-+
* | | | | | | | |
* | | | | | | | +- Output Buffer Full?
* | | | | | | +--- Input Buffer Full?
* | | | | | +----- <reserved>
* | | | | +------- Data Register is Command Byte?
* | | | +--------- Burst Mode Enabled?
* | | +----------- SCI Event?
* | +------------- SMI Event?
* +--------------- <Reserved>
*
*/
typedef UINT8 EC_STATUS;
#define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01)
#define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02)
#define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10)
#define EC_FLAG_SCI ((EC_STATUS) 0x20)
/*
* EC_EVENT:
* ---------
*/
typedef UINT8 EC_EVENT;
#define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00)
#define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01)
#define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02)
#define EC_EVENT_SCI ((EC_EVENT) 0x20)
/*
* Register access primitives
*/
#define EC_GET_DATA(sc) bus_space_read_1 (sc->ec_data_tag, sc->ec_data_handle, 0)
#define EC_SET_DATA(sc, v) bus_space_write_1(sc->ec_data_tag, sc->ec_data_handle, 0, v)
#define EC_GET_CSR(sc) bus_space_read_1 (sc->ec_csr_tag, sc->ec_csr_handle, 0)
#define EC_SET_CSR(sc, v) bus_space_write_1(sc->ec_csr_tag, sc->ec_csr_handle, 0, v)

442
sys/dev/acpica/acpi_isa.c Normal file
View File

@ -0,0 +1,442 @@
/*-
* 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$
*/
/*
* ISA bus enumerator using PnP HIDs from ACPI space.
*/
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <isa/isavar.h>
#include "acpi.h"
#include <dev/acpica/acpivar.h>
#define PNP_HEXTONUM(c) ((c) >= 'a' \
? (c) - 'a' + 10 \
: ((c) >= 'A' \
? (c) - 'A' + 10 \
: (c) - '0'))
#define PNP_EISAID(s) \
((((s[0] - '@') & 0x1f) << 2) \
| (((s[1] - '@') & 0x18) >> 3) \
| (((s[1] - '@') & 0x07) << 13) \
| (((s[2] - '@') & 0x1f) << 8) \
| (PNP_HEXTONUM(s[4]) << 16) \
| (PNP_HEXTONUM(s[3]) << 20) \
| (PNP_HEXTONUM(s[6]) << 24) \
| (PNP_HEXTONUM(s[5]) << 28))
static void acpi_isa_set_init(device_t dev, void **context);
static void acpi_isa_set_done(device_t dev, void *context);
static void acpi_isa_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
static void acpi_isa_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_isa_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
static void acpi_isa_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_isa_set_irq(device_t dev, void *context, u_int32_t irq);
static void acpi_isa_set_drq(device_t dev, void *context, u_int32_t drq);
static void acpi_isa_set_start_dependant(device_t dev, void *context, int preference);
static void acpi_isa_set_end_dependant(device_t dev, void *context);
static struct acpi_parse_resource_set acpi_isa_parse_set = {
acpi_isa_set_init,
acpi_isa_set_done,
acpi_isa_set_ioport,
acpi_isa_set_iorange,
acpi_isa_set_memory,
acpi_isa_set_memoryrange,
acpi_isa_set_irq,
acpi_isa_set_drq,
acpi_isa_set_start_dependant,
acpi_isa_set_end_dependant
};
#define MAXDEP 8
struct acpi_isa_context {
int ai_config;
int ai_nconfigs;
struct isa_config ai_configs[MAXDEP + 1];
int ai_priorities[MAXDEP + 1];
};
static void acpi_isa_set_config(void *arg, struct isa_config *config, int enable);
static void acpi_isa_identify(driver_t *driver, device_t bus);
static ACPI_STATUS acpi_isa_identify_child(ACPI_HANDLE handle, UINT32 level,
void *context, void **status);
static device_method_t acpi_isa_methods[] = {
DEVMETHOD(device_identify, acpi_isa_identify),
{0, 0}
};
static driver_t acpi_isa_driver = {
"acpi_isa",
acpi_isa_methods,
1,
};
static devclass_t acpi_isa_devclass;
DRIVER_MODULE(acpi_isa, isa, acpi_isa_driver, acpi_isa_devclass, 0, 0);
/*
* This function is called to make the selected configuration
* active.
*/
static void
acpi_isa_set_config(void *arg, struct isa_config *config, int enable)
{
}
/*
* Interrogate ACPI for devices which might be attatched to an ISA
* bus.
*
* Note that it is difficult to determine whether a device in the ACPI
* namespace is or is not visible to the ISA bus, and thus we are a
* little too generous here and just export everything with _HID
* and _CRS.
*/
static void
acpi_isa_identify(driver_t *driver, device_t bus)
{
ACPI_HANDLE parent;
ACPI_STATUS status;
/*
* Look for the _SB_ scope, which will contain all the devices
* we are likely to support.
*/
if ((status = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent)) != AE_OK) {
device_printf(bus, "no ACPI _SB_ scope - %s\n", acpi_strerror(status));
return;
}
if ((status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100, acpi_isa_identify_child, bus, NULL)) != AE_OK) {
device_printf(bus, "AcpiWalkNamespace on _SB_ failed - %s\n", acpi_strerror(status));
return;
}
}
/*
* Check a device to see whether it makes sense to try attaching it to an
* ISA bus, and if so, do so.
*
* Note that we *must* always return AE_OK, or the namespace walk will terminate.
*
* XXX Note also that this is picking up a *lot* of things that are not ISA devices.
* Should we consider lazy-binding this so that only the ID is saved and resources
* are not parsed until the device is claimed by a driver?
*/
static ACPI_STATUS
acpi_isa_identify_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
{
ACPI_DEVICE_INFO devinfo;
ACPI_BUFFER buf;
device_t child, bus = (device_t)context;
u_int32_t devid;
/*
* Try to get information about the device
*/
if (AcpiGetObjectInfo(handle, &devinfo) != AE_OK)
return(AE_OK);
/*
* Reformat the _HID value into 32 bits.
*/
if (!(devinfo.Valid & ACPI_VALID_HID))
return(AE_OK);
/*
* XXX Try to avoid passing stuff to ISA that it just isn't interested
* in. This is the *wrong* solution, and what needs to be done
* involves just sending ISA the PnP ID and a handle, and then
* lazy-parsing the resources if and only if a driver attaches.
* With the way that ISA currently works (using bus_probe_and_attach)
* this is very difficult. Maybe we need a device_configure method?
*/
if (!(strncmp(devinfo.HardwareId, "PNP0C", 5)))
return(AE_OK);
devid = PNP_EISAID(devinfo.HardwareId);
/* XXX check _STA here? */
if (devinfo.Valid & ACPI_VALID_STA) {
}
/*
* Fetch our current settings.
*
* XXX Note that we may want to support alternate settings at some
* point as well.
*/
if (acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf) != AE_OK)
return(AE_OK);
/*
* Add the device and parse our resources
*/
child = BUS_ADD_CHILD(bus, ISA_ORDER_PNP, NULL, -1);
isa_set_vendorid(child, devid);
isa_set_logicalid(child, devid);
ISA_SET_CONFIG_CALLBACK(bus, child, acpi_isa_set_config, 0);
acpi_parse_resources(child, handle, &acpi_isa_parse_set);
AcpiOsFree(buf.Pointer);
if (!device_get_desc(child))
device_set_desc_copy(child, devinfo.HardwareId);
/*
* XXX Parse configuration data and _CID list to find compatible IDs
*/
return(AE_OK);
}
static void
acpi_isa_set_init(device_t dev, void **context)
{
struct acpi_isa_context *cp;
cp = malloc(sizeof(*cp), M_DEVBUF, M_NOWAIT);
bzero(cp, sizeof(*cp));
cp->ai_nconfigs = 1;
*context = cp;
}
static void
acpi_isa_set_done(device_t dev, void *context)
{
struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
struct isa_config *config, *configs;
device_t parent;
int i, j;
if (cp == NULL)
return;
parent = device_get_parent(dev);
/* simple config without dependants */
if (cp->ai_nconfigs == 1) {
ISA_ADD_CONFIG(parent, dev, cp->ai_priorities[0], &cp->ai_configs[0]);
goto done;
}
/* Cycle through dependant configs merging primary details */
configs = &cp->ai_configs[0];
for(i = 1; i < cp->ai_nconfigs; i++) {
config = &configs[i];
for(j = 0; j < configs[0].ic_nmem; j++) {
if (config->ic_nmem == ISA_NMEM) {
device_printf(parent, "too many memory ranges\n");
free(configs, M_DEVBUF);
return;
}
config->ic_mem[config->ic_nmem] = configs[0].ic_mem[j];
config->ic_nmem++;
}
for(j = 0; j < configs[0].ic_nport; j++) {
if (config->ic_nport == ISA_NPORT) {
device_printf(parent, "too many port ranges\n");
free(configs, M_DEVBUF);
return;
}
config->ic_port[config->ic_nport] = configs[0].ic_port[j];
config->ic_nport++;
}
for(j = 0; j < configs[0].ic_nirq; j++) {
if (config->ic_nirq == ISA_NIRQ) {
device_printf(parent, "too many irq ranges\n");
free(configs, M_DEVBUF);
return;
}
config->ic_irqmask[config->ic_nirq] = configs[0].ic_irqmask[j];
config->ic_nirq++;
}
for(j = 0; j < configs[0].ic_ndrq; j++) {
if (config->ic_ndrq == ISA_NDRQ) {
device_printf(parent, "too many drq ranges\n");
free(configs, M_DEVBUF);
return;
}
config->ic_drqmask[config->ic_ndrq] = configs[0].ic_drqmask[j];
config->ic_ndrq++;
}
(void)ISA_ADD_CONFIG(parent, dev, cp->ai_priorities[i], &configs[i]);
}
done:
free(cp, M_DEVBUF);
}
static void
acpi_isa_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
{
struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
struct isa_config *ic = &cp->ai_configs[cp->ai_config];
if (cp == NULL)
return;
if (ic->ic_nport == ISA_NPORT) {
printf("too many ports\n");
return;
}
ic->ic_port[ic->ic_nport].ir_start = base;
ic->ic_port[ic->ic_nport].ir_end = base + length - 1;
ic->ic_port[ic->ic_nport].ir_size = length;
ic->ic_port[ic->ic_nport].ir_align = 1;
ic->ic_nport++;
}
static void
acpi_isa_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_isa_context *cp = (struct acpi_isa_context *)context;
struct isa_config *ic = &cp->ai_configs[cp->ai_config];
if (cp == NULL)
return;
if (ic->ic_nport == ISA_NPORT) {
printf("too many ports\n");
return;
}
ic->ic_port[ic->ic_nport].ir_start = low;
ic->ic_port[ic->ic_nport].ir_end = high + length - 1;
ic->ic_port[ic->ic_nport].ir_size = length;
ic->ic_port[ic->ic_nport].ir_align = imin(1, align);
ic->ic_nport++;
}
static void
acpi_isa_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
{
struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
struct isa_config *ic = &cp->ai_configs[cp->ai_config];
if (cp == NULL)
return;
if (ic->ic_nmem == ISA_NMEM) {
printf("too many memory ranges\n");
return;
}
ic->ic_mem[ic->ic_nmem].ir_start = base;
ic->ic_mem[ic->ic_nmem].ir_end = base + length - 1;
ic->ic_mem[ic->ic_nmem].ir_size = length;
ic->ic_mem[ic->ic_nmem].ir_align = 1;
ic->ic_nmem++;
}
static void
acpi_isa_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_isa_context *cp = (struct acpi_isa_context *)context;
struct isa_config *ic = &cp->ai_configs[cp->ai_config];
if (cp == NULL)
return;
if (ic->ic_nmem == ISA_NMEM) {
printf("too many memory ranges\n");
return;
}
ic->ic_mem[ic->ic_nmem].ir_start = low;
ic->ic_mem[ic->ic_nmem].ir_end = high + length - 1;
ic->ic_mem[ic->ic_nmem].ir_size = length;
ic->ic_mem[ic->ic_nmem].ir_align = imin(1, align);
ic->ic_nmem++;
}
static void
acpi_isa_set_irq(device_t dev, void *context, u_int32_t irq)
{
struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
struct isa_config *ic = &cp->ai_configs[cp->ai_config];
if (cp == NULL)
return;
if (ic->ic_nirq == ISA_NIRQ) {
printf("too many IRQs\n");
return;
}
ic->ic_irqmask[ic->ic_nirq] = 1 << irq;
ic->ic_nirq++;
}
static void
acpi_isa_set_drq(device_t dev, void *context, u_int32_t drq)
{
struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
struct isa_config *ic = &cp->ai_configs[cp->ai_config];
if (cp == NULL)
return;
if (ic->ic_nirq == ISA_NDRQ) {
printf("too many DRQs\n");
return;
}
ic->ic_drqmask[ic->ic_ndrq] = drq;
ic->ic_ndrq++;
}
/*
* XXX the "too many dependant configs" logic here is wrong, and
* will spam the last dependant config.
*/
static void
acpi_isa_set_start_dependant(device_t dev, void *context, int preference)
{
struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
if (cp == NULL)
return;
if (cp->ai_nconfigs > MAXDEP) {
printf("too many dependant configs\n");
return;
}
cp->ai_config = cp->ai_nconfigs;
cp->ai_priorities[cp->ai_config] = preference;
cp->ai_nconfigs++;
}
static void
acpi_isa_set_end_dependant(device_t dev, void *context)
{
struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
if (cp == NULL)
return;
cp->ai_config = 0;
}

152
sys/dev/acpica/acpi_lid.c Normal file
View File

@ -0,0 +1,152 @@
/*-
* Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
* Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
* Copyright (c) 2000 Michael Smith <msmith@freebd.org>
* 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 "acpi.h"
#include <dev/acpica/acpivar.h>
struct acpi_lid_softc {
device_t lid_dev;
ACPI_HANDLE lid_handle;
int lid_status; /* open or closed */
};
static int acpi_lid_probe(device_t dev);
static int acpi_lid_attach(device_t dev);
static void acpi_lid_notify_status_changed(void *arg);
static void acpi_lid_notify_handler(ACPI_HANDLE h,UINT32 notify, void *context);
static device_method_t acpi_lid_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, acpi_lid_probe),
DEVMETHOD(device_attach, acpi_lid_attach),
{0, 0}
};
static driver_t acpi_lid_driver = {
"acpi_lid",
acpi_lid_methods,
sizeof(struct acpi_lid_softc),
};
devclass_t acpi_lid_devclass;
DRIVER_MODULE(acpi_lid, acpi, acpi_lid_driver, acpi_lid_devclass, 0, 0);
static int
acpi_lid_probe(device_t dev)
{
if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
acpi_MatchHid(dev, "PNP0C0D")) {
device_set_desc(dev, "Control Method Lid Switch");
return(0);
}
return(ENXIO);
}
static int
acpi_lid_attach(device_t dev)
{
struct acpi_lid_softc *sc;
sc = device_get_softc(dev);
sc->lid_dev = dev;
sc->lid_handle = acpi_get_handle(dev);
/*
* Install notification handler
*/
AcpiInstallNotifyHandler(sc->lid_handle, ACPI_DEVICE_NOTIFY, acpi_lid_notify_handler, sc);
return(0);
}
static void
acpi_lid_notify_status_changed(void *arg)
{
struct acpi_lid_softc *sc;
struct acpi_softc *acpi_sc;
ACPI_BUFFER Buffer;
ACPI_OBJECT Object;
sc = (struct acpi_lid_softc *)arg;
/*
* Evaluate _LID and check the return value
* Zero: The lid is closed
* Non-zero: The lid is open
*/
Buffer.Length = sizeof(Object);
Buffer.Pointer = &Object;
if (AcpiEvaluateObject(sc->lid_handle, "_LID", NULL, &Buffer) != AE_OK)
return;
if (Object.Type != ACPI_TYPE_NUMBER)
return;
/*
* Update lid status
*/
sc->lid_status = Object.Number.Value;
device_printf(sc->lid_dev, "Lid %s\n", sc->lid_status ? "opened" : "closed");
acpi_sc = acpi_device_get_parent_softc(sc->lid_dev);
if (acpi_sc == NULL) {
return;
}
if (sc->lid_status == 0) {
EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx);
} else {
EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx);
}
}
/* XXX maybe not here */
#define ACPI_NOTIFY_STATUS_CHANGED 0x80
static void
acpi_lid_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
{
struct acpi_lid_softc *sc = (struct acpi_lid_softc *)context;
switch (notify) {
case ACPI_NOTIFY_STATUS_CHANGED:
AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_lid_notify_status_changed, sc);
break;
default:
return; /* unknown notification value */
}
}

236
sys/dev/acpica/acpi_pcib.c Normal file
View File

@ -0,0 +1,236 @@
/*-
* 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 "acpi.h"
#include <dev/acpica/acpivar.h>
#include <machine/pci_cfgreg.h>
#include <pci/pcivar.h>
#include "pcib_if.h"
struct acpi_pcib_softc {
device_t ap_dev;
ACPI_HANDLE ap_handle;
int ap_segment; /* analagous to Alpha 'hose' */
int ap_bus; /* bios-assigned bus number */
};
static int acpi_pcib_probe(device_t bus);
static int acpi_pcib_attach(device_t bus);
static int acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
static int acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
static int acpi_pcib_maxslots(device_t dev);
static u_int32_t acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes);
static void acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
u_int32_t data, int bytes);
static int acpi_pcib_route_interrupt(device_t bus, int device, int pin);
static device_method_t acpi_pcib_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, acpi_pcib_probe),
DEVMETHOD(device_attach, acpi_pcib_attach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, acpi_pcib_read_ivar),
DEVMETHOD(bus_write_ivar, acpi_pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
/* pcib interface */
DEVMETHOD(pcib_maxslots, acpi_pcib_maxslots),
DEVMETHOD(pcib_read_config, acpi_pcib_read_config),
DEVMETHOD(pcib_write_config, acpi_pcib_write_config),
DEVMETHOD(pcib_route_interrupt, acpi_pcib_route_interrupt),
{0, 0}
};
static driver_t acpi_pcib_driver = {
"acpi_pcib",
acpi_pcib_methods,
sizeof(struct acpi_pcib_softc),
};
devclass_t acpi_pcib_devclass;
DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_driver, acpi_pcib_devclass, 0, 0);
static int
acpi_pcib_probe(device_t dev)
{
if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
acpi_MatchHid(dev, "PNP0A03")) {
/*
* Set device description
*/
device_set_desc(dev, "Host-PCI bridge");
return(0);
}
return(ENXIO);
}
static int
acpi_pcib_attach(device_t dev)
{
struct acpi_pcib_softc *sc;
device_t child;
ACPI_STATUS status;
sc = device_get_softc(dev);
sc->ap_dev = dev;
sc->ap_handle = acpi_get_handle(dev);
/*
* Don't attach if we're not really there.
*
* XXX this isn't entirely correct, since we may be a PCI bus
* on a hot-plug docking station, etc.
*/
if (!acpi_DeviceIsPresent(dev))
return(ENXIO);
/*
* Get our segment number by evaluating _SEG
* It's OK for this to not exist.
*/
if ((status = acpi_EvaluateNumber(sc->ap_handle, "_SEG", &sc->ap_segment)) != AE_OK) {
if (status != AE_NOT_FOUND) {
device_printf(dev, "could not evaluate _SEG - %s\n", acpi_strerror(status));
return(ENXIO);
}
/* if it's not found, assume 0 */
sc->ap_segment = 0;
}
/*
* Get our base bus number by evaluating _BBN
* If this doesn't exist, we assume we're bus number 0.
*
* XXX note that it may also not exist in the case where we are
* meant to use a private configuration space mechanism for this bus,
* so we should dig out our resources and check to see if we have
* anything like that. How do we do this?
*/
if ((status = acpi_EvaluateNumber(sc->ap_handle, "_BBN", &sc->ap_bus)) != AE_OK) {
if (status != AE_NOT_FOUND) {
device_printf(dev, "could not evaluate _BBN - %s\n", acpi_strerror(status));
return(ENXIO);
}
/* if it's not found, assume 0 */
sc->ap_bus = 0;
}
/*
* XXX we should check here to make sure that this bus number hasn't already
* been attached. It shouldn't really be an issue.
*/
if ((child = device_add_child(dev, "pci", sc->ap_bus)) == NULL) {
device_printf(device_get_parent(dev), "couldn't attach pci bus");
return(ENXIO);
}
/*
* XXX If we have the requisite information, and if we don't think the
* default PCI configuration space handlers can deal with this bus,
* we should attach our own handler.
*/
/* XXX invoke _REG on this for the PCI config space address space? */
/*
* Now go scan the bus.
*
* XXX is it possible to defer this and count on the nexus getting to it
* reliably after it's finished with ACPI? Should we really care?
*/
return(bus_generic_attach(dev));
}
static int
acpi_pcib_maxslots(device_t dev)
{
return(31);
}
static int
acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct acpi_pcib_softc *sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_BUS:
*result = sc->ap_bus;
return(0);
}
return(ENOENT);
}
static int
acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
{
struct acpi_pcib_softc *sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_BUS:
sc->ap_bus = value;
return(0);
}
return(ENOENT);
}
static u_int32_t
acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes)
{
return(pci_cfgregread(bus, slot, func, reg, bytes));
}
static void
acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg, u_int32_t data, int bytes)
{
pci_cfgregwrite(bus, slot, func, reg, data, bytes);
}
static int
acpi_pcib_route_interrupt(device_t bus, int device, int pin)
{
return(255); /* XXX implement */
}

View File

@ -0,0 +1,236 @@
/*-
* 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 "acpi.h"
#include <dev/acpica/acpivar.h>
#include <machine/pci_cfgreg.h>
#include <pci/pcivar.h>
#include "pcib_if.h"
struct acpi_pcib_softc {
device_t ap_dev;
ACPI_HANDLE ap_handle;
int ap_segment; /* analagous to Alpha 'hose' */
int ap_bus; /* bios-assigned bus number */
};
static int acpi_pcib_probe(device_t bus);
static int acpi_pcib_attach(device_t bus);
static int acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
static int acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
static int acpi_pcib_maxslots(device_t dev);
static u_int32_t acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes);
static void acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
u_int32_t data, int bytes);
static int acpi_pcib_route_interrupt(device_t bus, int device, int pin);
static device_method_t acpi_pcib_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, acpi_pcib_probe),
DEVMETHOD(device_attach, acpi_pcib_attach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, acpi_pcib_read_ivar),
DEVMETHOD(bus_write_ivar, acpi_pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
/* pcib interface */
DEVMETHOD(pcib_maxslots, acpi_pcib_maxslots),
DEVMETHOD(pcib_read_config, acpi_pcib_read_config),
DEVMETHOD(pcib_write_config, acpi_pcib_write_config),
DEVMETHOD(pcib_route_interrupt, acpi_pcib_route_interrupt),
{0, 0}
};
static driver_t acpi_pcib_driver = {
"acpi_pcib",
acpi_pcib_methods,
sizeof(struct acpi_pcib_softc),
};
devclass_t acpi_pcib_devclass;
DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_driver, acpi_pcib_devclass, 0, 0);
static int
acpi_pcib_probe(device_t dev)
{
if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
acpi_MatchHid(dev, "PNP0A03")) {
/*
* Set device description
*/
device_set_desc(dev, "Host-PCI bridge");
return(0);
}
return(ENXIO);
}
static int
acpi_pcib_attach(device_t dev)
{
struct acpi_pcib_softc *sc;
device_t child;
ACPI_STATUS status;
sc = device_get_softc(dev);
sc->ap_dev = dev;
sc->ap_handle = acpi_get_handle(dev);
/*
* Don't attach if we're not really there.
*
* XXX this isn't entirely correct, since we may be a PCI bus
* on a hot-plug docking station, etc.
*/
if (!acpi_DeviceIsPresent(dev))
return(ENXIO);
/*
* Get our segment number by evaluating _SEG
* It's OK for this to not exist.
*/
if ((status = acpi_EvaluateNumber(sc->ap_handle, "_SEG", &sc->ap_segment)) != AE_OK) {
if (status != AE_NOT_FOUND) {
device_printf(dev, "could not evaluate _SEG - %s\n", acpi_strerror(status));
return(ENXIO);
}
/* if it's not found, assume 0 */
sc->ap_segment = 0;
}
/*
* Get our base bus number by evaluating _BBN
* If this doesn't exist, we assume we're bus number 0.
*
* XXX note that it may also not exist in the case where we are
* meant to use a private configuration space mechanism for this bus,
* so we should dig out our resources and check to see if we have
* anything like that. How do we do this?
*/
if ((status = acpi_EvaluateNumber(sc->ap_handle, "_BBN", &sc->ap_bus)) != AE_OK) {
if (status != AE_NOT_FOUND) {
device_printf(dev, "could not evaluate _BBN - %s\n", acpi_strerror(status));
return(ENXIO);
}
/* if it's not found, assume 0 */
sc->ap_bus = 0;
}
/*
* XXX we should check here to make sure that this bus number hasn't already
* been attached. It shouldn't really be an issue.
*/
if ((child = device_add_child(dev, "pci", sc->ap_bus)) == NULL) {
device_printf(device_get_parent(dev), "couldn't attach pci bus");
return(ENXIO);
}
/*
* XXX If we have the requisite information, and if we don't think the
* default PCI configuration space handlers can deal with this bus,
* we should attach our own handler.
*/
/* XXX invoke _REG on this for the PCI config space address space? */
/*
* Now go scan the bus.
*
* XXX is it possible to defer this and count on the nexus getting to it
* reliably after it's finished with ACPI? Should we really care?
*/
return(bus_generic_attach(dev));
}
static int
acpi_pcib_maxslots(device_t dev)
{
return(31);
}
static int
acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct acpi_pcib_softc *sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_BUS:
*result = sc->ap_bus;
return(0);
}
return(ENOENT);
}
static int
acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
{
struct acpi_pcib_softc *sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_BUS:
sc->ap_bus = value;
return(0);
}
return(ENOENT);
}
static u_int32_t
acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes)
{
return(pci_cfgregread(bus, slot, func, reg, bytes));
}
static void
acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg, u_int32_t data, int bytes)
{
pci_cfgregwrite(bus, slot, func, reg, data, bytes);
}
static int
acpi_pcib_route_interrupt(device_t bus, int device, int pin)
{
return(255); /* XXX implement */
}

View File

@ -0,0 +1,640 @@
/*-
* 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$
*/
/******************************************************************************
*
* 1. Copyright Notice
*
* Some or all of this work - Copyright (c) 1999, Intel Corp. All rights
* reserved.
*
* 2. License
*
* 2.1. This is your license from Intel Corp. under its intellectual property
* rights. You may have additional license terms from the party that provided
* you this software, covering your right to use that party's intellectual
* property rights.
*
* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
* copy of the source code appearing in this file ("Covered Code") an
* irrevocable, perpetual, worldwide license under Intel's copyrights in the
* base code distributed originally by Intel ("Original Intel Code") to copy,
* make derivatives, distribute, use and display any portion of the Covered
* Code in any form, with the right to sublicense such rights; and
*
* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
* license (with the right to sublicense), under only those claims of Intel
* patents that are infringed by the Original Intel Code, to make, use, sell,
* offer to sell, and import the Covered Code and derivative works thereof
* solely to the minimum extent necessary to exercise the above copyright
* license, and in no event shall the patent license extend to any additions
* to or modifications of the Original Intel Code. No other license or right
* is granted directly or by implication, estoppel or otherwise;
*
* The above copyright and patent license is granted only if the following
* conditions are met:
*
* 3. Conditions
*
* 3.1. Redistribution of Source with Rights to Further Distribute Source.
* Redistribution of source code of any substantial portion of the Covered
* Code or modification with rights to further distribute source must include
* the above Copyright Notice, the above License, this list of Conditions,
* and the following Disclaimer and Export Compliance provision. In addition,
* Licensee must cause all Covered Code to which Licensee contributes to
* contain a file documenting the changes Licensee made to create that Covered
* Code and the date of any change. Licensee must include in that file the
* documentation of any changes made by any predecessor Licensee. Licensee
* must include a prominent statement that the modification is derived,
* directly or indirectly, from Original Intel Code.
*
* 3.2. Redistribution of Source with no Rights to Further Distribute Source.
* Redistribution of source code of any substantial portion of the Covered
* Code or modification without rights to further distribute source must
* include the following Disclaimer and Export Compliance provision in the
* documentation and/or other materials provided with distribution. In
* addition, Licensee may not authorize further sublicense of source of any
* portion of the Covered Code, and must include terms to the effect that the
* license from Licensee to its licensee is limited to the intellectual
* property embodied in the software Licensee provides to its licensee, and
* not to intellectual property embodied in modifications its licensee may
* make.
*
* 3.3. Redistribution of Executable. Redistribution in executable form of any
* substantial portion of the Covered Code or modification must reproduce the
* above Copyright Notice, and the following Disclaimer and Export Compliance
* provision in the documentation and/or other materials provided with the
* distribution.
*
* 3.4. Intel retains all right, title, and interest in and to the Original
* Intel Code.
*
* 3.5. Neither the name Intel nor any other trademark owned or controlled by
* Intel shall be used in advertising or otherwise to promote the sale, use or
* other dealings in products derived from or relating to the Covered Code
* without prior written authorization from Intel.
*
* 4. Disclaimer and Export Compliance
*
* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
* LIMITED REMEDY.
*
* 4.3. Licensee shall not export, either directly or indirectly, any of this
* software or system incorporating such software without first obtaining any
* required license or other approval from the U. S. Department of Commerce or
* any other agency or department of the United States Government. In the
* event Licensee exports any such software from the United States or
* re-exports any such software from a foreign destination, Licensee shall
* ensure that the distribution and export/re-export of the software is in
* compliance with all laws, regulations, orders, or other restrictions of the
* U.S. Export Administration Regulations. Licensee agrees that neither it nor
* any of its subsidiaries will export/re-export any technical data, process,
* software, or service, directly or indirectly, to any country for which the
* United States government or any agency thereof requires an export license,
* other governmental approval, or letter of assurance, without first obtaining
* such license, approval or letter.
*
*****************************************************************************/
/*
* Processor driver.
*
* XXX Note that the power state code here is almost certainly suboptimal.
* We should go raid the Linux code for their ideas and experience.
*
* Code style here is a hairy mix of BSD-like and Intel-like. Should be
* sanitised at some point.
*/
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include "acpi.h"
#include <dev/acpica/acpivar.h>
#define PR_MAX_POWER_STATES 4
#define PR_MAX_PERFORMANCE_STATES 8
#define PR_MAX_THROTTLING_STATES 8
/*
* Processor Commands:
* -------------------
*/
#define PR_COMMAND_GET_INFO ((BM_COMMAND) 0x80)
#define PR_COMMAND_SET_CX_STATE_INFO ((BM_COMMAND) 0x81)
#define PR_COMMAND_GET_THROTTLING_STATE ((BM_COMMAND) 0x82)
#define PR_COMMAND_SET_THROTTLING_STATE ((BM_COMMAND) 0x83)
#define PR_COMMAND_GET_PERF_STATE ((BM_COMMAND) 0x84)
#define PR_COMMAND_SET_PERF_STATE ((BM_COMMAND) 0x85)
#define PR_COMMAND_GET_CURRENT_FREQ ((BM_COMMAND) 0x86)
/*
* PR_POWER_STATE:
* ---------------
*/
typedef u_int32_t PR_POWER_STATE;
#define PR_POWER_STATE_UNKNOWN ((PR_POWER_STATE) 0xFFFFFFFF)
#define PR_POWER_STATE_C0 ((PR_POWER_STATE) 0x00000000)
#define PR_POWER_STATE_C1 ((PR_POWER_STATE) 0x00000001)
#define PR_POWER_STATE_C2 ((PR_POWER_STATE) 0x00000002)
#define PR_POWER_STATE_C3 ((PR_POWER_STATE) 0x00000003)
/*
* Processor Notifications:
* ------------------------
*/
#define PR_NOTIFY_PERF_STATES_CHANGE ((BM_NOTIFY) 0x80)
#define PR_NOTIFY_POWER_STATES_CHANGE ((BM_NOTIFY) 0x81)
typedef struct
{
u_int32_t TimeThreshold;
u_int32_t CountThreshold;
u_int32_t Count;
PR_POWER_STATE TargetState;
} PR_POLICY_VALUES;
/*
* PR_CX_STATE_INFO:
* -----------------
*/
typedef struct
{
u_int32_t Latency;
u_int64_t Utilization;
PR_POLICY_VALUES PromotionPolicy;
PR_POLICY_VALUES DemotionPolicy;
} PR_CX_STATE_INFO;
/*
* PR_POWER_INFO:
* --------------
*/
typedef struct
{
u_int32_t Count;
PR_POWER_STATE ActiveState;
PR_CX_STATE_INFO Info[PR_MAX_POWER_STATES];
} PR_POWER_INFO;
/*
* PR_PERFORMANCE_INFO:
* --------------------
*/
typedef struct
{
u_int32_t Count;
/* TODO... */
} PR_PERFORMANCE_INFO;
/*
* PR_THROTTLING_INFO:
* -------------------
*/
typedef struct
{
u_int32_t Count;
u_int32_t Percentage[PR_MAX_THROTTLING_STATES];
} PR_THROTTLING_INFO;
struct acpi_pr_softc {
device_t pr_dev;
ACPI_HANDLE pr_handle;
PR_POWER_INFO pr_PowerStates;
PR_PERFORMANCE_INFO pr_PerformanceStates;
PR_THROTTLING_INFO pr_ThrottlingStates;
eventhandler_tag pr_idleevent;
/* local APIC data */
PROCESSOR_APIC pr_lapic;
};
#define PR_MAGIC 0x20555043 /* "CPU " */
static void acpi_pr_identify(driver_t *driver, device_t bus);
static ACPI_STATUS acpi_pr_identify_cpu(ACPI_HANDLE handle, UINT32 level, void *context, void **status);
static int acpi_pr_probe(device_t dev);
static int acpi_pr_attach(device_t dev);
static void acpi_pr_FindLapic(device_t dev, ACPI_HANDLE handle, PROCESSOR_APIC *lapic);
static ACPI_STATUS acpi_pr_CalculatePowerStates(struct acpi_pr_softc *sc);
static ACPI_STATUS acpi_pr_CalculatePerformanceStates(struct acpi_pr_softc *sc);
static ACPI_STATUS acpi_pr_CalculateThrottlingStates(struct acpi_pr_softc *sc);
static void acpi_pr_IdleHandler(void *arg, int count);
static ACPI_STATUS acpi_pr_PolicyInitialize(struct acpi_pr_softc *sc);
static device_method_t acpi_pr_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, acpi_pr_identify),
DEVMETHOD(device_probe, acpi_pr_probe),
DEVMETHOD(device_attach, acpi_pr_attach),
{0, 0}
};
static driver_t acpi_pr_driver = {
"acpi_pr",
acpi_pr_methods,
sizeof(struct acpi_pr_softc),
};
devclass_t acpi_pr_devclass;
DRIVER_MODULE(acpi_pr, acpi, acpi_pr_driver, acpi_pr_devclass, 0, 0);
/*
* Scan the \_PR_ scope for processor objects, and attach them accordingly.
*
* XXX note that we should find the local APIC address and obtain a resource
* that we can hand to child devices for access to it...
*/
static void
acpi_pr_identify(driver_t *driver, device_t bus)
{
ACPI_HANDLE handle;
if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_PR_", &handle) == AE_OK)
AcpiWalkNamespace(ACPI_TYPE_PROCESSOR, handle, 2, acpi_pr_identify_cpu, bus, NULL);
}
/*
* Create a child device for CPUs
*/
static ACPI_STATUS
acpi_pr_identify_cpu(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
{
device_t bus = (device_t)context;
device_t child;
PROCESSOR_APIC lapic;
acpi_pr_FindLapic(bus, handle, &lapic);
if (lapic.ProcessorEnabled) {
if ((child = BUS_ADD_CHILD(bus, 0, "acpi_pr", -1)) == NULL) {
device_printf(bus, "could not create CPU device\n");
return(AE_OK);
}
acpi_set_handle(child, handle);
acpi_set_magic(child, PR_MAGIC);
device_set_desc(child, "processor device");
}
return(AE_OK);
}
static int
acpi_pr_probe(device_t dev)
{
if (acpi_get_magic(dev) == PR_MAGIC)
return(0);
return(ENXIO);
}
static int
acpi_pr_attach(device_t dev)
{
struct acpi_pr_softc *sc;
sc = device_get_softc(dev);
sc->pr_dev = dev;
sc->pr_handle = acpi_get_handle(dev);
acpi_pr_FindLapic(dev, sc->pr_handle, &sc->pr_lapic);
/*
* If the APIC information is valid, print it
*/
if (sc->pr_lapic.LocalApicId != (UINT8)0xff)
device_printf(dev, "local APIC ID %d\n", sc->pr_lapic.LocalApicId);
/*
* Fetch operational parameters.
*/
if (acpi_pr_CalculatePowerStates(sc) == AE_OK) {
acpi_pr_PolicyInitialize(sc);
}
acpi_pr_CalculatePerformanceStates(sc);
acpi_pr_CalculateThrottlingStates(sc);
/* XXX call MD cpu-identification here? */
return(0);
}
/*
* Find the Local Apic information for this CPU
*/
static void
acpi_pr_FindLapic(device_t dev, ACPI_HANDLE handle, PROCESSOR_APIC *lapic)
{
ACPI_BUFFER buf;
ACPI_STATUS status;
APIC_HEADER *hdr;
APIC_TABLE *tbl;
PROCESSOR_APIC *pap;
int len, cpuno;
/*
* Assume that we're not going to suceed in finding/parsing the APIC table.
* In this case, CPU 0 is valid, and any other CPU is invalid.
*/
lapic->LocalApicId = 0xff;
lapic->ProcessorEnabled = 0;
if ((status = AcpiGetProcessorId(handle, &cpuno)) != AE_OK) {
device_printf(dev, "error fetching CPU device ID - %s\n", acpi_strerror(status));
return;
}
lapic->ProcessorEnabled = (cpuno == 0);
/*
* Perform the tedious double-get to fetch the actual APIC table, and suck it in.
*/
buf.Length = 0;
buf.Pointer = NULL;
if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_BUFFER_OVERFLOW) {
if (status != AE_NOT_EXIST)
device_printf(dev, "error sizing APIC table - %s\n", acpi_strerror(status));
return;
}
if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL)
return;
if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_OK) {
device_printf(dev, "error fetching APIC table - %s\n", acpi_strerror(status));
return;
}
/*
* Scan the tables looking for this CPU index.
*/
tbl = (APIC_TABLE *)buf.Pointer;
len = tbl->header.Length - sizeof(APIC_TABLE);
hdr = (APIC_HEADER *)((char *)buf.Pointer + sizeof(APIC_TABLE));
while(len > 0) {
if (hdr->Length > len) {
device_printf(dev, "APIC header corrupt (claims %d bytes where only %d left in structure)\n",
hdr->Length, len);
break;
}
/*
* If we have found a processor APIC definition with
* matching CPU index, copy it out and return.
*/
if (hdr->Type == APIC_PROC) {
pap = (PROCESSOR_APIC *)hdr;
if (pap->ProcessorApicId == cpuno) {
bcopy(pap, lapic, sizeof(*pap));
break;
}
}
len -= hdr->Length;
hdr = (APIC_HEADER *)((char *)hdr + hdr->Length);
}
AcpiOsFree(buf.Pointer);
}
static ACPI_STATUS
acpi_pr_CalculatePowerStates(struct acpi_pr_softc *sc)
{
ACPI_STATUS Status = AE_OK;
ACPI_BUFFER Buffer;
ACPI_CX_STATE *State = NULL;
u_int32_t StateCount = 0;
u_int32_t i = 0;
/*
* Set Latency Defaults:
* ---------------------
* Default state latency to ACPI_UINT32_MAX -- meaning that this state
* should not be used by policy. This value is overriden by states
* that are present and have usable latencies (e.g. <= 1000us for C3).
*/
for (i = 0; i < PR_MAX_POWER_STATES; i++)
sc->pr_PowerStates.Info[i].Latency = ACPI_UINT32_MAX;
/*
* Get Power State Latencies:
* --------------------------
*
* XXX Note that ACPICA will never give us back C2 if it costs more than 100us,
* or C3 if it costs more than 1000us, so some of this code is redundant.
*/
Status = acpi_GetIntoBuffer(sc->pr_handle, AcpiGetProcessorCxInfo, &Buffer);
if (Status != AE_OK) {
device_printf(sc->pr_dev, "could not fetch ProcessorCxInfo - %s\n", acpi_strerror(Status));
return(Status);
}
State = (ACPI_CX_STATE*)(Buffer.Pointer);
if (State != NULL) {
device_printf(sc->pr_dev, "supported power states:");
StateCount = Buffer.Length / sizeof(ACPI_CX_STATE);
for (i = 0; i < StateCount; i++) {
/* XXX C3 isn't supportable in MP configurations, how to best handle this? */
if ((State[i].StateNumber < PR_MAX_POWER_STATES) && (State[i].Latency <= 1000)) {
printf(" C%d (%dus)", i, State[i].Latency);
sc->pr_PowerStates.Info[State[i].StateNumber].Latency = State[i].Latency;
}
}
printf("\n");
}
sc->pr_PowerStates.Count = PR_MAX_POWER_STATES;
sc->pr_PowerStates.ActiveState = PR_POWER_STATE_C1;
AcpiOsFree(Buffer.Pointer);
return(Status);
}
static ACPI_STATUS
acpi_pr_CalculatePerformanceStates(struct acpi_pr_softc *sc)
{
ACPI_STATUS Status = AE_OK;
/* TODO... */
return(Status);
}
static ACPI_STATUS
acpi_pr_CalculateThrottlingStates(struct acpi_pr_softc *sc)
{
ACPI_STATUS Status = AE_OK;
ACPI_BUFFER Buffer;
ACPI_CPU_THROTTLING_STATE *State = NULL;
u_int32_t StateCount = 0;
u_int32_t i = 0;
/*
* Get Throttling States:
* ----------------------
*/
Status = acpi_GetIntoBuffer(sc->pr_handle, AcpiGetProcessorThrottlingInfo, &Buffer);
if (Status != AE_OK) {
device_printf(sc->pr_dev, "could not fetch ThrottlingInfo - %s\n", acpi_strerror(Status));
return(Status);
}
State = (ACPI_CPU_THROTTLING_STATE*)(Buffer.Pointer);
if (State != NULL) {
StateCount = Buffer.Length / sizeof(ACPI_CPU_THROTTLING_STATE);
device_printf(sc->pr_dev, "supported throttling states:");
for (i = 0; i < StateCount; i++) {
if (State[i].StateNumber < PR_MAX_THROTTLING_STATES) {
/* TODO: Verify that state is *really* supported by this chipset/processor (e.g. errata). */
sc->pr_ThrottlingStates.Percentage[State[i].StateNumber] = State[i].PercentOfClock;
sc->pr_ThrottlingStates.Count++;
printf(" %d%%", State[i].PercentOfClock);
}
}
printf("\n");
}
AcpiOsFree(Buffer.Pointer);
return(Status);
}
static ACPI_STATUS
acpi_pr_PolicyInitialize(struct acpi_pr_softc *sc)
{
ACPI_STATUS status;
if ((status = AcpiSetProcessorSleepState(sc->pr_handle, sc->pr_PowerStates.ActiveState)) != AE_OK) {
device_printf(sc->pr_dev, "could not set Active sleep state - %s\n", acpi_strerror(status));
return(status);
}
/* XXX need to hook ourselves to be called when things go idle */
/* sc->pr_idleevent = EVENTHANDLER_FAST_REGISTER(idle_event, acpi_pr_IdleHandler, sc, IDLE_PRI_FIRST); */
return(AE_OK);
}
static void
acpi_pr_IdleHandler(void *arg, int count)
{
struct acpi_pr_softc *sc = (struct acpi_pr_softc *)arg;
ACPI_STATUS Status = AE_OK;
PR_CX_STATE_INFO *CxState = NULL;
PR_POWER_STATE ActiveState = PR_POWER_STATE_UNKNOWN;
PR_POWER_STATE NextState = PR_POWER_STATE_UNKNOWN;
u_int32_t PmTimerTicks = 0;
ActiveState = NextState = sc->pr_PowerStates.ActiveState;
CxState = &(sc->pr_PowerStates.Info[ActiveState]);
CxState->Utilization++;
/*
* Invoke Cx State:
* ----------------
*/
if ((Status = AcpiProcessorSleep(sc->pr_handle, &PmTimerTicks)) != AE_OK) {
device_printf(sc->pr_dev, "AcpiProcessorSleep() failed - %s\n", acpi_strerror(Status));
/*
* Something went wrong with the sleep attempt, so give up on trying to do this.
*/
/* EVENTHANDLER_FAST_DEREGISTER(idle_event, sc->pr_idleevent);*/
device_printf(sc->pr_dev, "disabling CPU power saving\n");
return;
}
/*
* Check For State Promotion:
* --------------------------
* Only need to check for promotion on C1 and C2, and then only
* when the state has a non-zero count threshold and target state.
*/
if (CxState->PromotionPolicy.CountThreshold && CxState->PromotionPolicy.TargetState &&
((ActiveState == PR_POWER_STATE_C1) || (ActiveState == PR_POWER_STATE_C2))) {
/*
* Check the amount of time we spent in the Cx state against our
* promotion policy. If successful (asleep longer than our threshold)
* increment our count and see if a promotion is in order.
*/
if (PmTimerTicks > (CxState->PromotionPolicy.TimeThreshold)) {
CxState->PromotionPolicy.Count++;
CxState->DemotionPolicy.Count = 0;
if (CxState->PromotionPolicy.Count >= CxState->PromotionPolicy.CountThreshold)
NextState = CxState->PromotionPolicy.TargetState;
}
}
/*
* Check For State Demotion:
* -------------------------
* Only need to check for demotion on C2 and C3, and then only
* when the state has a non-zero count threshold and target state.
*/
if (CxState->DemotionPolicy.CountThreshold && CxState->DemotionPolicy.TargetState &&
((ActiveState == PR_POWER_STATE_C2) || (ActiveState == PR_POWER_STATE_C3))) {
/*
* Check the amount of time we spent in the Cx state against our
* demotion policy. If unsuccessful (asleep shorter than our threshold)
* increment our count and see if a demotion is in order.
*/
if (PmTimerTicks < (CxState->DemotionPolicy.TimeThreshold)) {
CxState->DemotionPolicy.Count++;
CxState->PromotionPolicy.Count = 0;
if (CxState->DemotionPolicy.Count >= CxState->DemotionPolicy.CountThreshold)
NextState = CxState->DemotionPolicy.TargetState;
}
}
/*
* New Cx State?
* -------------
* If so, clean up from the previous Cx state (if necessary).
*/
if (NextState != sc->pr_PowerStates.ActiveState) {
if ((Status = AcpiSetProcessorSleepState(sc->pr_handle, NextState)) != AE_OK) {
device_printf(sc->pr_dev, "AcpiSetProcessorSleepState() returned error [0x%08X]\n", Status);
} else {
CxState->PromotionPolicy.Count = 0;
CxState->DemotionPolicy.Count = 0;
sc->pr_PowerStates.ActiveState = NextState;
}
}
}

View File

@ -0,0 +1,343 @@
/*-
* 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>
/*
* 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;
/*
* 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(status);
}
#ifdef ACPI_RES_DEBUG
device_printf(dev, "got %d bytes of resources\n", buf.Length);
#endif
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:
#ifdef ACPI_RES_DEBUG
device_printf(dev, "EndTag\n");
#endif
curr = last;
break;
case FixedIo:
#ifdef ACPI_RES_DEBUG
device_printf(dev, "FixedIo 0x%x/%d\n", res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength);
#endif
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) {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Io 0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength);
#endif
set->set_ioport(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength);
} else {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Io 0x%x-0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
res->Data.Io.RangeLength);
#endif
set->set_iorange(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
res->Data.Io.RangeLength, res->Data.Io.Alignment);
}
break;
case FixedMemory32:
#ifdef ACPI_RES_DEBUG
device_printf(dev, "FixedMemory32 0x%x/%d\n", res->Data.FixedMemory32.RangeBaseAddress,
res->Data.FixedMemory32.RangeLength);
#endif
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) {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Memory32 0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
res->Data.Memory32.RangeLength);
#endif
set->set_memory(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.RangeLength);
} else {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Memory32 0x%x-0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
res->Data.Memory32.MaxBaseAddress, res->Data.Memory32.RangeLength);
#endif
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) {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Memory24 0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
res->Data.Memory24.RangeLength);
#endif
set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.RangeLength);
} else {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Memory24 0x%x-0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
res->Data.Memory24.MaxBaseAddress, res->Data.Memory24.RangeLength);
#endif
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++) {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Irq %d\n", res->Data.Irq.Interrupts[i]);
#endif
set->set_irq(dev, context, res->Data.Irq.Interrupts[i]);
}
break;
case Dma:
for (i = 0; i < res->Data.Dma.NumberOfChannels; i++) {
#ifdef ACPI_RES_DEBUG
device_printf(dev, "Drq %d\n", res->Data.Dma.Channels[i]);
#endif
set->set_drq(dev, context, res->Data.Dma.Channels[i]);
}
break;
case StartDependentFunctions:
#ifdef ACPI_RES_DEBUG
device_printf(dev, "start dependant functions");
#endif
set->set_start_dependant(dev, context, res->Data.StartDependentFunctions.CompatibilityPriority);
break;
case EndDependentFunctions:
#ifdef ACPI_RES_DEBUG
device_printf(dev, "end dependant functions");
#endif
set->set_end_dependant(dev, context);
break;
case Address32:
device_printf(dev, "unimplemented Address32 resource\n");
break;
case Address16:
device_printf(dev, "unimplemented Address16 resource\n");
break;
case ExtendedIrq:
device_printf(dev, "unimplemented ExtendedIrq resource\n");
break;
case VendorSpecific:
device_printf(dev, "unimplemented VendorSpecific resource\n");
break;
default:
break;
}
}
AcpiOsFree(buf.Pointer);
set->set_done(dev, context);
return(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;
}

View File

@ -0,0 +1,102 @@
/*-
* 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 "acpi.h"
#include <dev/acpica/acpivar.h>
#define TZ_KELVTOC(x) (((x) - 2732) / 10), (((x) - 2732) % 10)
struct acpi_tz_softc {
device_t tz_dev;
ACPI_HANDLE tz_handle;
};
static int acpi_tz_probe(device_t dev);
static int acpi_tz_attach(device_t dev);
static device_method_t acpi_tz_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, acpi_tz_probe),
DEVMETHOD(device_attach, acpi_tz_attach),
{0, 0}
};
static driver_t acpi_tz_driver = {
"acpi_tz",
acpi_tz_methods,
sizeof(struct acpi_tz_softc),
};
devclass_t acpi_tz_devclass;
DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0);
static int
acpi_tz_probe(device_t dev)
{
if (acpi_get_type(dev) == ACPI_TYPE_THERMAL) {
device_set_desc(dev, "thermal zone");
return(0);
}
return(ENXIO);
}
static int
acpi_tz_attach(device_t dev)
{
struct acpi_tz_softc *sc;
UINT32 param[4];
ACPI_BUFFER buf;
ACPI_STATUS status;
sc = device_get_softc(dev);
sc->tz_dev = dev;
sc->tz_handle = acpi_get_handle(dev);
buf.Pointer = &param[0];
buf.Length = sizeof(param);
if ((status = AcpiEvaluateObject(sc->tz_handle, "_TMP", NULL, &buf)) != AE_OK) {
device_printf(sc->tz_dev, "can't fetch temperature - %s\n", acpi_strerror(status));
return(ENXIO);
}
if (param[0] != ACPI_TYPE_NUMBER) {
device_printf(sc->tz_dev, "%s._TMP does not evaluate to ACPI_TYPE_NUMBER\n",
acpi_name(sc->tz_handle));
return(ENXIO);
}
device_printf(sc->tz_dev, "current temperature %d.%dC\n", TZ_KELVTOC(param[1]));
return(0);
}

117
sys/dev/acpica/acpi_timer.c Normal file
View File

@ -0,0 +1,117 @@
/*-
* 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 "acpi.h"
#include <dev/acpica/acpivar.h>
#define ACPITIMER_MAGIC 0x524d4954 /* "TIMR" */
struct acpi_timer_softc {
device_t tm_dev;
};
static void acpi_timer_identify(driver_t *driver, device_t parent);
static int acpi_timer_probe(device_t dev);
static int acpi_timer_attach(device_t dev);
static device_method_t acpi_timer_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, acpi_timer_identify),
DEVMETHOD(device_probe, acpi_timer_probe),
DEVMETHOD(device_attach, acpi_timer_attach),
{0, 0}
};
static driver_t acpi_timer_driver = {
"acpi_timer",
acpi_timer_methods,
sizeof(struct acpi_timer_softc),
};
devclass_t acpi_timer_devclass;
DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0);
static void
acpi_timer_identify(driver_t *driver, device_t parent)
{
static FIXED_ACPI_DESCRIPTION_TABLE facp;
ACPI_BUFFER buf;
ACPI_STATUS status;
device_t dev;
char desc[40];
buf.Pointer = &facp;
buf.Length = sizeof(facp);
if ((status = AcpiGetTable(ACPI_TABLE_FACP, 1, &buf)) != AE_OK) {
device_printf(parent, "can't locate FACP - %s\n", acpi_strerror(status));
return;
}
if (buf.Length != sizeof(facp)) {
device_printf(parent, "invalid FACP\n");
return;
}
if ((dev = BUS_ADD_CHILD(parent, 0, "acpi_timer", 0)) == NULL) {
device_printf(parent, "could not add acpi_timer0\n");
return;
}
if (acpi_set_magic(dev, ACPITIMER_MAGIC)) {
device_printf(dev, "could not set magic\n");
return;
}
sprintf(desc, "%d-bit timer at 3.579545MHz", facp.TmrValExt ? 32 : 24);
device_set_desc_copy(dev, desc);
}
static int
acpi_timer_probe(device_t dev)
{
if (acpi_get_magic(dev) == ACPITIMER_MAGIC)
return(0);
return(ENXIO);
}
static int
acpi_timer_attach(device_t dev)
{
struct acpi_timer_softc *sc;
sc = device_get_softc(dev);
sc->tm_dev = dev;
return(0);
}

33
sys/dev/acpica/acpiio.h Normal file
View File

@ -0,0 +1,33 @@
/*-
* Copyright (c) 1999 Takanori Watanabe <takawata@shidahara1.planet.sci.kobe-u.ac.jp>
* Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
* 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$
*/
#define ACPIIO_ENABLE _IO('P', 1)
#define ACPIIO_DISABLE _IO('P', 2)
#define ACPIIO_SETSLPSTATE _IOW('P', 3, int)

221
sys/dev/acpica/acpivar.h Normal file
View File

@ -0,0 +1,221 @@
/*-
* Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
* Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
* 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 "bus_if.h"
#include <sys/eventhandler.h>
extern devclass_t acpi_devclass;
struct acpi_softc {
device_t acpi_dev;
dev_t acpi_dev_t;
struct resource *acpi_irq;
int acpi_irq_rid;
void *acpi_irq_handle;
int acpi_enabled;
int acpi_sstate;
#define ACPI_POWER_BUTTON_DEFAULT_SX ACPI_STATE_S5;
#define ACPI_SLEEP_BUTTON_DEFAULT_SX ACPI_STATE_S1;
#define ACPI_LID_SWITCH_DEFAULT_SX ACPI_STATE_S1;
int acpi_power_button_sx;
int acpi_sleep_button_sx;
int acpi_lid_switch_sx;
};
struct acpi_device {
/* ACPI ivars */
ACPI_HANDLE ad_handle;
int ad_magic;
void *ad_private;
/* resources */
struct resource_list ad_rl;
};
/*
* This is a cheap and nasty way to get around the horrid counted list
* argument format that AcpiEvalateMethod uses.
*/
#define ACPI_OBJECTLIST_MAX 16
struct acpi_object_list {
UINT32 count;
ACPI_OBJECT *pointer[ACPI_OBJECTLIST_MAX];
ACPI_OBJECT object[ACPI_OBJECTLIST_MAX];
};
static __inline struct acpi_object_list *
acpi_AllocObjectList(int nobj) {
struct acpi_object_list *l;
int i;
if (nobj > ACPI_OBJECTLIST_MAX)
return(NULL);
if ((l = AcpiOsAllocate(sizeof(*l))) == NULL)
return(NULL);
bzero(l, sizeof(*l));
for (i = 0; i < ACPI_OBJECTLIST_MAX; i++)
l->pointer[i] = &l->object[i];
l->count = nobj;
return(l);
}
#define ACPI_IVAR_HANDLE 0x100
#define ACPI_IVAR_MAGIC 0x101
#define ACPI_IVAR_PRIVATE 0x102
static __inline ACPI_HANDLE
acpi_get_handle(device_t dev) {
ACPI_HANDLE h;
if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, (uintptr_t *)&h))
return(NULL);
return(h);
}
static __inline int
acpi_set_handle(device_t dev, ACPI_HANDLE h) {
return(BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, (uintptr_t)h));
}
static __inline int
acpi_get_magic(device_t dev) {
int m;
if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, (uintptr_t *)&m))
return(0);
return(m);
}
static __inline int
acpi_set_magic(device_t dev, int m) {
return(BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, (uintptr_t)m));
}
static __inline void *
acpi_get_private(device_t dev) {
void *p;
if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, (uintptr_t *)&p))
return(NULL);
return(p);
}
static __inline int
acpi_set_private(device_t dev, void *p) {
return(BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, (uintptr_t)p));
}
static __inline ACPI_OBJECT_TYPE
acpi_get_type(device_t dev) {
ACPI_HANDLE h;
ACPI_OBJECT_TYPE t;
if ((h = acpi_get_handle(dev)) == NULL)
return(ACPI_TYPE_NOT_FOUND);
if (AcpiGetType(h, &t) != AE_OK)
return(ACPI_TYPE_NOT_FOUND);
return(t);
}
#ifdef ENABLE_DEBUGGER
extern void acpi_EnterDebugger(void);
#endif
extern BOOLEAN acpi_MatchHid(device_t dev, char *hid);
extern ACPI_STATUS acpi_GetIntoBuffer(ACPI_HANDLE handle,
ACPI_STATUS (*func)(ACPI_HANDLE, ACPI_BUFFER *),
ACPI_BUFFER *buf);
extern ACPI_BUFFER *acpi_AllocBuffer(int size);
extern ACPI_STATUS acpi_SetSleepState(struct acpi_softc *sc, int state);
extern ACPI_STATUS acpi_Enable(struct acpi_softc *sc);
extern ACPI_STATUS acpi_Disable(struct acpi_softc *sc);
extern BOOLEAN acpi_DeviceIsPresent(device_t dev);
extern ACPI_STATUS acpi_EvaluateNumber(ACPI_HANDLE handle, char *path, int *number);
struct acpi_parse_resource_set {
void (* set_init)(device_t dev, void **context);
void (* set_done)(device_t dev, void *context);
void (* set_ioport)(device_t dev, void *context, u_int32_t base, u_int32_t length);
void (* set_iorange)(device_t dev, void *context, u_int32_t low, u_int32_t high,
u_int32_t length, u_int32_t align);
void (* set_memory)(device_t dev, void *context, u_int32_t base, u_int32_t length);
void (* set_memoryrange)(device_t dev, void *context, u_int32_t low, u_int32_t high,
u_int32_t length, u_int32_t align);
void (* set_irq)(device_t dev, void *context, u_int32_t irq);
void (* set_drq)(device_t dev, void *context, u_int32_t drq);
void (* set_start_dependant)(device_t dev, void *context, int preference);
void (* set_end_dependant)(device_t dev, void *context);
};
extern struct acpi_parse_resource_set acpi_res_parse_set;
extern ACPI_STATUS acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
struct acpi_parse_resource_set *set);
/* XXX this is ugly */
extern char *acpi_strerror(ACPI_STATUS excep);
/*
* ACPI event handling
*/
extern UINT32 acpi_eventhandler_power_button_for_sleep(void *context);
extern UINT32 acpi_eventhandler_power_button_for_wakeup(void *context);
extern UINT32 acpi_eventhandler_sleep_button_for_sleep(void *context);
extern UINT32 acpi_eventhandler_sleep_button_for_wakeup(void *context);
#define ACPI_EVENT_PRI_FIRST 0
#define ACPI_EVENT_PRI_DEFAULT 10000
#define ACPI_EVENT_PRI_LAST 20000
typedef void (*acpi_event_handler_t) __P((void *, int));
EVENTHANDLER_DECLARE(acpi_sleep_event, acpi_event_handler_t);
EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t);
/*
* Misc.
*/
static __inline struct acpi_softc *
acpi_device_get_parent_softc(device_t child)
{
device_t parent;
parent = device_get_parent(child);
if (parent == NULL) {
return(NULL);
}
return(device_get_softc(parent));
}
extern char *acpi_name(ACPI_HANDLE handle);
extern int acpi_avoid(ACPI_HANDLE handle);