More updates to the ACPI code:
- Move all register I/O into acpi_io.c - Move event handling into acpi_event.c - Reorganise headers into acpivar/acpireg/acpiio - Move find-RSDT and find-ACPI-owned-memory into acpi_machdep - Allocate all resources (except those detailed only by AML) as real resources. Add infrastructure that will make adding resource support to AML code easy. - Remove all ACPI #ifdefs in non-ACPI code - Removed unnecessary includes - Minor style and commenting fixes Reviewed by: iwasaki
This commit is contained in:
parent
8cc643d7ff
commit
43b494595e
@ -31,7 +31,6 @@
|
||||
* Code for dealing with the BIOS in x86 PC systems.
|
||||
*/
|
||||
|
||||
#include "acpi.h"
|
||||
#include "isa.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -50,10 +49,6 @@
|
||||
#include <isa/pnpreg.h>
|
||||
#include <isa/pnpvar.h>
|
||||
|
||||
#if NACPI > 0
|
||||
#include <sys/acpi.h>
|
||||
#endif
|
||||
|
||||
#define BIOS_START 0xe0000
|
||||
#define BIOS_SIZE 0x20000
|
||||
|
||||
@ -148,26 +143,6 @@ bios32_init(void *junk)
|
||||
printf("pnpbios: Bad PnP BIOS data checksum\n");
|
||||
}
|
||||
}
|
||||
#if NACPI > 0
|
||||
/*
|
||||
* ACPI BIOS
|
||||
* acpi_rsdp is GLOBAL and holds RSD PTR signature
|
||||
*/
|
||||
if ((sigaddr = bios_sigsearch(0, "RSD PTR ", 8, 16, 0)) != 0) {
|
||||
/* get a virtual pointer to the structure */
|
||||
acpi_rsdp = (struct ACPIrsdp *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
|
||||
for (cv = (u_int8_t *)acpi_rsdp, ck = 0, i = 0; i < sizeof(struct ACPIrsdp); i++) {
|
||||
ck += cv[i];
|
||||
}
|
||||
|
||||
/* If checksum is NG, disable it */
|
||||
if (ck != 0) {
|
||||
printf("ACPI: Bad ACPI BIOS data checksum\n");
|
||||
acpi_rsdp=NULL;/* 0xa0000<=RSD_PTR<0x100000*/
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bootverbose) {
|
||||
/* look for other know signatures */
|
||||
printf("Other BIOS signatures found:\n");
|
||||
|
@ -37,7 +37,6 @@
|
||||
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include "acpi.h"
|
||||
#include "apm.h"
|
||||
#include "npx.h"
|
||||
#include "opt_atalk.h"
|
||||
@ -100,6 +99,7 @@
|
||||
#include <machine/ipl.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/mutex.h>
|
||||
#include <machine/pc/bios.h>
|
||||
#include <machine/pcb_ext.h> /* pcb.h included via sys/user.h */
|
||||
#include <machine/globaldata.h>
|
||||
#include <machine/globals.h>
|
||||
@ -120,10 +120,6 @@
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/sigframe.h>
|
||||
|
||||
#if NACPI > 0
|
||||
#include <sys/acpi.h>
|
||||
#endif
|
||||
|
||||
extern void init386 __P((int first));
|
||||
extern void dblfault_handler __P((void));
|
||||
|
||||
@ -1457,11 +1453,7 @@ getmemsize(int first)
|
||||
vm_offset_t pa, physmap[PHYSMAP_SIZE];
|
||||
pt_entry_t pte;
|
||||
const char *cp;
|
||||
struct {
|
||||
u_int64_t base;
|
||||
u_int64_t length;
|
||||
u_int32_t type;
|
||||
} *smap;
|
||||
struct bios_smap *smap;
|
||||
|
||||
bzero(&vmf, sizeof(struct vm86frame));
|
||||
bzero(physmap, sizeof(physmap));
|
||||
@ -1521,22 +1513,16 @@ getmemsize(int first)
|
||||
/*
|
||||
* get memory map with INT 15:E820
|
||||
*/
|
||||
#define SMAPSIZ sizeof(*smap)
|
||||
#define SMAP_SIG 0x534D4150 /* 'SMAP' */
|
||||
|
||||
vmc.npages = 0;
|
||||
smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT));
|
||||
vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di);
|
||||
|
||||
#if NACPI > 0
|
||||
acpi_init_addr_range();
|
||||
#endif
|
||||
physmap_idx = 0;
|
||||
vmf.vmf_ebx = 0;
|
||||
do {
|
||||
vmf.vmf_eax = 0xE820;
|
||||
vmf.vmf_edx = SMAP_SIG;
|
||||
vmf.vmf_ecx = SMAPSIZ;
|
||||
vmf.vmf_ecx = sizeof(struct bios_smap);
|
||||
i = vm86_datacall(0x15, &vmf, &vmc);
|
||||
if (i || vmf.vmf_eax != SMAP_SIG)
|
||||
break;
|
||||
@ -1547,13 +1533,7 @@ getmemsize(int first)
|
||||
(u_int32_t)smap->base,
|
||||
*(u_int32_t *)((char *)&smap->length + 4),
|
||||
(u_int32_t)smap->length);
|
||||
#if NACPI > 0
|
||||
/* Save ACPI related memory Info */
|
||||
if (smap->type == 0x03 || smap->type == 0x04) {
|
||||
acpi_register_addr_range(smap->base,
|
||||
smap->length, smap->type);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (smap->type != 0x01)
|
||||
goto next_run;
|
||||
|
||||
|
@ -218,3 +218,16 @@ extern int bios16(struct bios_args *, char *, ...);
|
||||
extern int bios16_call(struct bios_regs *, char *);
|
||||
extern int bios32(struct bios_regs *, u_int, u_short);
|
||||
extern void set_bios_selectors(struct bios_segments *, int);
|
||||
|
||||
/*
|
||||
* Int 15:E820 'SMAP' structure
|
||||
*
|
||||
* XXX add constants for type
|
||||
*/
|
||||
#define SMAP_SIG 0x534D4150 /* 'SMAP' */
|
||||
struct bios_smap {
|
||||
u_int64_t base;
|
||||
u_int64_t length;
|
||||
u_int32_t type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
@ -75,7 +75,9 @@ dev/aac/aac.c optional aac
|
||||
#dev/aac/aac_debug.c optional aac
|
||||
dev/aac/aac_disk.c optional aac
|
||||
dev/aac/aac_pci.c optional aac pci
|
||||
dev/acpi/acpi.c count acpi
|
||||
dev/acpi/acpi.c optional acpi
|
||||
dev/acpi/acpi_io.c optional acpi
|
||||
dev/acpi/acpi_event.c optional acpi
|
||||
dev/acpi/acpi_powerres.c optional acpi
|
||||
dev/acpi/aml/aml_amlmem.c optional acpi
|
||||
dev/acpi/aml/aml_common.c optional acpi
|
||||
|
1101
sys/dev/acpi/acpi.c
1101
sys/dev/acpi/acpi.c
File diff suppressed because it is too large
Load Diff
418
sys/dev/acpi/acpi_event.c
Normal file
418
sys/dev/acpi/acpi_event.c
Normal file
@ -0,0 +1,418 @@
|
||||
/*-
|
||||
* Copyright (c) 1999 Takanori Watanabe <takawata@shidahara1.planet.sci.kobe-u.ac.jp>
|
||||
* Copyright (c) 1999, 2000 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$
|
||||
*/
|
||||
|
||||
#include "opt_acpi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#include <dev/acpi/acpivar.h>
|
||||
|
||||
#include <dev/acpi/aml/aml_env.h>
|
||||
#include <dev/acpi/aml/aml_evalobj.h>
|
||||
|
||||
/*
|
||||
* ACPI events
|
||||
*/
|
||||
static void acpi_process_event(acpi_softc_t *sc, u_int32_t status_e,
|
||||
u_int32_t status_0, u_int32_t status_1);
|
||||
|
||||
/*
|
||||
* ACPI events
|
||||
*/
|
||||
|
||||
static void
|
||||
acpi_process_event(acpi_softc_t *sc, u_int32_t status_e,
|
||||
u_int32_t status_0, u_int32_t status_1)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (status_e & ACPI_PM1_PWRBTN_EN) {
|
||||
if (sc->ignore_events & ACPI_PM1_PWRBTN_EN) {
|
||||
ACPI_DEBUGPRINT("PWRBTN event ingnored\n");
|
||||
} else {
|
||||
#if 1
|
||||
acpi_set_sleeping_state(sc, ACPI_S_STATE_S5);
|
||||
#else
|
||||
/*
|
||||
* If there is ACPI userland daemon,
|
||||
* this event should be passed to it
|
||||
* so that the user can determine power policy.
|
||||
*/
|
||||
acpi_queue_event(sc, ACPI_EVENT_TYPE_FIXEDREG, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (status_e & ACPI_PM1_SLPBTN_EN) {
|
||||
if (sc->ignore_events & ACPI_PM1_SLPBTN_EN) {
|
||||
ACPI_DEBUGPRINT("SLPBTN event ingnored\n");
|
||||
} else {
|
||||
#if 1
|
||||
acpi_set_sleeping_state(sc, ACPI_S_STATE_S1);
|
||||
#else
|
||||
acpi_queue_event(sc, ACPI_EVENT_TYPE_FIXEDREG, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
for(i = 0; i < sc->facp_body->gpe0_len * 4; i++)
|
||||
if((status_0 & (1 << i)) && (sc->gpe0_mask & (1 << i)))
|
||||
acpi_queue_event(sc, ACPI_EVENT_TYPE_GPEREG, i);
|
||||
for(i = 0; i < sc->facp_body->gpe1_len * 4 ; i++)
|
||||
if((status_1 & (1 << i)) && (sc->gpe1_mask & (1 << i)))
|
||||
acpi_queue_event(sc, ACPI_EVENT_TYPE_GPEREG,
|
||||
i + sc->facp_body->gpe1_base);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_intr(void *data)
|
||||
{
|
||||
u_int32_t enable;
|
||||
u_int32_t status_e, status_0, status_1;
|
||||
u_int32_t val;
|
||||
int debug;
|
||||
acpi_softc_t *sc;
|
||||
|
||||
sc = (acpi_softc_t *)data;
|
||||
debug = acpi_debug; /* Save debug level */
|
||||
acpi_debug = 0; /* Shut up */
|
||||
|
||||
/*
|
||||
* Power Management 1 Status Registers
|
||||
*/
|
||||
status_e = enable = 0;
|
||||
acpi_io_pm1_status(sc, ACPI_REGISTER_INPUT, &status_e);
|
||||
|
||||
/*
|
||||
* Get current interrupt mask
|
||||
*/
|
||||
acpi_io_pm1_enable(sc, ACPI_REGISTER_INPUT, &enable);
|
||||
|
||||
/*
|
||||
* Disable events and re-enable again
|
||||
*/
|
||||
if ((status_e & enable) != 0) {
|
||||
acpi_debug = debug; /* OK, you can speak */
|
||||
|
||||
ACPI_DEBUGPRINT("pm1_status intr CALLED\n");
|
||||
|
||||
/* Disable all interrupt generation */
|
||||
val = enable & (~ACPI_PM1_ALL_ENABLE_BITS);
|
||||
acpi_io_pm1_enable(sc, ACPI_REGISTER_OUTPUT, &val);
|
||||
|
||||
/* Clear interrupt status */
|
||||
val = enable & ACPI_PM1_ALL_ENABLE_BITS;
|
||||
acpi_io_pm1_status(sc, ACPI_REGISTER_OUTPUT, &val);
|
||||
|
||||
/* Re-enable interrupt */
|
||||
acpi_io_pm1_enable(sc, ACPI_REGISTER_OUTPUT, &enable);
|
||||
|
||||
acpi_debug = 0; /* Shut up again */
|
||||
}
|
||||
|
||||
/*
|
||||
* General-Purpose Events 0 Status Registers
|
||||
*/
|
||||
status_0 = enable = 0;
|
||||
acpi_io_gpe0_status(sc, ACPI_REGISTER_INPUT, &status_0);
|
||||
|
||||
/*
|
||||
* Get current interrupt mask
|
||||
*/
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_INPUT, &enable);
|
||||
|
||||
/*
|
||||
* Disable events and re-enable again
|
||||
*/
|
||||
if ((status_0 & enable) != 0) {
|
||||
acpi_debug = debug; /* OK, you can speak */
|
||||
|
||||
ACPI_DEBUGPRINT("gpe0_status intr CALLED\n");
|
||||
|
||||
/* Disable all interrupt generation */
|
||||
val = enable & ~status_0;
|
||||
#if 0
|
||||
/* or should we disable all? */
|
||||
val = 0x0;
|
||||
#endif
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_OUTPUT, &val);
|
||||
#if 0
|
||||
/* Clear interrupt status */
|
||||
val = enable; /* XXX */
|
||||
acpi_io_gpe0_status(sc, ACPI_REGISTER_OUTPUT, &val);
|
||||
|
||||
/* Re-enable interrupt */
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_OUTPUT, &enable);
|
||||
|
||||
acpi_debug = 0; /* Shut up again */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* General-Purpose Events 1 Status Registers
|
||||
*/
|
||||
status_1 = enable = 0;
|
||||
acpi_io_gpe1_status(sc, ACPI_REGISTER_INPUT, &status_1);
|
||||
|
||||
/*
|
||||
Get current interrupt mask
|
||||
*/
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_INPUT, &enable);
|
||||
|
||||
/*
|
||||
* Disable events and re-enable again
|
||||
*/
|
||||
if ((status_1 & enable) != 0) {
|
||||
acpi_debug = debug; /* OK, you can speak */
|
||||
|
||||
ACPI_DEBUGPRINT("gpe1_status intr CALLED\n");
|
||||
|
||||
/* Disable all interrupt generation */
|
||||
val = enable & ~status_1;
|
||||
#if 0
|
||||
/* or should we disable all? */
|
||||
val = 0x0;
|
||||
#endif
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_OUTPUT, &val);
|
||||
|
||||
/* Clear interrupt status */
|
||||
val = enable; /* XXX */
|
||||
acpi_io_gpe1_status(sc, ACPI_REGISTER_OUTPUT, &val);
|
||||
|
||||
/* Re-enable interrupt */
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_OUTPUT, &enable);
|
||||
|
||||
acpi_debug = 0; /* Shut up again */
|
||||
}
|
||||
|
||||
acpi_debug = debug; /* Restore debug level */
|
||||
|
||||
/* do something to handle the events... */
|
||||
acpi_process_event(sc, status_e, status_0, status_1);
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_set_gpe_bits(struct aml_name *name, va_list ap)
|
||||
{
|
||||
struct acpi_softc *sc = va_arg(ap, struct acpi_softc *);
|
||||
int *gpemask0 = va_arg(ap, int *);
|
||||
int *gpemask1 = va_arg(ap, int *);
|
||||
int gpenum;
|
||||
|
||||
#define XDIGITTONUM(c) ((isdigit(c)) ? ((c) - '0') : ('A' <= (c)&& (c) <= 'F') ? ((c) - 'A' + 10) : 0)
|
||||
|
||||
if (isxdigit(name->name[2]) && isxdigit(name->name[3])) {
|
||||
gpenum = XDIGITTONUM(name->name[2]) * 16 +
|
||||
XDIGITTONUM(name->name[3]);
|
||||
ACPI_DEBUGPRINT("GPENUM %d %d \n", gpenum, sc->facp_body->gpe0_len * 4);
|
||||
if (gpenum < (sc->facp_body->gpe0_len * 4)) {
|
||||
*gpemask0 |= (1 << gpenum);
|
||||
} else {
|
||||
*gpemask1 |= (1 << (gpenum - sc->facp_body->gpe1_base));
|
||||
}
|
||||
}
|
||||
ACPI_DEBUGPRINT("GPEMASK %x %x\n", *gpemask0, *gpemask1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
acpi_enable_events(acpi_softc_t *sc)
|
||||
{
|
||||
u_int32_t status;
|
||||
u_int32_t mask0, mask1;
|
||||
u_int32_t flags;
|
||||
|
||||
/*
|
||||
* Setup PM1 Enable Registers Fixed Feature Enable Bits (4.7.3.1.2)
|
||||
* based on flags field of Fixed ACPI Description Table (5.2.5).
|
||||
*/
|
||||
acpi_io_pm1_enable(sc, ACPI_REGISTER_INPUT, &status);
|
||||
flags = sc->facp_body->flags;
|
||||
if ((flags & ACPI_FACP_FLAG_PWR_BUTTON) == 0) {
|
||||
status |= ACPI_PM1_PWRBTN_EN;
|
||||
}
|
||||
if ((flags & ACPI_FACP_FLAG_SLP_BUTTON) == 0) {
|
||||
status |= ACPI_PM1_SLPBTN_EN;
|
||||
}
|
||||
acpi_io_pm1_enable(sc, ACPI_REGISTER_OUTPUT, &status);
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* XXX
|
||||
* This should be done based on level event handlers in
|
||||
* \_GPE scope (4.7.2.2.1.2).
|
||||
*/
|
||||
|
||||
mask0 = mask1 = 0;
|
||||
aml_apply_foreach_found_objects(NULL, "\\_GPE._L", acpi_set_gpe_bits,
|
||||
sc, &mask0, &mask1); /* XXX correct? */
|
||||
sc->gpe0_mask = mask0;
|
||||
sc->gpe1_mask = mask1;
|
||||
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_OUTPUT, &mask0);
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_OUTPUT, &mask1);
|
||||
#endif
|
||||
|
||||
/* print all event status for debugging */
|
||||
acpi_io_pm1_status(sc, ACPI_REGISTER_INPUT, &status);
|
||||
acpi_io_pm1_enable(sc, ACPI_REGISTER_INPUT, &status);
|
||||
acpi_io_gpe0_status(sc, ACPI_REGISTER_INPUT, &status);
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_INPUT, &status);
|
||||
acpi_io_gpe1_status(sc, ACPI_REGISTER_INPUT, &status);
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_INPUT, &status);
|
||||
acpi_io_pm1_control(sc, ACPI_REGISTER_INPUT, &mask0, &mask1);
|
||||
acpi_io_pm2_control(sc, ACPI_REGISTER_INPUT, &status);
|
||||
acpi_io_pm_timer(sc, ACPI_REGISTER_INPUT, &status);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_clear_ignore_events(void *arg)
|
||||
{
|
||||
((acpi_softc_t *)arg)->ignore_events = 0;
|
||||
ACPI_DEBUGPRINT("ignore events cleared\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Transition the rest of the system through state changes.
|
||||
*/
|
||||
int
|
||||
acpi_send_pm_event(acpi_softc_t *sc, u_int8_t state)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = 0;
|
||||
switch (state) {
|
||||
case ACPI_S_STATE_S0:
|
||||
if (sc->system_state != ACPI_S_STATE_S0) {
|
||||
DEVICE_RESUME(root_bus);
|
||||
}
|
||||
break;
|
||||
case ACPI_S_STATE_S1:
|
||||
case ACPI_S_STATE_S2:
|
||||
case ACPI_S_STATE_S3:
|
||||
case ACPI_S_STATE_S4:
|
||||
error = DEVICE_SUSPEND(root_bus);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Event-handler thread.
|
||||
*/
|
||||
void
|
||||
acpi_queue_event(acpi_softc_t *sc, int type, int arg)
|
||||
{
|
||||
struct acpi_event *ae;
|
||||
int s;
|
||||
|
||||
ae = malloc(sizeof(*ae), M_TEMP, M_NOWAIT);
|
||||
if(ae == NULL)
|
||||
panic("acpi_queue_event: can't allocate event");
|
||||
|
||||
ae->ae_type = type;
|
||||
ae->ae_arg = arg;
|
||||
s = splhigh();
|
||||
STAILQ_INSERT_TAIL(&sc->event, ae, ae_q);
|
||||
splx(s);
|
||||
wakeup(&sc->event);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_event_thread(void *arg)
|
||||
{
|
||||
acpi_softc_t *sc = arg;
|
||||
int s , gpe1_base = sc->facp_body->gpe1_base;
|
||||
u_int32_t status,bit;
|
||||
struct acpi_event *ae;
|
||||
const char numconv[] = {'0','1','2','3','4','5','6','7',
|
||||
'8','9','A','B','C','D','E','F',-1};
|
||||
char gpemethod[] = "\\_GPE._LXX";
|
||||
union aml_object argv; /* Dummy*/
|
||||
|
||||
while(1) {
|
||||
s = splhigh();
|
||||
if ((ae = STAILQ_FIRST(&sc->event)) == NULL) {
|
||||
splx(s);
|
||||
tsleep(&sc->event, PWAIT, "acpiev", 0);
|
||||
continue;
|
||||
} else {
|
||||
splx(s);
|
||||
}
|
||||
s = splhigh();
|
||||
STAILQ_REMOVE_HEAD_UNTIL(&sc->event, ae, ae_q);
|
||||
splx(s);
|
||||
switch(ae->ae_type) {
|
||||
case ACPI_EVENT_TYPE_GPEREG:
|
||||
sprintf(gpemethod, "\\_GPE._L%c%c",
|
||||
numconv[(ae->ae_arg / 0x10) & 0xf],
|
||||
numconv[ae->ae_arg & 0xf]);
|
||||
aml_invoke_method_by_name(gpemethod, 0, &argv);
|
||||
sprintf(gpemethod, "\\_GPE._E%c%c",
|
||||
numconv[(ae->ae_arg / 0x10) & 0xf],
|
||||
numconv[ae->ae_arg & 0xf]);
|
||||
aml_invoke_method_by_name(gpemethod, 0, &argv);
|
||||
s=splhigh();
|
||||
if((ae->ae_arg < gpe1_base) || (gpe1_base == 0)){
|
||||
bit = 1 << ae->ae_arg;
|
||||
ACPI_DEBUGPRINT("GPE0%x\n", bit);
|
||||
acpi_io_gpe0_status(sc, ACPI_REGISTER_OUTPUT,
|
||||
&bit);
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_INPUT,
|
||||
&status);
|
||||
ACPI_DEBUGPRINT("GPE0%x\n", status);
|
||||
status |= bit;
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_OUTPUT,
|
||||
&status);
|
||||
} else {
|
||||
bit = 1 << (ae->ae_arg - sc->facp_body->gpe1_base);
|
||||
acpi_io_gpe1_status(sc, ACPI_REGISTER_OUTPUT,
|
||||
&bit);
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_INPUT,
|
||||
&status);
|
||||
status |= bit;
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_OUTPUT,
|
||||
&status);
|
||||
}
|
||||
splx(s);
|
||||
break;
|
||||
}
|
||||
free(ae, M_TEMP);
|
||||
}
|
||||
ACPI_DEVPRINTF("????\n");
|
||||
}
|
356
sys/dev/acpi/acpi_io.c
Normal file
356
sys/dev/acpi/acpi_io.c
Normal file
@ -0,0 +1,356 @@
|
||||
/*-
|
||||
* Copyright (c) 1999 Takanori Watanabe <takawata@shidahara1.planet.sci.kobe-u.ac.jp>
|
||||
* Copyright (c) 1999, 2000 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$
|
||||
*/
|
||||
|
||||
#include "opt_acpi.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#include <dev/acpi/acpivar.h>
|
||||
|
||||
/*
|
||||
* ACPI Register I/O
|
||||
*/
|
||||
static __inline void
|
||||
acpi_register_input(acpi_softc_t *sc, int res, int offset, u_int32_t *value, u_int32_t size)
|
||||
{
|
||||
bus_space_tag_t bst;
|
||||
bus_space_handle_t bsh;
|
||||
u_int32_t val;
|
||||
|
||||
if (sc->iores[res].rsc == NULL)
|
||||
return;
|
||||
|
||||
bst = sc->iores[res].btag;
|
||||
bsh = sc->iores[res].bhandle;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
val = bus_space_read_1(bst, bsh, offset);
|
||||
break;
|
||||
case 2:
|
||||
val = bus_space_read_2(bst, bsh, offset);
|
||||
break;
|
||||
case 3:
|
||||
val = bus_space_read_4(bst, bsh, offset);
|
||||
val &= 0x00ffffff;
|
||||
break;
|
||||
case 4:
|
||||
val = bus_space_read_4(bst, bsh, offset);
|
||||
break;
|
||||
default:
|
||||
ACPI_DEVPRINTF("acpi_register_input(): invalid size (%d)\n", size);
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*value = val;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
acpi_register_output(acpi_softc_t *sc, int res, int offset, u_int32_t *value, u_int32_t size)
|
||||
{
|
||||
bus_space_tag_t bst;
|
||||
bus_space_handle_t bsh;
|
||||
u_int32_t val;
|
||||
|
||||
if (sc->iores[res].rsc == NULL)
|
||||
return;
|
||||
|
||||
val = *value;
|
||||
bst = sc->iores[res].btag;
|
||||
bsh = sc->iores[res].bhandle;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
bus_space_write_1(bst, bsh, offset, val & 0xff);
|
||||
break;
|
||||
case 2:
|
||||
bus_space_write_2(bst, bsh, offset, val & 0xffff);
|
||||
break;
|
||||
case 3:
|
||||
bus_space_write_2(bst, bsh, offset, val & 0xffff);
|
||||
bus_space_write_1(bst, bsh, offset + 2, (val >> 16) & 0xff);
|
||||
break;
|
||||
case 4:
|
||||
bus_space_write_4(bst, bsh, offset, val);
|
||||
break;
|
||||
default:
|
||||
ACPI_DEVPRINTF("acpi_register_output(): invalid size\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void
|
||||
acpi_io_mirreg(acpi_softc_t *sc, boolean_t io, u_int32_t *data,
|
||||
int res, int altres, int offset, int size)
|
||||
{
|
||||
u_int32_t result;
|
||||
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, res, offset, &result, size);
|
||||
*data = result;
|
||||
acpi_register_input(sc, altres, offset, &result, size);
|
||||
*data |= result;
|
||||
} else {
|
||||
acpi_register_output(sc, res, offset, data, size);
|
||||
acpi_register_output(sc, altres, offset, data, size);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
acpi_enable_disable(acpi_softc_t *sc, boolean_t enable)
|
||||
{
|
||||
u_int8_t val;
|
||||
|
||||
val = enable ? sc->facp_body->acpi_enable : sc->facp_body->acpi_disable;
|
||||
bus_space_write_1(sc->iores[ACPI_RES_SMI_CMD].btag,
|
||||
sc->iores[ACPI_RES_SMI_CMD].bhandle,
|
||||
0, val);
|
||||
sc->enabled = enable;
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_enable_disable(%d) = (%x)\n", enable, val);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_pm1_status(acpi_softc_t *sc, boolean_t io, u_int32_t *status)
|
||||
{
|
||||
int size;
|
||||
struct FACPbody *facp;
|
||||
|
||||
facp = sc->facp_body;
|
||||
size = facp->pm1_evt_len / 2;
|
||||
acpi_io_mirreg(sc, io, status, ACPI_RES_PM1A_EVT, ACPI_RES_PM1B_EVT, 0, size);
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_pm1_status(%d) = (%x)\n", io, *status);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_pm1_enable(acpi_softc_t *sc, boolean_t io, u_int32_t *enable)
|
||||
{
|
||||
int size;
|
||||
struct FACPbody *facp;
|
||||
|
||||
facp = sc->facp_body;
|
||||
size = facp->pm1_evt_len / 2;
|
||||
acpi_io_mirreg(sc, io, enable, ACPI_RES_PM1A_EVT, ACPI_RES_PM1B_EVT, size, size);
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_pm1_enable(%d) = (%x)\n", io, *enable);
|
||||
}
|
||||
|
||||
/*
|
||||
* PM1 is awkward because the SLP_TYP bits are not common between the two registers.
|
||||
* A better interface than this might pass the SLP_TYP bits separately.
|
||||
*/
|
||||
void
|
||||
acpi_io_pm1_control(acpi_softc_t *sc, boolean_t io, u_int32_t *value_a, u_int32_t *value_b)
|
||||
{
|
||||
struct FACPbody *facp;
|
||||
u_int32_t result;
|
||||
|
||||
facp = sc->facp_body;
|
||||
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, ACPI_RES_PM1A_CNT, 0, &result, facp->pm1_cnt_len);
|
||||
*value_a = result;
|
||||
acpi_register_input(sc, ACPI_RES_PM1B_CNT, 0, &result, facp->pm1_cnt_len);
|
||||
*value_a |= result;
|
||||
*value_a &= ~ACPI_CNT_SLP_TYPX; /* mask the SLP_TYP bits */
|
||||
} else {
|
||||
acpi_register_output(sc, ACPI_RES_PM1A_CNT, 0, value_a, facp->pm1_cnt_len);
|
||||
acpi_register_output(sc, ACPI_RES_PM1B_CNT, 0, value_b, facp->pm1_cnt_len);
|
||||
}
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_pm1_control(%d) = (%x, %x)\n", io, *value_a, *value_b);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_pm2_control(acpi_softc_t *sc, boolean_t io, u_int32_t *val)
|
||||
{
|
||||
int size;
|
||||
struct FACPbody *facp;
|
||||
|
||||
facp = sc->facp_body;
|
||||
size = facp->pm2_cnt_len;
|
||||
|
||||
if (size == 0) /* port is optional */
|
||||
return;
|
||||
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, ACPI_RES_PM2_CNT, 0, val, size);
|
||||
} else {
|
||||
acpi_register_output(sc, ACPI_RES_PM2_CNT, 0, val, size);
|
||||
}
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_pm2_control(%d) = (%x)\n", io, *val);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_pm_timer(acpi_softc_t *sc, boolean_t io, u_int32_t *val)
|
||||
{
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, ACPI_RES_PM_TMR, 0, val, sizeof(u_int32_t));
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_pm_timer(%d) = (%x)\n", io, *val);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_gpe0_status(acpi_softc_t *sc, boolean_t io, u_int32_t *val)
|
||||
{
|
||||
int size;
|
||||
struct FACPbody *facp;
|
||||
|
||||
facp = sc->facp_body;
|
||||
size = facp->gpe0_len / 2;
|
||||
|
||||
if (size == 0) /* port is optional */
|
||||
return;
|
||||
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, ACPI_RES_GPE0, 0, val, size);
|
||||
} else {
|
||||
acpi_register_output(sc, ACPI_RES_GPE0, 0, val, size);
|
||||
}
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_gpe0_status(%d) = (%x)\n", io, *val);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_gpe0_enable(acpi_softc_t *sc, boolean_t io, u_int32_t *val)
|
||||
{
|
||||
int size;
|
||||
struct FACPbody *facp;
|
||||
|
||||
facp = sc->facp_body;
|
||||
size = facp->gpe0_len / 2;
|
||||
|
||||
if (size == 0) /* port is optional */
|
||||
return;
|
||||
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, ACPI_RES_GPE0, size, val, size);
|
||||
} else {
|
||||
acpi_register_output(sc, ACPI_RES_GPE0, size, val, size);
|
||||
}
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_gpe0_enable(%d) = (%x)\n", io, *val);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_gpe1_status(acpi_softc_t *sc, boolean_t io, u_int32_t *val)
|
||||
{
|
||||
int size;
|
||||
struct FACPbody *facp;
|
||||
|
||||
facp = sc->facp_body;
|
||||
size = facp->gpe1_len / 2;
|
||||
|
||||
if (size == 0) /* port is optional */
|
||||
return;
|
||||
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, ACPI_RES_GPE1, 0, val, size);
|
||||
} else {
|
||||
acpi_register_output(sc, ACPI_RES_GPE1, 0, val, size);
|
||||
}
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_gpe1_status(%d) = (%x)\n", io, *val);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_io_gpe1_enable(acpi_softc_t *sc, boolean_t io, u_int32_t *val)
|
||||
{
|
||||
int size;
|
||||
struct FACPbody *facp;
|
||||
|
||||
facp = sc->facp_body;
|
||||
size = facp->gpe1_len / 2;
|
||||
|
||||
if (size == 0) /* port is optional */
|
||||
return;
|
||||
|
||||
if (io == ACPI_REGISTER_INPUT) {
|
||||
acpi_register_input(sc, ACPI_RES_GPE1, size, val, size);
|
||||
} else {
|
||||
acpi_register_output(sc, ACPI_RES_GPE1, size, val, size);
|
||||
}
|
||||
|
||||
ACPI_DEBUGPRINT("acpi_io_gpe0_enable(%d) = (%x)\n", io, *val);
|
||||
}
|
||||
|
||||
void
|
||||
acpi_gpe_enable_bit(acpi_softc_t *sc, u_int32_t bit, boolean_t on_off)
|
||||
{
|
||||
u_int32_t value;
|
||||
int res;
|
||||
|
||||
/*
|
||||
* Is the bit in the first GPE port?
|
||||
*/
|
||||
if (bit < ((sc->facp_body->gpe0_len / 2) * 8)) {
|
||||
res = ACPI_RES_GPE0;
|
||||
} else {
|
||||
/*
|
||||
* Is the bit in the second GPE port?
|
||||
*/
|
||||
bit -= sc->facp_body->gpe1_base;
|
||||
if (bit < ((sc->facp_body->gpe1_len / 2) * 8)) {
|
||||
res = ACPI_RES_GPE1;
|
||||
} else {
|
||||
return; /* do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
switch (res) {
|
||||
case ACPI_RES_GPE0:
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_INPUT, &value);
|
||||
break;
|
||||
case ACPI_RES_GPE1:
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_INPUT, &value);
|
||||
break;
|
||||
}
|
||||
value = (value & ~(1 << bit)) | (on_off ? (1 << bit) : 0);
|
||||
switch (res) {
|
||||
case ACPI_RES_GPE0:
|
||||
acpi_io_gpe0_enable(sc, ACPI_REGISTER_OUTPUT, &value);
|
||||
break;
|
||||
case ACPI_RES_GPE1:
|
||||
acpi_io_gpe1_enable(sc, ACPI_REGISTER_OUTPUT, &value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -27,15 +27,18 @@
|
||||
*/
|
||||
|
||||
#include "opt_acpi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <sys/acpi.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/acpi/acpi.h>
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#include <dev/acpi/acpivar.h>
|
||||
|
||||
#include <dev/acpi/aml/aml_amlmem.h>
|
||||
#include <dev/acpi/aml/aml_common.h>
|
||||
|
33
sys/dev/acpi/acpiio.h
Normal file
33
sys/dev/acpi/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)
|
||||
|
@ -24,14 +24,23 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: acpi.h,v 1.9 2000/08/08 14:12:16 iwasaki Exp $
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ACPI_H_
|
||||
#define _SYS_ACPI_H_
|
||||
|
||||
#include <sys/ioccom.h>
|
||||
/* Generic Address structure */
|
||||
struct ACPIgas {
|
||||
u_int8_t address_space_id;
|
||||
#define ACPI_GAS_MEMORY 0
|
||||
#define ACPI_GAS_IO 1
|
||||
#define ACPI_GAS_PCI 2
|
||||
#define ACPI_GAS_EMBEDDED 3
|
||||
#define ACPI_GAS_SMBUS 4
|
||||
#define ACPI_GAS_FIXED 0x7f
|
||||
u_int8_t register_bit_width;
|
||||
u_int8_t register_bit_offset;
|
||||
u_int8_t res;
|
||||
u_int64_t address;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Root System Description Pointer */
|
||||
struct ACPIrsdp {
|
||||
@ -96,7 +105,8 @@ struct FACPbody {
|
||||
u_int8_t day_alrm;
|
||||
u_int8_t mon_alrm;
|
||||
u_int8_t century;
|
||||
u_char reserved4[3];
|
||||
u_int16_t iapc_boot_arch;
|
||||
u_char reserved4[1];
|
||||
u_int32_t flags;
|
||||
#define ACPI_FACP_FLAG_WBINVD 1 /* WBINVD is correctly supported */
|
||||
#define ACPI_FACP_FLAG_WBINVD_FLUSH 2 /* WBINVD flushes caches */
|
||||
@ -108,6 +118,19 @@ struct FACPbody {
|
||||
#define ACPI_FACP_FLAG_RTC_S4 128 /* RTC can wakeup from S4 state */
|
||||
#define ACPI_FACP_FLAG_TMR_VAL_EXT 256 /* TMR_VAL is 32bit */
|
||||
#define ACPI_FACP_FLAG_DCK_CAP 512 /* Can support docking */
|
||||
struct ACPIgas reset_reg;
|
||||
u_int8_t reset_value;
|
||||
u_int8_t reserved5[3];
|
||||
u_int64_t x_firmware_ctrl;
|
||||
u_int64_t x_dsdt;
|
||||
struct ACPIgas x_pm1a_evt_blk;
|
||||
struct ACPIgas x_pm1b_evt_blk;
|
||||
struct ACPIgas x_pm1a_cnt_blk;
|
||||
struct ACPIgas x_pm1b_cnt_blk;
|
||||
struct ACPIgas x_pm2_cnt_blk;
|
||||
struct ACPIgas x_pm_tmr_blk;
|
||||
struct ACPIgas x_gpe0_blk;
|
||||
struct ACPIgas x_gpe1_blk;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Firmware ACPI Control Structure */
|
||||
@ -171,10 +194,6 @@ struct FACS {
|
||||
#define ACPI_S_STATE_S4 4
|
||||
#define ACPI_S_STATE_S5 5
|
||||
|
||||
#define ACPIIO_ENABLE _IO('P', 1)
|
||||
#define ACPIIO_DISABLE _IO('P', 2)
|
||||
#define ACPIIO_SETSLPSTATE _IOW('P', 3, int)
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* Structure for System State Package (7.5.2).
|
||||
@ -187,11 +206,6 @@ struct acpi_system_state_package {
|
||||
};
|
||||
#define ACPI_UNSUPPORTSLPTYP 0xff /* unsupported sleeping type */
|
||||
|
||||
extern struct ACPIrsdp *acpi_rsdp; /* ACPI Root System Description Table */
|
||||
|
||||
void acpi_init_addr_range(void);
|
||||
void acpi_register_addr_range(u_int64_t, u_int64_t, u_int32_t);
|
||||
|
||||
/*
|
||||
* ACPICA compatibility
|
||||
*/
|
||||
@ -330,4 +344,3 @@ void acpi_print_dsdt(struct ACPIsdt *);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _SYS_ACPI_H_ */
|
@ -1,6 +1,8 @@
|
||||
/*-
|
||||
* Copyright (c) 1999 Takanori Watanabe <takawata@shidahara1.planet.sci.kobe-u.ac.jp>
|
||||
* Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@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
|
||||
@ -27,9 +29,6 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DEV_ACPI_ACPI_H_
|
||||
#define _DEV_ACPI_ACPI_H_
|
||||
|
||||
/*
|
||||
* PowerResource control
|
||||
*/
|
||||
@ -92,15 +91,40 @@ struct acpi_event {
|
||||
int ae_arg;
|
||||
};
|
||||
|
||||
/*
|
||||
* I/O resource structure
|
||||
*/
|
||||
|
||||
#define ACPI_RES_SMI_CMD 0
|
||||
#define ACPI_RES_PM1A_EVT 1
|
||||
#define ACPI_RES_PM1B_EVT 2
|
||||
#define ACPI_RES_PM1A_CNT 3
|
||||
#define ACPI_RES_PM1B_CNT 4
|
||||
#define ACPI_RES_PM2_CNT 5
|
||||
#define ACPI_RES_PM_TMR 6
|
||||
#define ACPI_RES_GPE0 7
|
||||
#define ACPI_RES_GPE1 8
|
||||
#define ACPI_RES_FIRSTFREE 9
|
||||
#define ACPI_RES_AUTO -1
|
||||
#define ACPI_RES_MAX 64
|
||||
|
||||
struct acpi_io_resource {
|
||||
struct resource *rsc;
|
||||
int rid;
|
||||
int size;
|
||||
bus_space_handle_t bhandle;
|
||||
bus_space_tag_t btag;
|
||||
};
|
||||
|
||||
/*
|
||||
* Softc
|
||||
*/
|
||||
*/
|
||||
typedef struct acpi_softc {
|
||||
device_t dev;
|
||||
dev_t dev_t;
|
||||
|
||||
struct resource *port;
|
||||
int port_rid;
|
||||
struct acpi_io_resource iores[ACPI_RES_MAX];
|
||||
|
||||
struct resource *irq;
|
||||
int irq_rid;
|
||||
void *irq_handle;
|
||||
@ -125,6 +149,23 @@ typedef struct acpi_softc {
|
||||
STAILQ_HEAD(, acpi_event) event;
|
||||
} acpi_softc_t;
|
||||
|
||||
/*
|
||||
* ACPI register I/O
|
||||
*/
|
||||
#define ACPI_REGISTER_INPUT 0
|
||||
#define ACPI_REGISTER_OUTPUT 1
|
||||
extern void acpi_enable_disable(acpi_softc_t *sc, boolean_t enable);
|
||||
extern void acpi_io_pm1_status(acpi_softc_t *sc, boolean_t io, u_int32_t *status);
|
||||
extern void acpi_io_pm1_enable(acpi_softc_t *sc, boolean_t io, u_int32_t *enable);
|
||||
extern void acpi_io_pm1_control(acpi_softc_t *sc, boolean_t io, u_int32_t *val_a, u_int32_t *val_b);
|
||||
extern void acpi_io_pm2_control(acpi_softc_t *sc, boolean_t io, u_int32_t *val);
|
||||
extern void acpi_io_pm_timer(acpi_softc_t *sc, boolean_t io, u_int32_t *val);
|
||||
extern void acpi_io_gpe0_status(acpi_softc_t *sc, boolean_t io, u_int32_t *val);
|
||||
extern void acpi_io_gpe0_enable(acpi_softc_t *sc, boolean_t io, u_int32_t *val);
|
||||
extern void acpi_io_gpe1_status(acpi_softc_t *sc, boolean_t io, u_int32_t *val);
|
||||
extern void acpi_io_gpe1_enable(acpi_softc_t *sc, boolean_t io, u_int32_t *val);
|
||||
|
||||
|
||||
/*
|
||||
* Device State
|
||||
*/
|
||||
@ -134,6 +175,11 @@ extern void acpi_set_device_state(acpi_softc_t *sc, struct aml_name *name,
|
||||
extern void acpi_set_device_wakecap(acpi_softc_t *sc, struct aml_name *name,
|
||||
u_int8_t cap);
|
||||
|
||||
/*
|
||||
* System state
|
||||
*/
|
||||
extern void acpi_set_sleeping_state(acpi_softc_t *sc, u_int8_t state);
|
||||
|
||||
/*
|
||||
* PowerResource State
|
||||
*/
|
||||
@ -147,20 +193,54 @@ extern void acpi_powerres_set_sleeping_state(acpi_softc_t *sc, u_int8_t state);
|
||||
/*
|
||||
* GPE enable bit manipulation
|
||||
*/
|
||||
extern void acpi_gpe_enable_bit(acpi_softc_t *, u_int32_t, boolean_t);
|
||||
extern void acpi_gpe_enable_bit(acpi_softc_t *sc, u_int32_t bit, boolean_t on_off);
|
||||
|
||||
/*
|
||||
* Event queue
|
||||
* Event management
|
||||
*/
|
||||
extern void acpi_intr(void *data);
|
||||
extern void acpi_queue_event(acpi_softc_t *sc, int type, int arg);
|
||||
extern int acpi_send_pm_event(acpi_softc_t *sc, u_int8_t state);
|
||||
extern void acpi_enable_events(acpi_softc_t *sc);
|
||||
extern void acpi_clear_ignore_events(void *arg);
|
||||
extern void acpi_event_thread(void *arg);
|
||||
|
||||
/*
|
||||
* ACPI pmap subsystem
|
||||
*/
|
||||
#define ACPI_SMAP_MAX_SIZE 16
|
||||
|
||||
struct ACPIaddr {
|
||||
int entries;
|
||||
struct {
|
||||
vm_offset_t pa_base;
|
||||
vm_offset_t va_base;
|
||||
vm_size_t size;
|
||||
u_int32_t type;
|
||||
} t [ACPI_SMAP_MAX_SIZE];
|
||||
};
|
||||
|
||||
extern struct ACPIaddr acpi_addr;
|
||||
extern struct ACPIrsdp *acpi_rsdp; /* ACPI Root System Description Table */
|
||||
extern void acpi_init_addr_range(void);
|
||||
extern void acpi_register_addr_range(u_int64_t base, u_int64_t size, u_int32_t type);
|
||||
extern int acpi_sdt_checksum(struct ACPIsdt * sdt);
|
||||
extern vm_offset_t acpi_pmap_ptv(vm_offset_t pa);
|
||||
extern vm_offset_t acpi_pmap_vtp(vm_offset_t va);
|
||||
|
||||
/*
|
||||
* Bus interface.
|
||||
*/
|
||||
extern int acpi_attach_resource(acpi_softc_t *sc, int type, int *wantidx,
|
||||
u_long start, u_long size);
|
||||
extern struct ACPIrsdp *acpi_find_rsdp(void);
|
||||
extern void acpi_mapmem(void);
|
||||
|
||||
/*
|
||||
* Debugging, console output
|
||||
*
|
||||
* XXX this should really be using device_printf
|
||||
* XXX this should really be using device_printf or similar.
|
||||
*/
|
||||
extern int acpi_debug;
|
||||
#define ACPI_DEVPRINTF(args...) printf("acpi0: " args)
|
||||
#define ACPI_DEBUGPRINT(args...) do { if (acpi_debug) ACPI_DEVPRINTF(args);} while(0)
|
||||
|
||||
#endif /* !_DEV_ACPI_ACPI_H_ */
|
@ -42,7 +42,7 @@
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/acpi.h>
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#ifndef ACPI_NO_OSDFUNC_INLINE
|
||||
#include <machine/acpica_osd.h>
|
||||
#endif /* !ACPI_NO_OSDFUNC_INLINE */
|
||||
|
@ -32,10 +32,15 @@
|
||||
* Region I/O subroutine
|
||||
*/
|
||||
|
||||
#include "opt_acpi.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/acpi.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#include <dev/acpi/aml/aml_common.h>
|
||||
#include <dev/acpi/aml/aml_region.h>
|
||||
#include <dev/acpi/aml/aml_name.h>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
|
||||
* Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -23,14 +23,116 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: acpi_machdep.c,v 1.4 2000/08/08 14:12:10 iwasaki Exp $
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_acpi.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/acpi_machdep.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#ifdef ACPI_NO_OSDFUNC_INLINE
|
||||
#include <machine/acpica_osd.h>
|
||||
#endif /* ACPI_NO_OSDFUNC_INLINE */
|
||||
#include <machine/bus.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/vmparam.h>
|
||||
#include <machine/vm86.h>
|
||||
#include <machine/pc/bios.h>
|
||||
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#include <dev/acpi/acpivar.h>
|
||||
|
||||
struct ACPIrsdp *
|
||||
acpi_find_rsdp(void)
|
||||
{
|
||||
u_long sigaddr;
|
||||
struct ACPIrsdp *rsdp;
|
||||
u_int8_t ck, *cv;
|
||||
int i, year;
|
||||
char *dp;
|
||||
|
||||
/*
|
||||
* Search for the RSD PTR signature.
|
||||
*/
|
||||
if ((sigaddr = bios_sigsearch(0, "RSD PTR ", 8, 16, 0)) == 0)
|
||||
return(NULL);
|
||||
|
||||
/* get a virtual pointer to the structure */
|
||||
rsdp = (struct ACPIrsdp *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
|
||||
for (cv = (u_int8_t *)rsdp, ck = 0, i = 0; i < sizeof(struct ACPIrsdp); i++) {
|
||||
ck += cv[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Fail if the checksum doesn't match.
|
||||
*/
|
||||
if (ck != 0) {
|
||||
printf("ACPI: Bad ACPI BIOS data checksum\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fail if the BIOS is too old to be trustworthy.
|
||||
* XXX we should check the ACPI BIOS blacklist/goodlist here.
|
||||
*/
|
||||
dp = (char *)(uintptr_t)BIOS_PADDRTOVADDR(0xffff5);
|
||||
year = ((*(dp + 6) - '0') * 10) + (*(dp + 7) - '0');
|
||||
if (year < 70)
|
||||
year += 100;
|
||||
if (year < 99) {
|
||||
printf("ACPI: BIOS too old (%.8s < 01/01/99)\n", dp);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
return(rsdp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and map all memory regions that are regarded as belonging to ACPI
|
||||
* and let the MI code know about them. Scan the ACPI memory map as managed
|
||||
* by the MI code and map it into kernel space.
|
||||
*/
|
||||
void
|
||||
acpi_mapmem(void)
|
||||
{
|
||||
struct vm86frame vmf;
|
||||
struct vm86context vmc;
|
||||
struct bios_smap *smap;
|
||||
vm_offset_t va;
|
||||
int i;
|
||||
|
||||
bzero(&vmf, sizeof(struct vm86frame));
|
||||
|
||||
acpi_init_addr_range();
|
||||
|
||||
/*
|
||||
* Scan memory map with INT 15:E820
|
||||
*/
|
||||
vmc.npages = 0;
|
||||
smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT));
|
||||
vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di);
|
||||
|
||||
vmf.vmf_ebx = 0;
|
||||
do {
|
||||
vmf.vmf_eax = 0xE820;
|
||||
vmf.vmf_edx = SMAP_SIG;
|
||||
vmf.vmf_ecx = sizeof(struct bios_smap);
|
||||
i = vm86_datacall(0x15, &vmf, &vmc);
|
||||
if (i || vmf.vmf_eax != SMAP_SIG)
|
||||
break;
|
||||
|
||||
/* ACPI-owned memory? */
|
||||
if (smap->type == 0x03 || smap->type == 0x04) {
|
||||
acpi_register_addr_range(smap->base, smap->length, smap->type);
|
||||
}
|
||||
} while (vmf.vmf_ebx != 0);
|
||||
|
||||
/*
|
||||
* Map the physical ranges that have been registered into the kernel.
|
||||
*/
|
||||
for (i = 0; i < acpi_addr.entries; i++) {
|
||||
va = (vm_offset_t)pmap_mapdev(acpi_addr.t[i].pa_base, acpi_addr.t[i].size);
|
||||
acpi_addr.t[i].va_base = va;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
* Code for dealing with the BIOS in x86 PC systems.
|
||||
*/
|
||||
|
||||
#include "acpi.h"
|
||||
#include "isa.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -50,10 +49,6 @@
|
||||
#include <isa/pnpreg.h>
|
||||
#include <isa/pnpvar.h>
|
||||
|
||||
#if NACPI > 0
|
||||
#include <sys/acpi.h>
|
||||
#endif
|
||||
|
||||
#define BIOS_START 0xe0000
|
||||
#define BIOS_SIZE 0x20000
|
||||
|
||||
@ -148,26 +143,6 @@ bios32_init(void *junk)
|
||||
printf("pnpbios: Bad PnP BIOS data checksum\n");
|
||||
}
|
||||
}
|
||||
#if NACPI > 0
|
||||
/*
|
||||
* ACPI BIOS
|
||||
* acpi_rsdp is GLOBAL and holds RSD PTR signature
|
||||
*/
|
||||
if ((sigaddr = bios_sigsearch(0, "RSD PTR ", 8, 16, 0)) != 0) {
|
||||
/* get a virtual pointer to the structure */
|
||||
acpi_rsdp = (struct ACPIrsdp *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
|
||||
for (cv = (u_int8_t *)acpi_rsdp, ck = 0, i = 0; i < sizeof(struct ACPIrsdp); i++) {
|
||||
ck += cv[i];
|
||||
}
|
||||
|
||||
/* If checksum is NG, disable it */
|
||||
if (ck != 0) {
|
||||
printf("ACPI: Bad ACPI BIOS data checksum\n");
|
||||
acpi_rsdp=NULL;/* 0xa0000<=RSD_PTR<0x100000*/
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bootverbose) {
|
||||
/* look for other know signatures */
|
||||
printf("Other BIOS signatures found:\n");
|
||||
|
@ -37,7 +37,6 @@
|
||||
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include "acpi.h"
|
||||
#include "apm.h"
|
||||
#include "npx.h"
|
||||
#include "opt_atalk.h"
|
||||
@ -100,6 +99,7 @@
|
||||
#include <machine/ipl.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/mutex.h>
|
||||
#include <machine/pc/bios.h>
|
||||
#include <machine/pcb_ext.h> /* pcb.h included via sys/user.h */
|
||||
#include <machine/globaldata.h>
|
||||
#include <machine/globals.h>
|
||||
@ -120,10 +120,6 @@
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/sigframe.h>
|
||||
|
||||
#if NACPI > 0
|
||||
#include <sys/acpi.h>
|
||||
#endif
|
||||
|
||||
extern void init386 __P((int first));
|
||||
extern void dblfault_handler __P((void));
|
||||
|
||||
@ -1457,11 +1453,7 @@ getmemsize(int first)
|
||||
vm_offset_t pa, physmap[PHYSMAP_SIZE];
|
||||
pt_entry_t pte;
|
||||
const char *cp;
|
||||
struct {
|
||||
u_int64_t base;
|
||||
u_int64_t length;
|
||||
u_int32_t type;
|
||||
} *smap;
|
||||
struct bios_smap *smap;
|
||||
|
||||
bzero(&vmf, sizeof(struct vm86frame));
|
||||
bzero(physmap, sizeof(physmap));
|
||||
@ -1521,22 +1513,16 @@ getmemsize(int first)
|
||||
/*
|
||||
* get memory map with INT 15:E820
|
||||
*/
|
||||
#define SMAPSIZ sizeof(*smap)
|
||||
#define SMAP_SIG 0x534D4150 /* 'SMAP' */
|
||||
|
||||
vmc.npages = 0;
|
||||
smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT));
|
||||
vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di);
|
||||
|
||||
#if NACPI > 0
|
||||
acpi_init_addr_range();
|
||||
#endif
|
||||
physmap_idx = 0;
|
||||
vmf.vmf_ebx = 0;
|
||||
do {
|
||||
vmf.vmf_eax = 0xE820;
|
||||
vmf.vmf_edx = SMAP_SIG;
|
||||
vmf.vmf_ecx = SMAPSIZ;
|
||||
vmf.vmf_ecx = sizeof(struct bios_smap);
|
||||
i = vm86_datacall(0x15, &vmf, &vmc);
|
||||
if (i || vmf.vmf_eax != SMAP_SIG)
|
||||
break;
|
||||
@ -1547,13 +1533,7 @@ getmemsize(int first)
|
||||
(u_int32_t)smap->base,
|
||||
*(u_int32_t *)((char *)&smap->length + 4),
|
||||
(u_int32_t)smap->length);
|
||||
#if NACPI > 0
|
||||
/* Save ACPI related memory Info */
|
||||
if (smap->type == 0x03 || smap->type == 0x04) {
|
||||
acpi_register_addr_range(smap->base,
|
||||
smap->length, smap->type);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (smap->type != 0x01)
|
||||
goto next_run;
|
||||
|
||||
|
@ -218,3 +218,16 @@ extern int bios16(struct bios_args *, char *, ...);
|
||||
extern int bios16_call(struct bios_regs *, char *);
|
||||
extern int bios32(struct bios_regs *, u_int, u_short);
|
||||
extern void set_bios_selectors(struct bios_segments *, int);
|
||||
|
||||
/*
|
||||
* Int 15:E820 'SMAP' structure
|
||||
*
|
||||
* XXX add constants for type
|
||||
*/
|
||||
#define SMAP_SIG 0x534D4150 /* 'SMAP' */
|
||||
struct bios_smap {
|
||||
u_int64_t base;
|
||||
u_int64_t length;
|
||||
u_int32_t type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/acpi.h>
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#ifndef ACPI_NO_OSDFUNC_INLINE
|
||||
#include <machine/acpica_osd.h>
|
||||
#endif /* !ACPI_NO_OSDFUNC_INLINE */
|
||||
|
@ -32,10 +32,15 @@
|
||||
* Region I/O subroutine
|
||||
*/
|
||||
|
||||
#include "opt_acpi.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/acpi.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/acpi/acpireg.h>
|
||||
#include <dev/acpi/aml/aml_common.h>
|
||||
#include <dev/acpi/aml/aml_region.h>
|
||||
#include <dev/acpi/aml/aml_name.h>
|
||||
|
Loading…
x
Reference in New Issue
Block a user