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:
parent
fd660059d9
commit
15e32d5d03
1124
sys/dev/acpica/acpi.c
Normal file
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
159
sys/dev/acpica/acpi_apic.c
Normal 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);
|
||||
}
|
182
sys/dev/acpica/acpi_button.c
Normal file
182
sys/dev/acpica/acpi_button.c
Normal 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
710
sys/dev/acpica/acpi_ec.c
Normal 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
196
sys/dev/acpica/acpi_ecreg.h
Normal 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
442
sys/dev/acpica/acpi_isa.c
Normal 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
152
sys/dev/acpica/acpi_lid.c
Normal 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
236
sys/dev/acpica/acpi_pcib.c
Normal 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 */
|
||||
}
|
236
sys/dev/acpica/acpi_pcib_acpi.c
Normal file
236
sys/dev/acpica/acpi_pcib_acpi.c
Normal 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 */
|
||||
}
|
640
sys/dev/acpica/acpi_processor.c
Normal file
640
sys/dev/acpica/acpi_processor.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
343
sys/dev/acpica/acpi_resource.c
Normal file
343
sys/dev/acpica/acpi_resource.c
Normal 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;
|
||||
}
|
102
sys/dev/acpica/acpi_thermal.c
Normal file
102
sys/dev/acpica/acpi_thermal.c
Normal 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 = ¶m[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
117
sys/dev/acpica/acpi_timer.c
Normal 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
33
sys/dev/acpica/acpiio.h
Normal 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
221
sys/dev/acpica/acpivar.h
Normal 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);
|
||||
|
Loading…
Reference in New Issue
Block a user