/drivers/acpi/Makefile |
---|
0,0 → 1,192 |
CC = kos32-gcc |
FASM = fasm.exe |
DRV_DIR = $(CURDIR)/.. |
DRV_INCLUDES = $(DRV_DIR)/include |
ACPI_INCLUDES = ./acpica/include |
INCLUDES = -I$(DRV_INCLUDES) \ |
-I$(DRV_INCLUDES)/asm \ |
-I$(DRV_INCLUDES)/uapi |
INCLUDES+= -I$(ACPI_INCLUDES) -I./ |
DEFINES = -D_LINUX -D__KERNEL__ -DCONFIG_X86 -DCONFIG_X86_32 -DCONFIG_PCI -DCONFIG_ACPI -DBUILDING_ACPICA |
DEFINES += -DCONFIG_X86_CMPXCHG64 -DCONFIG_TINY_RCU -DCONFIG_X86_L1_CACHE_SHIFT=6 |
DEFINES += -DACPI_USE_LOCAL_CACHE -DACPI_NO_ERROR_MESSAGES |
DEFINES += -DCONFIG_DMI -DCONFIG_ACPI_REDUCED_HARDWARE_ONLY -DKBUILD_MODNAME=\"acpi.dll\" |
CFLAGS_OPT = -Os -march=i686 -fomit-frame-pointer -fno-ident -mno-stack-arg-probe |
CFLAGS_OPT+= -fno-builtin-printf -fno-builtin-snprintf -fno-builtin-sscanf -fno-builtin-vsscanf |
CFLAGS_OPT+= -fno-builtin-scnprintf -fno-builtin-vsprintf -fno-builtin-vsnprintf |
CFLAGS_OPT+= -mno-ms-bitfields |
CFLAGS = $(INCLUDES) $(DEFINES) $(CFLAGS_OPT) |
PE_FLAGS=--major-os-version,0,--minor-os-version,7,--major-subsystem-version,0,--minor-subsystem-version,5,--subsystem,native |
LDFLAGS=-e,_drvEntry,-nostdlib,-s,-pie,$(PE_FLAGS),--image-base,0,--file-alignment,512,--section-alignment,512 |
LIBPATH:= -L$(DRV_DIR)/ddk -L./acpica |
LIBS:= -lcore |
NAME= acpi |
NAME_SRCS= acpi.c \ |
blacklist.c \ |
boot.c \ |
bus.c \ |
tables.c \ |
acpica/dsargs.c \ |
acpica/dscontrol.c \ |
acpica/dsdebug.c \ |
acpica/dsfield.c \ |
acpica/dsinit.c \ |
acpica/dsmethod.c \ |
acpica/dsmthdat.c \ |
acpica/dsobject.c \ |
acpica/dsopcode.c \ |
acpica/dsutils.c \ |
acpica/dswexec.c \ |
acpica/dswload.c \ |
acpica/dswload2.c \ |
acpica/dswscope.c \ |
acpica/dswstate.c \ |
acpica/evmisc.c \ |
acpica/evregion.c \ |
acpica/evrgnini.c \ |
acpica/exconfig.c \ |
acpica/exconvrt.c \ |
acpica/excreate.c \ |
acpica/exdebug.c \ |
acpica/exfield.c \ |
acpica/exfldio.c \ |
acpica/exmisc.c \ |
acpica/exmutex.c \ |
acpica/exnames.c \ |
acpica/exoparg1.c \ |
acpica/exoparg2.c \ |
acpica/exoparg3.c \ |
acpica/exoparg6.c \ |
acpica/exprep.c \ |
acpica/exresnte.c \ |
acpica/exresolv.c \ |
acpica/exresop.c \ |
acpica/exstore.c \ |
acpica/exstoren.c \ |
acpica/exstorob.c \ |
acpica/exsystem.c \ |
acpica/exutils.c \ |
acpica/nsaccess.c \ |
acpica/nsalloc.c \ |
acpica/nsarguments.c \ |
acpica/nsconvert.c \ |
acpica/nseval.c \ |
acpica/nsinit.c \ |
acpica/nsload.c \ |
acpica/nsnames.c \ |
acpica/nsobject.c \ |
acpica/nsparse.c \ |
acpica/nspredef.c \ |
acpica/nsprepkg.c \ |
acpica/nsrepair.c \ |
acpica/nsrepair2.c \ |
acpica/nssearch.c \ |
acpica/nsutils.c \ |
acpica/nswalk.c \ |
acpica/psargs.c \ |
acpica/psloop.c \ |
acpica/psobject.c \ |
acpica/psopcode.c \ |
acpica/psopinfo.c \ |
acpica/psparse.c \ |
acpica/psscope.c \ |
acpica/pstree.c \ |
acpica/psutils.c \ |
acpica/pswalk.c \ |
acpica/psxface.c \ |
acpica/tbdata.c \ |
acpica/tbfind.c \ |
acpica/tbfadt.c \ |
acpica/tbinstal.c \ |
acpica/tbprint.c \ |
acpica/tbutils.c \ |
acpica/tbxface.c \ |
acpica/tbxfload.c \ |
acpica/utaddress.c \ |
acpica/utalloc.c \ |
acpica/utbuffer.c \ |
acpica/utcache.c \ |
acpica/utcopy.c \ |
acpica/utdecode.c \ |
acpica/utdelete.c \ |
acpica/uterror.c \ |
acpica/utexcep.c \ |
acpica/utglobal.c \ |
acpica/uthex.c \ |
acpica/utinit.c \ |
acpica/utlock.c \ |
acpica/utmath.c \ |
acpica/utmisc.c \ |
acpica/utmutex.c \ |
acpica/utnonansi.c \ |
acpica/utobject.c \ |
acpica/utosi.c \ |
acpica/utownerid.c \ |
acpica/utpredef.c \ |
acpica/utresrc.c \ |
acpica/utstate.c \ |
acpica/utstring.c \ |
acpica/utxface.c \ |
acpica/utxferror.c \ |
acpica/utxfinit.c \ |
../ddk/debug/dbglog.c \ |
../ddk/io/create.c \ |
../ddk/io/finfo.c \ |
../ddk/io/ssize.c \ |
../ddk/io/write.c \ |
../ddk/malloc/malloc.c \ |
../ddk/linux/ctype.c \ |
../ddk/linux/div64.c \ |
../ddk/linux/dmi.c \ |
../ddk/linux/hexdump.c \ |
../ddk/stdio/vsprintf.c \ |
../ddk/string/strstr.c \ |
../ddk/string/_strncat.S\ |
../ddk/string/_strncmp.S\ |
../ddk/string/_strncpy.S\ |
../ddk/string/_strnlen.S\ |
../ddk/string/memcmp.S \ |
../ddk/string/strcat.S \ |
../ddk/string/strcmp.S \ |
../ddk/string/strcpy.S \ |
../ddk/string/strncmp.S \ |
../ddk/string/strncpy.S \ |
../ddk/string/strnlen.S \ |
$(NULL) |
all: $(NAME).dll |
NAME_OBJS = $(patsubst %.S, %.o, $(patsubst %.asm, %.o,\ |
$(patsubst %.c, %.o, $(NAME_SRCS)))) |
all: $(NAME).dll |
$(NAME).dll: $(NAME_SRCS) acpi.lds Makefile |
$(CC) $(CFLAGS) -nostdlib -fwhole-program -flto -Wl,-Map,acpi.map,-T,acpi.lds,$(LDFLAGS) -Wl,$(LIBPATH) -o $@ $(NAME_SRCS) $(LIBS) |
strip $(NAME).dll |
# kpack $(NAME).dll |
%.o : %.S $(HFILES) Makefile |
as -o $@ $< |
/drivers/acpi/acpi |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/acpi/acpi.asm |
---|
0,0 → 1,27 |
use32 |
db 'MENUET01' |
dd 1 |
dd start |
dd i_end |
dd mem |
dd mem |
dd 0 |
dd 0 |
start: |
mov eax, 68 |
mov ebx, 21 |
mov ecx, sz_acpi |
int 0x40 |
mov eax, -1 |
int 0x40 |
sz_acpi db '/rd/1/drivers/acpi.dll',0 |
align 4 |
i_end: |
rb 128 |
mem: |
/drivers/acpi/acpi.c |
---|
0,0 → 1,631 |
#include <syscall.h> |
#include <linux/delay.h> |
#include <linux/ktime.h> |
#include <linux/acpi.h> |
#include <linux/dmi.h> |
#define PREFIX "ACPI: " |
int sbf_port __initdata = -1; |
static bool acpi_os_initialized; |
u32 __attribute__((externally_visible)) drvEntry(int action, char *cmdline) |
{ |
int result; |
if(action != 1) |
return 0; |
if( !dbg_open("/tmp0/1/acpi.log") ) |
{ |
printk("Can't open /tmp0/1/acpi.log\nExit\n"); |
return 0; |
} |
dmi_scan_machine(); |
acpi_boot_table_init(); |
early_acpi_boot_init(); |
acpi_noirq_set(); |
acpi_early_init(); |
// if (acpi_disabled) { |
// printk(KERN_INFO PREFIX "Interpreter disabled.\n"); |
// return -ENODEV; |
// } |
// init_acpi_device_notify(); |
// result = acpi_bus_init(); |
// if (result) { |
// disable_acpi(); |
// return result; |
// } |
// pci_mmcfg_late_init(); |
// acpi_scan_init(); |
// acpi_ec_init(); |
// acpi_debugfs_init(); |
// acpi_sleep_proc_init(); |
// acpi_wakeup_device_init(); |
dbgprintf("module loaded\n"); |
return 0; |
}; |
#define PREFIX "ACPI: " |
u32 IMPORT AcpiGetRootPtr(void)__asm__("AcpiGetRootPtr"); |
acpi_physical_address __init acpi_os_get_root_pointer(void) |
{ |
return AcpiGetRootPtr(); |
} |
void* acpi_os_map_memory(acpi_physical_address phys, acpi_size size) |
{ |
return (void *)MapIoMem((addr_t)phys, size, PG_SW); |
} |
void acpi_os_unmap_memory(void *virt, acpi_size size) |
{ |
u32 ptr = (u32)virt; |
ptr &= 0xFFFFF000; |
return FreeKernelSpace((void*)ptr); |
} |
void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) |
{ |
acpi_os_unmap_memory(virt, size); |
} |
int acpi_os_map_generic_address(struct acpi_generic_address *gas) |
{ |
addr_t addr; |
void *virt; |
if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
return 0; |
addr = (addr_t)gas->address; |
if (!addr || !gas->bit_width) |
return -EINVAL; |
virt = (void *)MapIoMem(addr, gas->bit_width / 8, PG_SW); |
if (!virt) |
return -EIO; |
return 0; |
} |
void acpi_os_printf(const char *fmt, ...) |
{ |
va_list args; |
va_start(args, fmt); |
acpi_os_vprintf(fmt, args); |
va_end(args); |
} |
void acpi_os_vprintf(const char *fmt, va_list args) |
{ |
static char buffer[512]; |
vsprintf(buffer, fmt, args); |
#ifdef ENABLE_DEBUGGER |
if (acpi_in_debugger) { |
kdb_printf("%s", buffer); |
} else { |
printk("%s", buffer); |
} |
#else |
printk("%s", buffer); |
#endif |
} |
static void acpi_table_taint(struct acpi_table_header *table) |
{ |
pr_warn(PREFIX |
"Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n", |
table->signature, table->oem_table_id); |
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); |
} |
acpi_status |
acpi_os_table_override(struct acpi_table_header * existing_table, |
struct acpi_table_header ** new_table) |
{ |
if (!existing_table || !new_table) |
return AE_BAD_PARAMETER; |
*new_table = NULL; |
#ifdef CONFIG_ACPI_CUSTOM_DSDT |
if (strncmp(existing_table->signature, "DSDT", 4) == 0) |
*new_table = (struct acpi_table_header *)AmlCode; |
#endif |
if (*new_table != NULL) |
acpi_table_taint(existing_table); |
return AE_OK; |
} |
acpi_status |
acpi_os_physical_table_override(struct acpi_table_header *existing_table, |
acpi_physical_address *address, |
u32 *table_length) |
{ |
#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE |
*table_length = 0; |
*address = 0; |
return AE_OK; |
#else |
int table_offset = 0; |
struct acpi_table_header *table; |
*table_length = 0; |
*address = 0; |
if (!acpi_tables_addr) |
return AE_OK; |
do { |
if (table_offset + ACPI_HEADER_SIZE > all_tables_size) { |
WARN_ON(1); |
return AE_OK; |
} |
table = acpi_os_map_memory(acpi_tables_addr + table_offset, |
ACPI_HEADER_SIZE); |
if (table_offset + table->length > all_tables_size) { |
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); |
WARN_ON(1); |
return AE_OK; |
} |
table_offset += table->length; |
if (memcmp(existing_table->signature, table->signature, 4)) { |
acpi_os_unmap_memory(table, |
ACPI_HEADER_SIZE); |
continue; |
} |
/* Only override tables with matching oem id */ |
if (memcmp(table->oem_table_id, existing_table->oem_table_id, |
ACPI_OEM_TABLE_ID_SIZE)) { |
acpi_os_unmap_memory(table, |
ACPI_HEADER_SIZE); |
continue; |
} |
table_offset -= table->length; |
*table_length = table->length; |
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); |
*address = acpi_tables_addr + table_offset; |
break; |
} while (table_offset + ACPI_HEADER_SIZE < all_tables_size); |
if (*address != 0) |
acpi_table_taint(existing_table); |
return AE_OK; |
#endif |
} |
static struct osi_linux { |
unsigned int enable:1; |
unsigned int dmi:1; |
unsigned int cmdline:1; |
unsigned int default_disabling:1; |
} osi_linux = {0, 0, 0, 0}; |
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
#define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */ |
struct osi_setup_entry { |
char string[OSI_STRING_LENGTH_MAX]; |
bool enable; |
}; |
static struct osi_setup_entry |
osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = { |
{"Module Device", true}, |
{"Processor Device", true}, |
{"3.0 _SCP Extensions", true}, |
{"Processor Aggregator Device", true}, |
}; |
void __init acpi_osi_setup(char *str) |
{ |
struct osi_setup_entry *osi; |
bool enable = true; |
int i; |
if (!acpi_gbl_create_osi_method) |
return; |
if (str == NULL || *str == '\0') { |
printk(KERN_INFO PREFIX "_OSI method disabled\n"); |
acpi_gbl_create_osi_method = FALSE; |
return; |
} |
if (*str == '!') { |
str++; |
if (*str == '\0') { |
osi_linux.default_disabling = 1; |
return; |
} else if (*str == '*') { |
acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS); |
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { |
osi = &osi_setup_entries[i]; |
osi->enable = false; |
} |
return; |
} |
enable = false; |
} |
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { |
osi = &osi_setup_entries[i]; |
if (!strcmp(osi->string, str)) { |
osi->enable = enable; |
break; |
} else if (osi->string[0] == '\0') { |
osi->enable = enable; |
strncpy(osi->string, str, OSI_STRING_LENGTH_MAX); |
break; |
} |
} |
} |
static void __init set_osi_linux(unsigned int enable) |
{ |
if (osi_linux.enable != enable) |
osi_linux.enable = enable; |
if (osi_linux.enable) |
acpi_osi_setup("Linux"); |
else |
acpi_osi_setup("!Linux"); |
return; |
} |
void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) |
{ |
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); |
if (enable == -1) |
return; |
osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */ |
set_osi_linux(enable); |
return; |
} |
acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) |
{ |
void *sem = (void*)handle; |
if (!acpi_os_initialized) |
return AE_OK; |
if (!sem || (units < 1)) |
return AE_BAD_PARAMETER; |
if (units > 1) |
return AE_SUPPORT; |
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", |
handle, units, timeout)); |
return AE_OK; |
} |
acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) |
{ |
void *sem = (void*)handle; |
if (!acpi_os_initialized) |
return AE_OK; |
if (!sem || (units < 1)) |
return AE_BAD_PARAMETER; |
if (units > 1) |
return AE_SUPPORT; |
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle, |
units)); |
// up(sem); |
return AE_OK; |
} |
acpi_status __init acpi_os_initialize(void) |
{ |
// acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block); |
// acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); |
// acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); |
// acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); |
if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) { |
/* |
* Use acpi_os_map_generic_address to pre-map the reset |
* register if it's in system memory. |
*/ |
int rv; |
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); |
pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv); |
} |
acpi_os_initialized = true; |
return AE_OK; |
} |
acpi_status __init acpi_os_initialize1(void) |
{ |
// kacpid_wq = alloc_workqueue("kacpid", 0, 1); |
// kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); |
// kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); |
// BUG_ON(!kacpid_wq); |
// BUG_ON(!kacpi_notify_wq); |
// BUG_ON(!kacpi_hotplug_wq); |
// acpi_install_interface_handler(acpi_osi_handler); |
// acpi_osi_setup_late(); |
return AE_OK; |
} |
acpi_status acpi_os_delete_semaphore(acpi_handle handle) |
{ |
// void *sem = (void*)handle; |
// if (!sem) |
// return AE_BAD_PARAMETER; |
// kfree(sem); |
// sem = NULL; |
return AE_OK; |
} |
acpi_status acpi_os_create_semaphore(u32 max_units, |
u32 initial_units, acpi_handle * out_handle) |
{ |
*out_handle = (acpi_handle) 1; |
return (AE_OK); |
} |
acpi_status |
acpi_os_create_mutex(acpi_handle * handle) |
{ |
struct mutex *mtx = NULL; |
mtx = kzalloc(sizeof(struct mutex),0); |
if (!mtx) |
return AE_NO_MEMORY; |
mutex_init(mtx); |
*handle = (acpi_handle *) mtx; |
return AE_OK; |
} |
void acpi_os_release_mutex(acpi_mutex handle) |
{ |
struct mutex *mtx = (struct mutex*)handle; |
if (!acpi_os_initialized) |
return; |
mutex_unlock(mtx); |
} |
acpi_status acpi_os_acquire_mutex(acpi_mutex handle, u16 timeout) |
{ |
struct mutex *mtx = (struct mutex*)handle; |
if (!acpi_os_initialized) |
return AE_OK; |
mutex_lock(mtx); |
return AE_OK; |
} |
void acpi_os_delete_mutex(acpi_mutex handle) |
{ |
struct mutex *mtx = (struct mutex*)handle; |
kfree(mtx); |
}; |
acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) |
{ |
acpi_cpu_flags flags; |
spin_lock_irqsave(lockp, flags); |
return flags; |
} |
void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) |
{ |
spin_unlock_irqrestore(lockp, flags); |
} |
acpi_status acpi_os_signal(u32 function, void *info) |
{ |
switch (function) { |
case ACPI_SIGNAL_FATAL: |
printk(KERN_ERR PREFIX "Fatal opcode executed\n"); |
break; |
case ACPI_SIGNAL_BREAKPOINT: |
/* |
* AML Breakpoint |
* ACPI spec. says to treat it as a NOP unless |
* you are debugging. So if/when we integrate |
* AML debugger into the kernel debugger its |
* hook will go here. But until then it is |
* not useful to print anything on breakpoints. |
*/ |
break; |
default: |
break; |
} |
return AE_OK; |
} |
void acpi_os_sleep(u64 ms) |
{ |
msleep(ms); |
} |
void acpi_os_stall(u32 us) |
{ |
while (us) { |
u32 delay = 1000; |
if (delay > us) |
delay = us; |
udelay(delay); |
// touch_nmi_watchdog(); |
us -= delay; |
} |
} |
void msleep(unsigned int msecs) |
{ |
msecs /= 10; |
if(!msecs) msecs = 1; |
__asm__ __volatile__ ( |
"call *__imp__Delay" |
::"b" (msecs)); |
__asm__ __volatile__ ( |
"":::"ebx"); |
}; |
acpi_status acpi_os_execute(acpi_execute_type type, |
acpi_osd_exec_callback function, void *context) |
{ |
return AE_OK; |
} |
u64 acpi_os_get_timer(void) |
{ |
u64 time_ns = ktime_to_ns(ktime_get()); |
do_div(time_ns, 100); |
return time_ns; |
} |
ktime_t ktime_get(void) |
{ |
ktime_t t; |
t.tv64 = GetClockNs(); |
return t; |
} |
void __delay(unsigned long loops) |
{ |
asm volatile( |
"test %0,%0\n" |
"jz 3f\n" |
"jmp 1f\n" |
".align 16\n" |
"1: jmp 2f\n" |
".align 16\n" |
"2: dec %0\n" |
" jnz 2b\n" |
"3: dec %0\n" |
: /* we don't need output */ |
: "a" (loops) |
); |
} |
inline void __const_udelay(unsigned long xloops) |
{ |
int d0; |
xloops *= 4; |
asm("mull %%edx" |
: "=d" (xloops), "=&a" (d0) |
: "1" (xloops), "" |
(loops_per_jiffy * (HZ/4))); |
__delay(++xloops); |
} |
void __udelay(unsigned long usecs) |
{ |
__const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ |
} |
#define acpi_rev_override false |
#define ACPI_MAX_OVERRIDE_LEN 100 |
static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN]; |
acpi_status |
acpi_os_predefined_override(const struct acpi_predefined_names *init_val, |
char **new_val) |
{ |
if (!init_val || !new_val) |
return AE_BAD_PARAMETER; |
*new_val = NULL; |
if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) { |
printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n", |
acpi_os_name); |
*new_val = acpi_os_name; |
} |
if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) { |
printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n"); |
*new_val = (char *)5; |
} |
return AE_OK; |
} |
/drivers/acpi/acpi.lds |
---|
0,0 → 1,69 |
OUTPUT_FORMAT(pei-i386) |
ENTRY("_drvEntry") |
SECTIONS |
{ |
. = SIZEOF_HEADERS; |
. = ALIGN(__section_alignment__); |
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) : |
{ |
*(.text) |
*(SORT(.text$*)) |
*(.text.*) |
. = ALIGN(16); |
*(.rdata) |
*(SORT(.rdata$*)) |
. = ALIGN(16); |
*(.data) |
*(.data2) |
*(SORT(.data$*)) |
. = ALIGN(16); |
*(.bss) |
*(COMMON) |
} |
.idata ALIGN(__section_alignment__): |
{ |
SORT(*)(.idata$2) |
SORT(*)(.idata$3) |
/* These zeroes mark the end of the import list. */ |
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0); |
SORT(*)(.idata$4) |
SORT(*)(.idata$5) |
SORT(*)(.idata$6) |
SORT(*)(.idata$7) |
} |
.reloc ALIGN(__section_alignment__) : |
{ |
*(.reloc) |
} |
/DISCARD/ : |
{ |
*(.debug$S) |
*(.debug$T) |
*(.debug$F) |
*(.drectve) |
*(.edata) |
*(.note.GNU-stack) |
*(.comment) |
*(.eh_frame) |
*(.debug_abbrev) |
*(.debug_info) |
*(.debug_line) |
*(.debug_frame) |
*(.debug_loc) |
*(.debug_pubnames) |
*(.debug_aranges) |
*(.debug_ranges) |
} |
} |
/drivers/acpi/acpica/acapps.h |
---|
0,0 → 1,173 |
/****************************************************************************** |
* |
* Module Name: acapps - common include for ACPI applications/tools |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef _ACAPPS |
#define _ACAPPS |
/* Common info for tool signons */ |
#define ACPICA_NAME "Intel ACPI Component Architecture" |
#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2015 Intel Corporation" |
#if ACPI_MACHINE_WIDTH == 64 |
#define ACPI_WIDTH "-64" |
#elif ACPI_MACHINE_WIDTH == 32 |
#define ACPI_WIDTH "-32" |
#else |
#error unknown ACPI_MACHINE_WIDTH |
#define ACPI_WIDTH "-??" |
#endif |
/* Macros for signons and file headers */ |
#define ACPI_COMMON_SIGNON(utility_name) \ |
"\n%s\n%s version %8.8X%s\n%s\n\n", \ |
ACPICA_NAME, \ |
utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, \ |
ACPICA_COPYRIGHT |
#define ACPI_COMMON_HEADER(utility_name, prefix) \ |
"%s%s\n%s%s version %8.8X%s\n%s%s\n%s\n", \ |
prefix, ACPICA_NAME, \ |
prefix, utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, \ |
prefix, ACPICA_COPYRIGHT, \ |
prefix |
/* Macros for usage messages */ |
#define ACPI_USAGE_HEADER(usage) \ |
acpi_os_printf ("Usage: %s\nOptions:\n", usage); |
#define ACPI_USAGE_TEXT(description) \ |
acpi_os_printf (description); |
#define ACPI_OPTION(name, description) \ |
acpi_os_printf (" %-18s%s\n", name, description); |
#define FILE_SUFFIX_DISASSEMBLY "dsl" |
#define FILE_SUFFIX_BINARY_TABLE ".dat" /* Needs the dot */ |
/* |
* getopt |
*/ |
int acpi_getopt(int argc, char **argv, char *opts); |
int acpi_getopt_argument(int argc, char **argv); |
extern int acpi_gbl_optind; |
extern int acpi_gbl_opterr; |
extern int acpi_gbl_sub_opt_char; |
extern char *acpi_gbl_optarg; |
/* |
* cmfsize - Common get file size function |
*/ |
u32 cm_get_file_size(ACPI_FILE file); |
#ifndef ACPI_DUMP_APP |
/* |
* adisasm |
*/ |
acpi_status |
ad_aml_disassemble(u8 out_to_file, |
char *filename, char *prefix, char **out_filename); |
void ad_print_statistics(void); |
acpi_status ad_find_dsdt(u8 **dsdt_ptr, u32 *dsdt_length); |
void ad_dump_tables(void); |
acpi_status ad_get_local_tables(void); |
acpi_status |
ad_parse_table(struct acpi_table_header *table, |
acpi_owner_id * owner_id, u8 load_table, u8 external); |
acpi_status ad_display_tables(char *filename, struct acpi_table_header *table); |
acpi_status ad_display_statistics(void); |
/* |
* adwalk |
*/ |
void |
acpi_dm_cross_reference_namespace(union acpi_parse_object *parse_tree_root, |
struct acpi_namespace_node *namespace_root, |
acpi_owner_id owner_id); |
void acpi_dm_dump_tree(union acpi_parse_object *origin); |
void acpi_dm_find_orphan_methods(union acpi_parse_object *origin); |
void |
acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root, |
struct acpi_namespace_node *namespace_root, |
acpi_owner_id owner_id); |
void |
acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root, |
struct acpi_namespace_node *namespace_root); |
/* |
* adfile |
*/ |
acpi_status ad_initialize(void); |
char *fl_generate_filename(char *input_filename, char *suffix); |
acpi_status |
fl_split_input_pathname(char *input_path, |
char **out_directory_path, char **out_filename); |
char *ad_generate_filename(char *prefix, char *table_id); |
void |
ad_write_table(struct acpi_table_header *table, |
u32 length, char *table_name, char *oem_table_id); |
#endif |
#endif /* _ACAPPS */ |
/drivers/acpi/acpica/accommon.h |
---|
0,0 → 1,66 |
/****************************************************************************** |
* |
* Name: accommon.h - Common include files for generation of ACPICA source |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACCOMMON_H__ |
#define __ACCOMMON_H__ |
/* |
* Common set of includes for all ACPICA source files. |
* We put them here because we don't want to duplicate them |
* in the the source code again and again. |
* |
* Note: The order of these include files is important. |
*/ |
#include <acpi/acconfig.h> /* Global configuration constants */ |
#include "acmacros.h" /* C macros */ |
#include "aclocal.h" /* Internal data types */ |
#include "acobject.h" /* ACPI internal object */ |
#include "acstruct.h" /* Common structures */ |
#include "acglobal.h" /* All global variables */ |
#include "achware.h" /* Hardware defines and interfaces */ |
#include "acutils.h" /* Utility interfaces */ |
#ifndef ACPI_USE_SYSTEM_CLIBRARY |
#include "acclib.h" /* C library interfaces */ |
#endif /* !ACPI_USE_SYSTEM_CLIBRARY */ |
#endif /* __ACCOMMON_H__ */ |
/drivers/acpi/acpica/acdebug.h |
---|
0,0 → 1,302 |
/****************************************************************************** |
* |
* Name: acdebug.h - ACPI/AML debugger |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACDEBUG_H__ |
#define __ACDEBUG_H__ |
/* The debugger is used in conjunction with the disassembler most of time */ |
#ifdef ACPI_DISASSEMBLER |
#include "acdisasm.h" |
#endif |
#define ACPI_DEBUG_BUFFER_SIZE 0x4000 /* 16K buffer for return objects */ |
struct acpi_db_command_info { |
char *name; /* Command Name */ |
u8 min_args; /* Minimum arguments required */ |
}; |
struct acpi_db_command_help { |
u8 line_count; /* Number of help lines */ |
char *invocation; /* Command Invocation */ |
char *description; /* Command Description */ |
}; |
struct acpi_db_argument_info { |
char *name; /* Argument Name */ |
}; |
struct acpi_db_execute_walk { |
u32 count; |
u32 max_count; |
}; |
#define PARAM_LIST(pl) pl |
#define EX_NO_SINGLE_STEP 1 |
#define EX_SINGLE_STEP 2 |
/* |
* dbxface - external debugger interfaces |
*/ |
acpi_status |
acpi_db_single_step(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, u32 op_type); |
/* |
* dbcmds - debug commands and output routines |
*/ |
struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string); |
void acpi_db_display_table_info(char *table_arg); |
void acpi_db_display_template(char *buffer_arg); |
void acpi_db_unload_acpi_table(char *name); |
void acpi_db_send_notify(char *name, u32 value); |
void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg); |
acpi_status acpi_db_sleep(char *object_arg); |
void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg); |
void acpi_db_display_locks(void); |
void acpi_db_display_resources(char *object_arg); |
ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_display_gpes(void)) |
void acpi_db_display_handlers(void); |
ACPI_HW_DEPENDENT_RETURN_VOID(void |
acpi_db_generate_gpe(char *gpe_arg, |
char *block_arg)) |
ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_sci(void)) |
void acpi_db_execute_test(char *type_arg); |
/* |
* dbconvert - miscellaneous conversion routines |
*/ |
acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value); |
acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object); |
acpi_status |
acpi_db_convert_to_object(acpi_object_type type, |
char *string, union acpi_object *object); |
u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info); |
void acpi_db_dump_pld_buffer(union acpi_object *obj_desc); |
/* |
* dbmethod - control method commands |
*/ |
void |
acpi_db_set_method_breakpoint(char *location, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op); |
void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg); |
acpi_status acpi_db_disassemble_method(char *name); |
void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op); |
void acpi_db_batch_execute(char *count_arg); |
/* |
* dbnames - namespace commands |
*/ |
void acpi_db_set_scope(char *name); |
void acpi_db_dump_namespace(char *start_arg, char *depth_arg); |
void acpi_db_dump_namespace_paths(void); |
void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg); |
acpi_status acpi_db_find_name_in_namespace(char *name_arg); |
void acpi_db_check_predefined_names(void); |
acpi_status |
acpi_db_display_objects(char *obj_type_arg, char *display_count_arg); |
void acpi_db_check_integrity(void); |
void acpi_db_find_references(char *object_arg); |
void acpi_db_get_bus_info(void); |
/* |
* dbdisply - debug display commands |
*/ |
void acpi_db_display_method_info(union acpi_parse_object *op); |
void acpi_db_decode_and_display_object(char *target, char *output_type); |
void |
acpi_db_display_result_object(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
acpi_status acpi_db_display_all_methods(char *display_count_arg); |
void acpi_db_display_arguments(void); |
void acpi_db_display_locals(void); |
void acpi_db_display_results(void); |
void acpi_db_display_calling_tree(void); |
void acpi_db_display_object_type(char *object_arg); |
void |
acpi_db_display_argument_object(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
/* |
* dbexec - debugger control method execution |
*/ |
void |
acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags); |
void |
acpi_db_create_execution_threads(char *num_threads_arg, |
char *num_loops_arg, char *method_name_arg); |
void acpi_db_delete_objects(u32 count, union acpi_object *objects); |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
u32 acpi_db_get_cache_info(struct acpi_memory_list *cache); |
#endif |
/* |
* dbfileio - Debugger file I/O commands |
*/ |
acpi_object_type |
acpi_db_match_argument(char *user_argument, |
struct acpi_db_argument_info *arguments); |
void acpi_db_close_debug_file(void); |
void acpi_db_open_debug_file(char *name); |
acpi_status acpi_db_load_acpi_table(char *filename); |
acpi_status |
acpi_db_get_table_from_file(char *filename, |
struct acpi_table_header **table, |
u8 must_be_aml_table); |
/* |
* dbhistry - debugger HISTORY command |
*/ |
void acpi_db_add_to_history(char *command_line); |
void acpi_db_display_history(void); |
char *acpi_db_get_from_history(char *command_num_arg); |
char *acpi_db_get_history_by_index(u32 commandd_num); |
/* |
* dbinput - user front-end to the AML debugger |
*/ |
acpi_status |
acpi_db_command_dispatch(char *input_buffer, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context); |
acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op); |
char *acpi_db_get_next_token(char *string, |
char **next, acpi_object_type * return_type); |
/* |
* dbobject |
*/ |
void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc); |
void |
acpi_db_display_internal_object(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
void acpi_db_decode_arguments(struct acpi_walk_state *walk_state); |
void acpi_db_decode_locals(struct acpi_walk_state *walk_state); |
void |
acpi_db_dump_method_info(acpi_status status, |
struct acpi_walk_state *walk_state); |
/* |
* dbstats - Generation and display of ACPI table statistics |
*/ |
void acpi_db_generate_statistics(union acpi_parse_object *root, u8 is_method); |
acpi_status acpi_db_display_statistics(char *type_arg); |
/* |
* dbutils - AML debugger utilities |
*/ |
void acpi_db_set_output_destination(u32 where); |
void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level); |
void acpi_db_prep_namestring(char *name); |
struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name); |
void acpi_db_uint32_to_hex_string(u32 value, char *buffer); |
#endif /* __ACDEBUG_H__ */ |
/drivers/acpi/acpica/acdispat.h |
---|
0,0 → 1,365 |
/****************************************************************************** |
* |
* Name: acdispat.h - dispatcher (parser to interpreter interface) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef _ACDISPAT_H_ |
#define _ACDISPAT_H_ |
#define NAMEOF_LOCAL_NTE "__L0" |
#define NAMEOF_ARG_NTE "__A0" |
/* |
* dsargs - execution of dynamic arguments for static objects |
*/ |
acpi_status |
acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc); |
acpi_status |
acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc); |
acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *rgn_desc); |
acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc); |
acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc); |
/* |
* dscontrol - support for execution control opcodes |
*/ |
acpi_status |
acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
acpi_status |
acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
/* |
* dsopcode - support for late operand evaluation |
*/ |
acpi_status |
acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
acpi_status |
acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
acpi_status |
acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
acpi_status |
acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
union acpi_operand_object *obj_desc); |
acpi_status |
acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
acpi_status acpi_ds_initialize_region(acpi_handle obj_handle); |
/* |
* dsexec - Parser/Interpreter interface, method execution callbacks |
*/ |
acpi_status |
acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, |
union acpi_operand_object *result_obj); |
acpi_status |
acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object **out_op); |
acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *state); |
/* |
* dsfield - Parser/Interpreter interface for AML fields |
*/ |
acpi_status |
acpi_ds_create_field(union acpi_parse_object *op, |
struct acpi_namespace_node *region_node, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_create_bank_field(union acpi_parse_object *op, |
struct acpi_namespace_node *region_node, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_create_index_field(union acpi_parse_object *op, |
struct acpi_namespace_node *region_node, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_create_buffer_field(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_init_field_objects(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state); |
/* |
* dsload - Parser/Interpreter interface |
*/ |
acpi_status |
acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number); |
/* dsload - pass 1 namespace load callbacks */ |
acpi_status |
acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object **out_op); |
acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state); |
/* dsload - pass 2 namespace load callbacks */ |
acpi_status |
acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object **out_op); |
acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state); |
/* |
* dsmthdat - method data (locals/args) |
*/ |
acpi_status |
acpi_ds_store_object_to_local(u8 type, |
u32 index, |
union acpi_operand_object *src_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_method_data_get_entry(u16 opcode, |
u32 index, |
struct acpi_walk_state *walk_state, |
union acpi_operand_object ***node); |
void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state); |
u8 acpi_ds_is_method_value(union acpi_operand_object *obj_desc); |
acpi_status |
acpi_ds_method_data_get_value(u8 type, |
u32 index, |
struct acpi_walk_state *walk_state, |
union acpi_operand_object **dest_desc); |
acpi_status |
acpi_ds_method_data_init_args(union acpi_operand_object **params, |
u32 max_param_count, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_method_data_get_node(u8 type, |
u32 index, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node **node); |
void acpi_ds_method_data_init(struct acpi_walk_state *walk_state); |
/* |
* dsmethod - Parser/Interpreter interface - control method parsing |
*/ |
acpi_status |
acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, |
union acpi_operand_object *obj_desc); |
acpi_status |
acpi_ds_call_control_method(struct acpi_thread_state *thread, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
acpi_status |
acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, |
union acpi_operand_object *return_desc); |
void |
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state); |
/* |
* dsinit |
*/ |
acpi_status |
acpi_ds_initialize_objects(u32 table_index, |
struct acpi_namespace_node *start_node); |
/* |
* dsobject - Parser/Interpreter interface - object initialization and conversion |
*/ |
acpi_status |
acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
u32 buffer_length, |
union acpi_operand_object **obj_desc_ptr); |
acpi_status |
acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
u32 package_length, |
union acpi_operand_object **obj_desc); |
acpi_status |
acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
u16 opcode, union acpi_operand_object **obj_desc); |
acpi_status |
acpi_ds_create_node(struct acpi_walk_state *walk_state, |
struct acpi_namespace_node *node, |
union acpi_parse_object *op); |
/* |
* dsutils - Parser/Interpreter interface utility routines |
*/ |
void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state); |
u8 |
acpi_ds_do_implicit_return(union acpi_operand_object *return_desc, |
struct acpi_walk_state *walk_state, |
u8 add_reference); |
u8 |
acpi_ds_is_result_used(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state); |
void |
acpi_ds_delete_result_if_not_used(union acpi_parse_object *op, |
union acpi_operand_object *result_obj, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_create_operand(struct acpi_walk_state *walk_state, |
union acpi_parse_object *arg, u32 args_remaining); |
acpi_status |
acpi_ds_create_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *first_arg); |
acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state); |
void acpi_ds_clear_operands(struct acpi_walk_state *walk_state); |
acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state); |
/* |
* dswscope - Scope Stack manipulation |
*/ |
acpi_status |
acpi_ds_scope_stack_push(struct acpi_namespace_node *node, |
acpi_object_type type, |
struct acpi_walk_state *walk_state); |
acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state); |
void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state); |
/* |
* dswstate - parser WALK_STATE management routines |
*/ |
acpi_status |
acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state); |
struct acpi_walk_state * acpi_ds_create_walk_state(acpi_owner_id owner_id, |
union acpi_parse_object |
*origin, |
union acpi_operand_object |
*mth_desc, |
struct acpi_thread_state |
*thread); |
acpi_status |
acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
struct acpi_namespace_node *method_node, |
u8 * aml_start, |
u32 aml_length, |
struct acpi_evaluate_info *info, u8 pass_number); |
void |
acpi_ds_obj_stack_pop_and_delete(u32 pop_count, |
struct acpi_walk_state *walk_state); |
void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state); |
struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state |
*thread); |
void |
acpi_ds_push_walk_state(struct acpi_walk_state *walk_state, |
struct acpi_thread_state *thread); |
acpi_status acpi_ds_result_stack_clear(struct acpi_walk_state *walk_state); |
struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state |
*thread); |
acpi_status |
acpi_ds_result_pop(union acpi_operand_object **object, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ds_result_push(union acpi_operand_object *object, |
struct acpi_walk_state *walk_state); |
/* |
* dsdebug - parser debugging routines |
*/ |
void |
acpi_ds_dump_method_stack(acpi_status status, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
#endif /* _ACDISPAT_H_ */ |
/drivers/acpi/acpica/acevents.h |
---|
0,0 → 1,253 |
/****************************************************************************** |
* |
* Name: acevents.h - Event subcomponent prototypes and defines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACEVENTS_H__ |
#define __ACEVENTS_H__ |
/* |
* evevent |
*/ |
acpi_status acpi_ev_initialize_events(void); |
acpi_status acpi_ev_install_xrupt_handlers(void); |
u32 acpi_ev_fixed_event_detect(void); |
/* |
* evmisc |
*/ |
u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node); |
u32 acpi_ev_get_gpe_number_index(u32 gpe_number); |
acpi_status |
acpi_ev_queue_notify_request(struct acpi_namespace_node *node, |
u32 notify_value); |
/* |
* evglock - Global Lock support |
*/ |
acpi_status acpi_ev_init_global_lock_handler(void); |
ACPI_HW_DEPENDENT_RETURN_OK(acpi_status |
acpi_ev_acquire_global_lock(u16 timeout)) |
ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_ev_release_global_lock(void)) |
acpi_status acpi_ev_remove_global_lock_handler(void); |
/* |
* evgpe - Low-level GPE support |
*/ |
u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list); |
acpi_status |
acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info); |
acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); |
acpi_status |
acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); |
acpi_status |
acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); |
struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, |
u32 gpe_number); |
struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number, |
struct acpi_gpe_block_info |
*gpe_block); |
acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info); |
/* |
* evgpeblk - Upper-level GPE block support |
*/ |
acpi_status |
acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, |
u64 address, |
u8 space_id, |
u32 register_count, |
u16 gpe_block_base_number, |
u32 interrupt_number, |
struct acpi_gpe_block_info **return_gpe_block); |
acpi_status |
acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *context); |
ACPI_HW_DEPENDENT_RETURN_OK(acpi_status |
acpi_ev_delete_gpe_block(struct acpi_gpe_block_info |
*gpe_block)) |
u32 |
acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, |
struct acpi_gpe_event_info *gpe_event_info, |
u32 gpe_number); |
/* |
* evgpeinit - GPE initialization and update |
*/ |
acpi_status acpi_ev_gpe_initialize(void); |
ACPI_HW_DEPENDENT_RETURN_VOID(void |
acpi_ev_update_gpes(acpi_owner_id table_owner_id)) |
acpi_status |
acpi_ev_match_gpe_method(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
/* |
* evgpeutil - GPE utilities |
*/ |
acpi_status |
acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context); |
acpi_status |
acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, void *context); |
acpi_status |
acpi_ev_get_gpe_xrupt_block(u32 interrupt_number, |
struct acpi_gpe_xrupt_info **gpe_xrupt_block); |
acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt); |
acpi_status |
acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *context); |
/* |
* evhandler - Address space handling |
*/ |
u8 |
acpi_ev_has_default_handler(struct acpi_namespace_node *node, |
acpi_adr_space_type space_id); |
acpi_status acpi_ev_install_region_handlers(void); |
acpi_status |
acpi_ev_install_space_handler(struct acpi_namespace_node *node, |
acpi_adr_space_type space_id, |
acpi_adr_space_handler handler, |
acpi_adr_space_setup setup, void *context); |
/* |
* evregion - Operation region support |
*/ |
acpi_status acpi_ev_initialize_op_regions(void); |
acpi_status |
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, |
union acpi_operand_object *field_obj, |
u32 function, |
u32 region_offset, u32 bit_width, u64 *value); |
acpi_status |
acpi_ev_attach_region(union acpi_operand_object *handler_obj, |
union acpi_operand_object *region_obj, |
u8 acpi_ns_is_locked); |
void |
acpi_ev_detach_region(union acpi_operand_object *region_obj, |
u8 acpi_ns_is_locked); |
acpi_status |
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, |
acpi_adr_space_type space_id); |
acpi_status |
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function); |
/* |
* evregini - Region initialization and setup |
*/ |
acpi_status |
acpi_ev_system_memory_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, |
void **region_context); |
acpi_status |
acpi_ev_io_space_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context); |
acpi_status |
acpi_ev_pci_config_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context); |
acpi_status |
acpi_ev_cmos_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context); |
acpi_status |
acpi_ev_pci_bar_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context); |
acpi_status |
acpi_ev_default_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context); |
acpi_status |
acpi_ev_initialize_region(union acpi_operand_object *region_obj, |
u8 acpi_ns_locked); |
/* |
* evsci - SCI (System Control Interrupt) handling/dispatch |
*/ |
u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context); |
u32 acpi_ev_sci_dispatch(void); |
u32 acpi_ev_install_sci_handler(void); |
acpi_status acpi_ev_remove_all_sci_handlers(void); |
ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_ev_terminate(void)) |
#endif /* __ACEVENTS_H__ */ |
/drivers/acpi/acpica/acglobal.h |
---|
0,0 → 1,395 |
/****************************************************************************** |
* |
* Name: acglobal.h - Declarations for global variables |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACGLOBAL_H__ |
#define __ACGLOBAL_H__ |
/***************************************************************************** |
* |
* Globals related to the ACPI tables |
* |
****************************************************************************/ |
/* Master list of all ACPI tables that were found in the RSDT/XSDT */ |
ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list); |
/* DSDT information. Used to check for DSDT corruption */ |
ACPI_GLOBAL(struct acpi_table_header *, acpi_gbl_DSDT); |
ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header); |
ACPI_INIT_GLOBAL(u32, acpi_gbl_dsdt_index, ACPI_INVALID_TABLE_INDEX); |
ACPI_INIT_GLOBAL(u32, acpi_gbl_facs_index, ACPI_INVALID_TABLE_INDEX); |
ACPI_INIT_GLOBAL(u32, acpi_gbl_xfacs_index, ACPI_INVALID_TABLE_INDEX); |
ACPI_INIT_GLOBAL(u32, acpi_gbl_fadt_index, ACPI_INVALID_TABLE_INDEX); |
#if (!ACPI_REDUCED_HARDWARE) |
ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS); |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/* These addresses are calculated from the FADT Event Block addresses */ |
ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_status); |
ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_enable); |
ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_status); |
ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_enable); |
/* |
* Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is |
* determined by the revision of the DSDT: If the DSDT revision is less than |
* 2, use only the lower 32 bits of the internal 64-bit Integer. |
*/ |
ACPI_GLOBAL(u8, acpi_gbl_integer_bit_width); |
ACPI_GLOBAL(u8, acpi_gbl_integer_byte_width); |
ACPI_GLOBAL(u8, acpi_gbl_integer_nybble_width); |
/***************************************************************************** |
* |
* Mutual exclusion within ACPICA subsystem |
* |
****************************************************************************/ |
/* |
* Predefined mutex objects. This array contains the |
* actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. |
* (The table maps local handles to the real OS handles) |
*/ |
ACPI_GLOBAL(struct acpi_mutex_info, acpi_gbl_mutex_info[ACPI_NUM_MUTEX]); |
/* |
* Global lock mutex is an actual AML mutex object |
* Global lock semaphore works in conjunction with the actual global lock |
* Global lock spinlock is used for "pending" handshake |
*/ |
ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_global_lock_mutex); |
ACPI_GLOBAL(acpi_semaphore, acpi_gbl_global_lock_semaphore); |
ACPI_GLOBAL(acpi_spinlock, acpi_gbl_global_lock_pending_lock); |
ACPI_GLOBAL(u16, acpi_gbl_global_lock_handle); |
ACPI_GLOBAL(u8, acpi_gbl_global_lock_acquired); |
ACPI_GLOBAL(u8, acpi_gbl_global_lock_present); |
ACPI_GLOBAL(u8, acpi_gbl_global_lock_pending); |
/* |
* Spinlocks are used for interfaces that can be possibly called at |
* interrupt level |
*/ |
ACPI_GLOBAL(acpi_spinlock, acpi_gbl_gpe_lock); /* For GPE data structs and registers */ |
ACPI_GLOBAL(acpi_spinlock, acpi_gbl_hardware_lock); /* For ACPI H/W except GPE registers */ |
ACPI_GLOBAL(acpi_spinlock, acpi_gbl_reference_count_lock); |
/* Mutex for _OSI support */ |
ACPI_GLOBAL(acpi_mutex, acpi_gbl_osi_mutex); |
/* Reader/Writer lock is used for namespace walk and dynamic table unload */ |
ACPI_GLOBAL(struct acpi_rw_lock, acpi_gbl_namespace_rw_lock); |
/***************************************************************************** |
* |
* Miscellaneous globals |
* |
****************************************************************************/ |
/* Object caches */ |
ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_namespace_cache); |
ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_state_cache); |
ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_cache); |
ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_ext_cache); |
ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_operand_cache); |
/* System */ |
ACPI_INIT_GLOBAL(u32, acpi_gbl_startup_flags, 0); |
ACPI_INIT_GLOBAL(u8, acpi_gbl_shutdown, TRUE); |
/* Global handlers */ |
ACPI_GLOBAL(struct acpi_global_notify_handler, acpi_gbl_global_notify[2]); |
ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler); |
ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler); |
ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler); |
ACPI_GLOBAL(void *, acpi_gbl_table_handler_context); |
ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler); |
ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list); |
/* Owner ID support */ |
ACPI_GLOBAL(u32, acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS]); |
ACPI_GLOBAL(u8, acpi_gbl_last_owner_id_index); |
ACPI_GLOBAL(u8, acpi_gbl_next_owner_id_offset); |
/* Initialization sequencing */ |
ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed); |
/* Misc */ |
ACPI_GLOBAL(u32, acpi_gbl_original_mode); |
ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count); |
ACPI_GLOBAL(u32, acpi_gbl_ps_find_count); |
ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save); |
ACPI_GLOBAL(u8, acpi_gbl_debugger_configuration); |
ACPI_GLOBAL(u8, acpi_gbl_step_to_next_call); |
ACPI_GLOBAL(u8, acpi_gbl_acpi_hardware_present); |
ACPI_GLOBAL(u8, acpi_gbl_events_initialized); |
ACPI_GLOBAL(struct acpi_interface_info *, acpi_gbl_supported_interfaces); |
ACPI_GLOBAL(struct acpi_address_range *, |
acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]); |
/* Other miscellaneous, declared and initialized in utglobal */ |
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; |
extern const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS]; |
extern const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS]; |
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; |
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
/* Lists for tracking memory allocations (debug only) */ |
ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_global_list); |
ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_ns_node_list); |
ACPI_GLOBAL(u8, acpi_gbl_display_final_mem_stats); |
ACPI_GLOBAL(u8, acpi_gbl_disable_mem_tracking); |
#endif |
/***************************************************************************** |
* |
* Namespace globals |
* |
****************************************************************************/ |
#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) |
#define NUM_PREDEFINED_NAMES 10 |
#else |
#define NUM_PREDEFINED_NAMES 9 |
#endif |
ACPI_GLOBAL(struct acpi_namespace_node, acpi_gbl_root_node_struct); |
ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_root_node); |
ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_fadt_gpe_device); |
ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_module_code_list); |
extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES]; |
extern const struct acpi_predefined_names |
acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES]; |
#ifdef ACPI_DEBUG_OUTPUT |
ACPI_GLOBAL(u32, acpi_gbl_current_node_count); |
ACPI_GLOBAL(u32, acpi_gbl_current_node_size); |
ACPI_GLOBAL(u32, acpi_gbl_max_concurrent_node_count); |
ACPI_GLOBAL(acpi_size *, acpi_gbl_entry_stack_pointer); |
ACPI_GLOBAL(acpi_size *, acpi_gbl_lowest_stack_pointer); |
ACPI_GLOBAL(u32, acpi_gbl_deepest_nesting); |
ACPI_INIT_GLOBAL(u32, acpi_gbl_nesting_level, 0); |
#endif |
/***************************************************************************** |
* |
* Interpreter globals |
* |
****************************************************************************/ |
ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list); |
/* Maximum number of While() loop iterations before forced abort */ |
ACPI_GLOBAL(u16, acpi_gbl_max_loop_iterations); |
/* Control method single step flag */ |
ACPI_GLOBAL(u8, acpi_gbl_cm_single_step); |
/***************************************************************************** |
* |
* Hardware globals |
* |
****************************************************************************/ |
extern struct acpi_bit_register_info |
acpi_gbl_bit_register_info[ACPI_NUM_BITREG]; |
ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a); |
ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b); |
/***************************************************************************** |
* |
* Event and GPE globals |
* |
****************************************************************************/ |
#if (!ACPI_REDUCED_HARDWARE) |
ACPI_GLOBAL(u8, acpi_gbl_all_gpes_initialized); |
ACPI_GLOBAL(struct acpi_gpe_xrupt_info *, acpi_gbl_gpe_xrupt_list_head); |
ACPI_GLOBAL(struct acpi_gpe_block_info *, |
acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]); |
ACPI_GLOBAL(acpi_gbl_event_handler, acpi_gbl_global_event_handler); |
ACPI_GLOBAL(void *, acpi_gbl_global_event_handler_context); |
ACPI_GLOBAL(struct acpi_fixed_event_handler, |
acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]); |
extern struct acpi_fixed_event_info |
acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS]; |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/***************************************************************************** |
* |
* Debug support |
* |
****************************************************************************/ |
/* Event counters */ |
ACPI_GLOBAL(u32, acpi_method_count); |
ACPI_GLOBAL(u32, acpi_gpe_count); |
ACPI_GLOBAL(u32, acpi_sci_count); |
ACPI_GLOBAL(u32, acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]); |
/* Support for dynamic control method tracing mechanism */ |
ACPI_GLOBAL(u32, acpi_gbl_original_dbg_level); |
ACPI_GLOBAL(u32, acpi_gbl_original_dbg_layer); |
/***************************************************************************** |
* |
* Debugger and Disassembler globals |
* |
****************************************************************************/ |
ACPI_INIT_GLOBAL(u8, acpi_gbl_db_output_flags, ACPI_DB_CONSOLE_OUTPUT); |
#ifdef ACPI_DISASSEMBLER |
/* Do not disassemble buffers to resource descriptors */ |
ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE); |
ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE); |
ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE); |
ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); |
ACPI_INIT_GLOBAL(u8, acpi_gbl_dm_opt_verbose, TRUE); |
ACPI_GLOBAL(u8, acpi_gbl_dm_opt_disasm); |
ACPI_GLOBAL(u8, acpi_gbl_dm_opt_listing); |
ACPI_GLOBAL(u8, acpi_gbl_num_external_methods); |
ACPI_GLOBAL(u32, acpi_gbl_resolved_external_methods); |
ACPI_GLOBAL(struct acpi_external_list *, acpi_gbl_external_list); |
ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list); |
#endif |
#ifdef ACPI_DEBUGGER |
ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE); |
ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE); |
ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID); |
ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods); |
ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support); |
ACPI_GLOBAL(u8, acpi_gbl_db_output_to_file); |
ACPI_GLOBAL(char *, acpi_gbl_db_buffer); |
ACPI_GLOBAL(char *, acpi_gbl_db_filename); |
ACPI_GLOBAL(u32, acpi_gbl_db_debug_level); |
ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level); |
ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node); |
ACPI_GLOBAL(u8, acpi_gbl_db_terminate_loop); |
ACPI_GLOBAL(u8, acpi_gbl_db_threads_terminated); |
ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]); |
ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]); |
/* These buffers should all be the same size */ |
ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]); |
ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]); |
ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]); |
ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]); |
/* |
* Statistic globals |
*/ |
ACPI_GLOBAL(u16, acpi_gbl_obj_type_count[ACPI_TOTAL_TYPES]); |
ACPI_GLOBAL(u16, acpi_gbl_node_type_count[ACPI_TOTAL_TYPES]); |
ACPI_GLOBAL(u16, acpi_gbl_obj_type_count_misc); |
ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc); |
ACPI_GLOBAL(u32, acpi_gbl_num_nodes); |
ACPI_GLOBAL(u32, acpi_gbl_num_objects); |
ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_ready); |
ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_complete); |
#endif /* ACPI_DEBUGGER */ |
/***************************************************************************** |
* |
* Application globals |
* |
****************************************************************************/ |
#ifdef ACPI_APPLICATION |
ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL); |
ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_output_file, NULL); |
/* Print buffer */ |
ACPI_GLOBAL(acpi_spinlock, acpi_gbl_print_lock); /* For print buffer */ |
ACPI_GLOBAL(char, acpi_gbl_print_buffer[1024]); |
#endif /* ACPI_APPLICATION */ |
/***************************************************************************** |
* |
* Info/help support |
* |
****************************************************************************/ |
extern const struct ah_predefined_name asl_predefined_info[]; |
extern const struct ah_device_id asl_device_ids[]; |
#endif /* __ACGLOBAL_H__ */ |
/drivers/acpi/acpica/achware.h |
---|
0,0 → 1,150 |
/****************************************************************************** |
* |
* Name: achware.h -- hardware specific interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACHWARE_H__ |
#define __ACHWARE_H__ |
/* Values for the _SST predefined method */ |
#define ACPI_SST_INDICATOR_OFF 0 |
#define ACPI_SST_WORKING 1 |
#define ACPI_SST_WAKING 2 |
#define ACPI_SST_SLEEPING 3 |
#define ACPI_SST_SLEEP_CONTEXT 4 |
/* |
* hwacpi - high level functions |
*/ |
acpi_status acpi_hw_set_mode(u32 mode); |
u32 acpi_hw_get_mode(void); |
/* |
* hwregs - ACPI Register I/O |
*/ |
acpi_status |
acpi_hw_validate_register(struct acpi_generic_address *reg, |
u8 max_bit_width, u64 *address); |
acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg); |
acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg); |
struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id); |
acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control); |
acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value); |
acpi_status acpi_hw_register_write(u32 register_id, u32 value); |
acpi_status acpi_hw_clear_acpi_status(void); |
/* |
* hwsleep - sleep/wake support (Legacy sleep registers) |
*/ |
acpi_status acpi_hw_legacy_sleep(u8 sleep_state); |
acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state); |
acpi_status acpi_hw_legacy_wake(u8 sleep_state); |
/* |
* hwesleep - sleep/wake support (Extended FADT-V5 sleep registers) |
*/ |
void acpi_hw_execute_sleep_method(char *method_name, u32 integer_argument); |
acpi_status acpi_hw_extended_sleep(u8 sleep_state); |
acpi_status acpi_hw_extended_wake_prep(u8 sleep_state); |
acpi_status acpi_hw_extended_wake(u8 sleep_state); |
/* |
* hwvalid - Port I/O with validation |
*/ |
acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width); |
acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width); |
/* |
* hwgpe - GPE support |
*/ |
u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info); |
acpi_status |
acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action); |
acpi_status |
acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, void *context); |
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info *gpe_event_info); |
acpi_status |
acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, void *context); |
acpi_status |
acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, |
acpi_event_status *event_status); |
acpi_status acpi_hw_disable_all_gpes(void); |
acpi_status acpi_hw_enable_all_runtime_gpes(void); |
acpi_status acpi_hw_enable_all_wakeup_gpes(void); |
acpi_status |
acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *context); |
/* |
* hwpci - PCI configuration support |
*/ |
acpi_status |
acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id, |
acpi_handle root_pci_device, acpi_handle pci_region); |
#endif /* __ACHWARE_H__ */ |
/drivers/acpi/acpica/acinterp.h |
---|
0,0 → 1,556 |
/****************************************************************************** |
* |
* Name: acinterp.h - Interpreter subcomponent prototypes and defines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACINTERP_H__ |
#define __ACINTERP_H__ |
#define ACPI_WALK_OPERANDS (&(walk_state->operands [walk_state->num_operands -1])) |
/* Macros for tables used for debug output */ |
#define ACPI_EXD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_operand_object,f) |
#define ACPI_EXD_NSOFFSET(f) (u8) ACPI_OFFSET (struct acpi_namespace_node,f) |
#define ACPI_EXD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_exdump_info)) |
/* |
* If possible, pack the following structures to byte alignment, since we |
* don't care about performance for debug output. Two cases where we cannot |
* pack the structures: |
* |
* 1) Hardware does not support misaligned memory transfers |
* 2) Compiler does not support pointers within packed structures |
*/ |
#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) |
#pragma pack(1) |
#endif |
typedef const struct acpi_exdump_info { |
u8 opcode; |
u8 offset; |
char *name; |
} acpi_exdump_info; |
/* Values for the Opcode field above */ |
#define ACPI_EXD_INIT 0 |
#define ACPI_EXD_TYPE 1 |
#define ACPI_EXD_UINT8 2 |
#define ACPI_EXD_UINT16 3 |
#define ACPI_EXD_UINT32 4 |
#define ACPI_EXD_UINT64 5 |
#define ACPI_EXD_LITERAL 6 |
#define ACPI_EXD_POINTER 7 |
#define ACPI_EXD_ADDRESS 8 |
#define ACPI_EXD_STRING 9 |
#define ACPI_EXD_BUFFER 10 |
#define ACPI_EXD_PACKAGE 11 |
#define ACPI_EXD_FIELD 12 |
#define ACPI_EXD_REFERENCE 13 |
#define ACPI_EXD_LIST 14 /* Operand object list */ |
#define ACPI_EXD_HDLR_LIST 15 /* Address Handler list */ |
#define ACPI_EXD_RGN_LIST 16 /* Region list */ |
#define ACPI_EXD_NODE 17 /* Namespace Node */ |
/* restore default alignment */ |
#pragma pack() |
/* |
* exconvrt - object conversion |
*/ |
acpi_status |
acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, |
union acpi_operand_object **result_desc, u32 flags); |
acpi_status |
acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, |
union acpi_operand_object **result_desc); |
acpi_status |
acpi_ex_convert_to_string(union acpi_operand_object *obj_desc, |
union acpi_operand_object **result_desc, u32 type); |
/* Types for ->String conversion */ |
#define ACPI_EXPLICIT_BYTE_COPY 0x00000000 |
#define ACPI_EXPLICIT_CONVERT_HEX 0x00000001 |
#define ACPI_IMPLICIT_CONVERT_HEX 0x00000002 |
#define ACPI_EXPLICIT_CONVERT_DECIMAL 0x00000003 |
acpi_status |
acpi_ex_convert_to_target_type(acpi_object_type destination_type, |
union acpi_operand_object *source_desc, |
union acpi_operand_object **result_desc, |
struct acpi_walk_state *walk_state); |
/* |
* exdebug - AML debug object |
*/ |
void |
acpi_ex_do_debug_object(union acpi_operand_object *source_desc, |
u32 level, u32 index); |
void |
acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
void |
acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
void |
acpi_ex_start_trace_opcode(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state); |
void |
acpi_ex_stop_trace_opcode(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state); |
void |
acpi_ex_trace_point(acpi_trace_event_type type, |
u8 begin, u8 *aml, char *pathname); |
/* |
* exfield - ACPI AML (p-code) execution - field manipulation |
*/ |
acpi_status |
acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc, |
u32 buffer_length, u32 * datum_count); |
acpi_status |
acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, |
u64 mask, |
u64 field_value, u32 field_datum_byte_offset); |
void |
acpi_ex_get_buffer_datum(u64 *datum, |
void *buffer, |
u32 buffer_length, |
u32 byte_granularity, u32 buffer_offset); |
void |
acpi_ex_set_buffer_datum(u64 merged_datum, |
void *buffer, |
u32 buffer_length, |
u32 byte_granularity, u32 buffer_offset); |
acpi_status |
acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, |
union acpi_operand_object *obj_desc, |
union acpi_operand_object **ret_buffer_desc); |
acpi_status |
acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, |
union acpi_operand_object *obj_desc, |
union acpi_operand_object **result_desc); |
/* |
* exfldio - low level field I/O |
*/ |
acpi_status |
acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, |
void *buffer, u32 buffer_length); |
acpi_status |
acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, |
void *buffer, u32 buffer_length); |
acpi_status |
acpi_ex_access_region(union acpi_operand_object *obj_desc, |
u32 field_datum_byte_offset, u64 *value, u32 read_write); |
/* |
* exmisc - misc support routines |
*/ |
acpi_status |
acpi_ex_get_object_reference(union acpi_operand_object *obj_desc, |
union acpi_operand_object **return_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_concat_template(union acpi_operand_object *obj_desc, |
union acpi_operand_object *obj_desc2, |
union acpi_operand_object **actual_return_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_do_concatenate(union acpi_operand_object *obj_desc, |
union acpi_operand_object *obj_desc2, |
union acpi_operand_object **actual_return_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_do_logical_numeric_op(u16 opcode, |
u64 integer0, u64 integer1, u8 *logical_result); |
acpi_status |
acpi_ex_do_logical_op(u16 opcode, |
union acpi_operand_object *operand0, |
union acpi_operand_object *operand1, u8 *logical_result); |
u64 acpi_ex_do_math_op(u16 opcode, u64 operand0, u64 operand1); |
acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_create_region(u8 * aml_start, |
u32 aml_length, |
u8 region_space, struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_create_method(u8 * aml_start, |
u32 aml_length, struct acpi_walk_state *walk_state); |
/* |
* exconfig - dynamic table load/unload |
*/ |
acpi_status |
acpi_ex_load_op(union acpi_operand_object *obj_desc, |
union acpi_operand_object *target, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_load_table_op(struct acpi_walk_state *walk_state, |
union acpi_operand_object **return_desc); |
acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle); |
/* |
* exmutex - mutex support |
*/ |
acpi_status |
acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_acquire_mutex_object(u16 timeout, |
union acpi_operand_object *obj_desc, |
acpi_thread_id thread_id); |
acpi_status |
acpi_ex_release_mutex(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc); |
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread); |
void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc); |
/* |
* exprep - ACPI AML execution - prep utilities |
*/ |
acpi_status |
acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, |
u8 field_flags, |
u8 field_attribute, |
u32 field_bit_position, u32 field_bit_length); |
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info); |
/* |
* exsystem - Interface to OS services |
*/ |
acpi_status |
acpi_ex_system_do_notify_op(union acpi_operand_object *value, |
union acpi_operand_object *obj_desc); |
acpi_status acpi_ex_system_do_sleep(u64 time); |
acpi_status acpi_ex_system_do_stall(u32 time); |
acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc); |
acpi_status |
acpi_ex_system_wait_event(union acpi_operand_object *time, |
union acpi_operand_object *obj_desc); |
acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc); |
acpi_status |
acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout); |
acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout); |
/* |
* exoparg1 - ACPI AML execution, 1 operand |
*/ |
acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state); |
/* |
* exoparg2 - ACPI AML execution, 2 operands |
*/ |
acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state); |
/* |
* exoparg3 - ACPI AML execution, 3 operands |
*/ |
acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state); |
acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state); |
/* |
* exoparg6 - ACPI AML execution, 6 operands |
*/ |
acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state *walk_state); |
/* |
* exresolv - Object resolution and get value functions |
*/ |
acpi_status |
acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, |
union acpi_operand_object *operand, |
acpi_object_type * return_type, |
union acpi_operand_object **return_desc); |
/* |
* exresnte - resolve namespace node |
*/ |
acpi_status |
acpi_ex_resolve_node_to_value(struct acpi_namespace_node **stack_ptr, |
struct acpi_walk_state *walk_state); |
/* |
* exresop - resolve operand to value |
*/ |
acpi_status |
acpi_ex_resolve_operands(u16 opcode, |
union acpi_operand_object **stack_ptr, |
struct acpi_walk_state *walk_state); |
/* |
* exdump - Interpreter debug output routines |
*/ |
void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth); |
void |
acpi_ex_dump_operands(union acpi_operand_object **operands, |
const char *opcode_name, u32 num_opcodes); |
void |
acpi_ex_dump_object_descriptor(union acpi_operand_object *object, u32 flags); |
void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags); |
/* |
* exnames - AML namestring support |
*/ |
acpi_status |
acpi_ex_get_name_string(acpi_object_type data_type, |
u8 * in_aml_address, |
char **out_name_string, u32 * out_name_length); |
/* |
* exstore - Object store support |
*/ |
acpi_status |
acpi_ex_store(union acpi_operand_object *val_desc, |
union acpi_operand_object *dest_desc, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, |
struct acpi_namespace_node *node, |
struct acpi_walk_state *walk_state, |
u8 implicit_conversion); |
#define ACPI_IMPLICIT_CONVERSION TRUE |
#define ACPI_NO_IMPLICIT_CONVERSION FALSE |
/* |
* exstoren - resolve/store object |
*/ |
acpi_status |
acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, |
acpi_object_type target_type, |
struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ex_store_object_to_object(union acpi_operand_object *source_desc, |
union acpi_operand_object *dest_desc, |
union acpi_operand_object **new_desc, |
struct acpi_walk_state *walk_state); |
/* |
* exstorob - store object - buffer/string |
*/ |
acpi_status |
acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, |
union acpi_operand_object *target_desc); |
acpi_status |
acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, |
union acpi_operand_object *target_desc); |
/* |
* excopy - object copy |
*/ |
acpi_status |
acpi_ex_copy_integer_to_index_field(union acpi_operand_object *source_desc, |
union acpi_operand_object *target_desc); |
acpi_status |
acpi_ex_copy_integer_to_bank_field(union acpi_operand_object *source_desc, |
union acpi_operand_object *target_desc); |
acpi_status |
acpi_ex_copy_data_to_named_field(union acpi_operand_object *source_desc, |
struct acpi_namespace_node *node); |
acpi_status |
acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc, |
union acpi_operand_object *target_desc); |
/* |
* exutils - interpreter/scanner utilities |
*/ |
void acpi_ex_enter_interpreter(void); |
void acpi_ex_exit_interpreter(void); |
u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc); |
void acpi_ex_acquire_global_lock(u32 rule); |
void acpi_ex_release_global_lock(u32 rule); |
void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id); |
void acpi_ex_integer_to_string(char *dest, u64 value); |
void acpi_ex_pci_cls_to_string(char *dest, u8 class_code[3]); |
u8 acpi_is_valid_space_id(u8 space_id); |
/* |
* exregion - default op_region handlers |
*/ |
acpi_status |
acpi_ex_system_memory_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, |
void *region_context); |
acpi_status |
acpi_ex_system_io_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context); |
acpi_status |
acpi_ex_pci_config_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context); |
acpi_status |
acpi_ex_cmos_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context); |
acpi_status |
acpi_ex_pci_bar_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context); |
acpi_status |
acpi_ex_embedded_controller_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, |
void *region_context); |
acpi_status |
acpi_ex_sm_bus_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context); |
acpi_status |
acpi_ex_data_table_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context); |
#endif /* __INTERP_H__ */ |
/drivers/acpi/acpica/aclocal.h |
---|
0,0 → 1,1210 |
/****************************************************************************** |
* |
* Name: aclocal.h - Internal data types used across the ACPI subsystem |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACLOCAL_H__ |
#define __ACLOCAL_H__ |
/* acpisrc:struct_defs -- for acpisrc conversion */ |
#define ACPI_SERIALIZED 0xFF |
typedef u32 acpi_mutex_handle; |
#define ACPI_GLOBAL_LOCK (acpi_semaphore) (-1) |
/* Total number of aml opcodes defined */ |
#define AML_NUM_OPCODES 0x82 |
/* Forward declarations */ |
struct acpi_walk_state; |
struct acpi_obj_mutex; |
union acpi_parse_object; |
/***************************************************************************** |
* |
* Mutex typedefs and structs |
* |
****************************************************************************/ |
/* |
* Predefined handles for the mutex objects used within the subsystem |
* All mutex objects are automatically created by acpi_ut_mutex_initialize. |
* |
* The acquire/release ordering protocol is implied via this list. Mutexes |
* with a lower value must be acquired before mutexes with a higher value. |
* |
* NOTE: any changes here must be reflected in the acpi_gbl_mutex_names |
* table below also! |
*/ |
#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */ |
#define ACPI_MTX_NAMESPACE 1 /* ACPI Namespace */ |
#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */ |
#define ACPI_MTX_EVENTS 3 /* Data for ACPI events */ |
#define ACPI_MTX_CACHES 4 /* Internal caches, general purposes */ |
#define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */ |
#define ACPI_MAX_MUTEX 5 |
#define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1 |
/* Lock structure for reader/writer interfaces */ |
struct acpi_rw_lock { |
acpi_mutex writer_mutex; |
acpi_mutex reader_mutex; |
u32 num_readers; |
}; |
/* |
* Predefined handles for spinlocks used within the subsystem. |
* These spinlocks are created by acpi_ut_mutex_initialize |
*/ |
#define ACPI_LOCK_GPES 0 |
#define ACPI_LOCK_HARDWARE 1 |
#define ACPI_MAX_LOCK 1 |
#define ACPI_NUM_LOCK ACPI_MAX_LOCK+1 |
/* This Thread ID means that the mutex is not in use (unlocked) */ |
#define ACPI_MUTEX_NOT_ACQUIRED (acpi_thread_id) 0 |
/* This Thread ID means an invalid thread ID */ |
#ifdef ACPI_OS_INVALID_THREAD_ID |
#define ACPI_INVALID_THREAD_ID ACPI_OS_INVALID_THREAD_ID |
#else |
#define ACPI_INVALID_THREAD_ID ((acpi_thread_id) 0xFFFFFFFF) |
#endif |
/* Table for the global mutexes */ |
struct acpi_mutex_info { |
acpi_mutex mutex; |
u32 use_count; |
acpi_thread_id thread_id; |
}; |
/* Lock flag parameter for various interfaces */ |
#define ACPI_MTX_DO_NOT_LOCK 0 |
#define ACPI_MTX_LOCK 1 |
/* Field access granularities */ |
#define ACPI_FIELD_BYTE_GRANULARITY 1 |
#define ACPI_FIELD_WORD_GRANULARITY 2 |
#define ACPI_FIELD_DWORD_GRANULARITY 4 |
#define ACPI_FIELD_QWORD_GRANULARITY 8 |
#define ACPI_ENTRY_NOT_FOUND NULL |
/***************************************************************************** |
* |
* Namespace typedefs and structs |
* |
****************************************************************************/ |
/* Operational modes of the AML interpreter/scanner */ |
typedef enum { |
ACPI_IMODE_LOAD_PASS1 = 0x01, |
ACPI_IMODE_LOAD_PASS2 = 0x02, |
ACPI_IMODE_EXECUTE = 0x03 |
} acpi_interpreter_mode; |
/* |
* The Namespace Node describes a named object that appears in the AML. |
* descriptor_type is used to differentiate between internal descriptors. |
* |
* The node is optimized for both 32-bit and 64-bit platforms: |
* 20 bytes for the 32-bit case, 32 bytes for the 64-bit case. |
* |
* Note: The descriptor_type and Type fields must appear in the identical |
* position in both the struct acpi_namespace_node and union acpi_operand_object |
* structures. |
*/ |
struct acpi_namespace_node { |
union acpi_operand_object *object; /* Interpreter object */ |
u8 descriptor_type; /* Differentiate object descriptor types */ |
u8 type; /* ACPI Type associated with this name */ |
u8 flags; /* Miscellaneous flags */ |
acpi_owner_id owner_id; /* Node creator */ |
union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ |
struct acpi_namespace_node *parent; /* Parent node */ |
struct acpi_namespace_node *child; /* First child */ |
struct acpi_namespace_node *peer; /* First peer */ |
/* |
* The following fields are used by the ASL compiler and disassembler only |
*/ |
#ifdef ACPI_LARGE_NAMESPACE_NODE |
union acpi_parse_object *op; |
void *method_locals; |
void *method_args; |
u32 value; |
u32 length; |
u8 arg_count; |
#endif |
}; |
/* Namespace Node flags */ |
#define ANOBJ_RESERVED 0x01 /* Available for use */ |
#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */ |
#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ |
#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ |
#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ |
#define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ |
#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ |
#define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ |
#define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ |
#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* iASL only: Method has at least one return value */ |
#define ANOBJ_IS_REFERENCED 0x80 /* iASL only: Object was referenced */ |
/* Internal ACPI table management - master table list */ |
struct acpi_table_list { |
struct acpi_table_desc *tables; /* Table descriptor array */ |
u32 current_table_count; /* Tables currently in the array */ |
u32 max_table_count; /* Max tables array will hold */ |
u8 flags; |
}; |
/* Flags for above */ |
#define ACPI_ROOT_ORIGIN_UNKNOWN (0) /* ~ORIGIN_ALLOCATED */ |
#define ACPI_ROOT_ORIGIN_ALLOCATED (1) |
#define ACPI_ROOT_ALLOW_RESIZE (2) |
/* Predefined table indexes */ |
#define ACPI_INVALID_TABLE_INDEX (0xFFFFFFFF) |
struct acpi_find_context { |
char *search_for; |
acpi_handle *list; |
u32 *count; |
}; |
struct acpi_ns_search_data { |
struct acpi_namespace_node *node; |
}; |
/* Object types used during package copies */ |
#define ACPI_COPY_TYPE_SIMPLE 0 |
#define ACPI_COPY_TYPE_PACKAGE 1 |
/* Info structure used to convert external<->internal namestrings */ |
struct acpi_namestring_info { |
const char *external_name; |
const char *next_external_char; |
char *internal_name; |
u32 length; |
u32 num_segments; |
u32 num_carats; |
u8 fully_qualified; |
}; |
/* Field creation info */ |
struct acpi_create_field_info { |
struct acpi_namespace_node *region_node; |
struct acpi_namespace_node *field_node; |
struct acpi_namespace_node *register_node; |
struct acpi_namespace_node *data_register_node; |
struct acpi_namespace_node *connection_node; |
u8 *resource_buffer; |
u32 bank_value; |
u32 field_bit_position; |
u32 field_bit_length; |
u16 resource_length; |
u16 pin_number_index; |
u8 field_flags; |
u8 attribute; |
u8 field_type; |
u8 access_length; |
}; |
typedef |
acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state); |
/* |
* Bitmapped ACPI types. Used internally only |
*/ |
#define ACPI_BTYPE_ANY 0x00000000 |
#define ACPI_BTYPE_INTEGER 0x00000001 |
#define ACPI_BTYPE_STRING 0x00000002 |
#define ACPI_BTYPE_BUFFER 0x00000004 |
#define ACPI_BTYPE_PACKAGE 0x00000008 |
#define ACPI_BTYPE_FIELD_UNIT 0x00000010 |
#define ACPI_BTYPE_DEVICE 0x00000020 |
#define ACPI_BTYPE_EVENT 0x00000040 |
#define ACPI_BTYPE_METHOD 0x00000080 |
#define ACPI_BTYPE_MUTEX 0x00000100 |
#define ACPI_BTYPE_REGION 0x00000200 |
#define ACPI_BTYPE_POWER 0x00000400 |
#define ACPI_BTYPE_PROCESSOR 0x00000800 |
#define ACPI_BTYPE_THERMAL 0x00001000 |
#define ACPI_BTYPE_BUFFER_FIELD 0x00002000 |
#define ACPI_BTYPE_DDB_HANDLE 0x00004000 |
#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000 |
#define ACPI_BTYPE_REFERENCE_OBJECT 0x00010000 /* From Index(), ref_of(), etc (type6_opcodes) */ |
#define ACPI_BTYPE_RESOURCE 0x00020000 |
#define ACPI_BTYPE_NAMED_REFERENCE 0x00040000 /* Generic unresolved Name or Namepath */ |
#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER) |
#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE) |
/* Used by Copy, de_ref_of, Store, Printf, Fprintf */ |
#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE_OBJECT | ACPI_BTYPE_DDB_HANDLE) |
#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR) |
#define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */ |
#define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF |
#pragma pack(1) |
/* |
* Information structure for ACPI predefined names. |
* Each entry in the table contains the following items: |
* |
* name - The ACPI reserved name |
* param_count - Number of arguments to the method |
* expected_return_btypes - Allowed type(s) for the return value |
*/ |
struct acpi_name_info { |
char name[ACPI_NAME_SIZE]; |
u16 argument_list; |
u8 expected_btypes; |
}; |
/* |
* Secondary information structures for ACPI predefined objects that return |
* package objects. This structure appears as the next entry in the table |
* after the NAME_INFO structure above. |
* |
* The reason for this is to minimize the size of the predefined name table. |
*/ |
/* |
* Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2, |
* ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT, |
* ACPI_PTYPE2_FIX_VAR |
*/ |
struct acpi_package_info { |
u8 type; |
u8 object_type1; |
u8 count1; |
u8 object_type2; |
u8 count2; |
u16 reserved; |
}; |
/* Used for ACPI_PTYPE2_FIXED */ |
struct acpi_package_info2 { |
u8 type; |
u8 count; |
u8 object_type[4]; |
u8 reserved; |
}; |
/* Used for ACPI_PTYPE1_OPTION */ |
struct acpi_package_info3 { |
u8 type; |
u8 count; |
u8 object_type[2]; |
u8 tail_object_type; |
u16 reserved; |
}; |
struct acpi_package_info4 { |
u8 type; |
u8 object_type1; |
u8 count1; |
u8 sub_object_types; |
u8 pkg_count; |
u16 reserved; |
}; |
union acpi_predefined_info { |
struct acpi_name_info info; |
struct acpi_package_info ret_info; |
struct acpi_package_info2 ret_info2; |
struct acpi_package_info3 ret_info3; |
struct acpi_package_info4 ret_info4; |
}; |
/* Reset to default packing */ |
#pragma pack() |
/* Return object auto-repair info */ |
typedef acpi_status(*acpi_object_converter) (union acpi_operand_object |
*original_object, |
union acpi_operand_object |
**converted_object); |
struct acpi_simple_repair_info { |
char name[ACPI_NAME_SIZE]; |
u32 unexpected_btypes; |
u32 package_index; |
acpi_object_converter object_converter; |
}; |
/* |
* Bitmapped return value types |
* Note: the actual data types must be contiguous, a loop in nspredef.c |
* depends on this. |
*/ |
#define ACPI_RTYPE_ANY 0x00 |
#define ACPI_RTYPE_NONE 0x01 |
#define ACPI_RTYPE_INTEGER 0x02 |
#define ACPI_RTYPE_STRING 0x04 |
#define ACPI_RTYPE_BUFFER 0x08 |
#define ACPI_RTYPE_PACKAGE 0x10 |
#define ACPI_RTYPE_REFERENCE 0x20 |
#define ACPI_RTYPE_ALL 0x3F |
#define ACPI_NUM_RTYPES 5 /* Number of actual object types */ |
/* Info for running the _REG methods */ |
struct acpi_reg_walk_info { |
acpi_adr_space_type space_id; |
u32 reg_run_count; |
}; |
/***************************************************************************** |
* |
* Event typedefs and structs |
* |
****************************************************************************/ |
/* Dispatch info for each host-installed SCI handler */ |
struct acpi_sci_handler_info { |
struct acpi_sci_handler_info *next; |
acpi_sci_handler address; /* Address of handler */ |
void *context; /* Context to be passed to handler */ |
}; |
/* Dispatch info for each GPE -- either a method or handler, cannot be both */ |
struct acpi_gpe_handler_info { |
acpi_gpe_handler address; /* Address of handler, if any */ |
void *context; /* Context to be passed to handler */ |
struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ |
u8 original_flags; /* Original (pre-handler) GPE info */ |
u8 originally_enabled; /* True if GPE was originally enabled */ |
}; |
/* Notify info for implicit notify, multiple device objects */ |
struct acpi_gpe_notify_info { |
struct acpi_namespace_node *device_node; /* Device to be notified */ |
struct acpi_gpe_notify_info *next; |
}; |
/* |
* GPE dispatch info. At any time, the GPE can have at most one type |
* of dispatch - Method, Handler, or Implicit Notify. |
*/ |
union acpi_gpe_dispatch_info { |
struct acpi_namespace_node *method_node; /* Method node for this GPE level */ |
struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ |
struct acpi_gpe_notify_info *notify_list; /* List of _PRW devices for implicit notifies */ |
}; |
/* |
* Information about a GPE, one per each GPE in an array. |
* NOTE: Important to keep this struct as small as possible. |
*/ |
struct acpi_gpe_event_info { |
union acpi_gpe_dispatch_info dispatch; /* Either Method, Handler, or notify_list */ |
struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ |
u8 flags; /* Misc info about this GPE */ |
u8 gpe_number; /* This GPE */ |
u8 runtime_count; /* References to a run GPE */ |
}; |
/* Information about a GPE register pair, one per each status/enable pair in an array */ |
struct acpi_gpe_register_info { |
struct acpi_generic_address status_address; /* Address of status reg */ |
struct acpi_generic_address enable_address; /* Address of enable reg */ |
u16 base_gpe_number; /* Base GPE number for this register */ |
u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ |
u8 enable_for_run; /* GPEs to keep enabled when running */ |
u8 enable_mask; /* Current mask of enabled GPEs */ |
}; |
/* |
* Information about a GPE register block, one per each installed block -- |
* GPE0, GPE1, and one per each installed GPE Block Device. |
*/ |
struct acpi_gpe_block_info { |
struct acpi_namespace_node *node; |
struct acpi_gpe_block_info *previous; |
struct acpi_gpe_block_info *next; |
struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ |
struct acpi_gpe_register_info *register_info; /* One per GPE register pair */ |
struct acpi_gpe_event_info *event_info; /* One for each GPE */ |
u64 address; /* Base address of the block */ |
u32 register_count; /* Number of register pairs in block */ |
u16 gpe_count; /* Number of individual GPEs in block */ |
u16 block_base_number; /* Base GPE number for this block */ |
u8 space_id; |
u8 initialized; /* TRUE if this block is initialized */ |
}; |
/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ |
struct acpi_gpe_xrupt_info { |
struct acpi_gpe_xrupt_info *previous; |
struct acpi_gpe_xrupt_info *next; |
struct acpi_gpe_block_info *gpe_block_list_head; /* List of GPE blocks for this xrupt */ |
u32 interrupt_number; /* System interrupt number */ |
}; |
struct acpi_gpe_walk_info { |
struct acpi_namespace_node *gpe_device; |
struct acpi_gpe_block_info *gpe_block; |
u16 count; |
acpi_owner_id owner_id; |
u8 execute_by_owner_id; |
}; |
struct acpi_gpe_device_info { |
u32 index; |
u32 next_block_base_index; |
acpi_status status; |
struct acpi_namespace_node *gpe_device; |
}; |
typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info * |
gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *context); |
/* Information about each particular fixed event */ |
struct acpi_fixed_event_handler { |
acpi_event_handler handler; /* Address of handler. */ |
void *context; /* Context to be passed to handler */ |
}; |
struct acpi_fixed_event_info { |
u8 status_register_id; |
u8 enable_register_id; |
u16 status_bit_mask; |
u16 enable_bit_mask; |
}; |
/* Information used during field processing */ |
struct acpi_field_info { |
u8 skip_field; |
u8 field_flag; |
u32 pkg_length; |
}; |
/***************************************************************************** |
* |
* Generic "state" object for stacks |
* |
****************************************************************************/ |
#define ACPI_CONTROL_NORMAL 0xC0 |
#define ACPI_CONTROL_CONDITIONAL_EXECUTING 0xC1 |
#define ACPI_CONTROL_PREDICATE_EXECUTING 0xC2 |
#define ACPI_CONTROL_PREDICATE_FALSE 0xC3 |
#define ACPI_CONTROL_PREDICATE_TRUE 0xC4 |
#define ACPI_STATE_COMMON \ |
void *next; \ |
u8 descriptor_type; /* To differentiate various internal objs */\ |
u8 flags; \ |
u16 value; \ |
u16 state; |
/* There are 2 bytes available here until the next natural alignment boundary */ |
struct acpi_common_state { |
ACPI_STATE_COMMON}; |
/* |
* Update state - used to traverse complex objects such as packages |
*/ |
struct acpi_update_state { |
ACPI_STATE_COMMON union acpi_operand_object *object; |
}; |
/* |
* Pkg state - used to traverse nested package structures |
*/ |
struct acpi_pkg_state { |
ACPI_STATE_COMMON u16 index; |
union acpi_operand_object *source_object; |
union acpi_operand_object *dest_object; |
struct acpi_walk_state *walk_state; |
void *this_target_obj; |
u32 num_packages; |
}; |
/* |
* Control state - one per if/else and while constructs. |
* Allows nesting of these constructs |
*/ |
struct acpi_control_state { |
ACPI_STATE_COMMON u16 opcode; |
union acpi_parse_object *predicate_op; |
u8 *aml_predicate_start; /* Start of if/while predicate */ |
u8 *package_end; /* End of if/while block */ |
u32 loop_count; /* While() loop counter */ |
}; |
/* |
* Scope state - current scope during namespace lookups |
*/ |
struct acpi_scope_state { |
ACPI_STATE_COMMON struct acpi_namespace_node *node; |
}; |
struct acpi_pscope_state { |
ACPI_STATE_COMMON u32 arg_count; /* Number of fixed arguments */ |
union acpi_parse_object *op; /* Current op being parsed */ |
u8 *arg_end; /* Current argument end */ |
u8 *pkg_end; /* Current package end */ |
u32 arg_list; /* Next argument to parse */ |
}; |
/* |
* Thread state - one per thread across multiple walk states. Multiple walk |
* states are created when there are nested control methods executing. |
*/ |
struct acpi_thread_state { |
ACPI_STATE_COMMON u8 current_sync_level; /* Mutex Sync (nested acquire) level */ |
struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ |
union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ |
acpi_thread_id thread_id; /* Running thread ID */ |
}; |
/* |
* Result values - used to accumulate the results of nested |
* AML arguments |
*/ |
struct acpi_result_values { |
ACPI_STATE_COMMON |
union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM]; |
}; |
typedef |
acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state, |
union acpi_parse_object ** out_op); |
typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state); |
/* Global handlers for AML Notifies */ |
struct acpi_global_notify_handler { |
acpi_notify_handler handler; |
void *context; |
}; |
/* |
* Notify info - used to pass info to the deferred notify |
* handler/dispatcher. |
*/ |
struct acpi_notify_info { |
ACPI_STATE_COMMON u8 handler_list_id; |
struct acpi_namespace_node *node; |
union acpi_operand_object *handler_list_head; |
struct acpi_global_notify_handler *global; |
}; |
/* Generic state is union of structs above */ |
union acpi_generic_state { |
struct acpi_common_state common; |
struct acpi_control_state control; |
struct acpi_update_state update; |
struct acpi_scope_state scope; |
struct acpi_pscope_state parse_scope; |
struct acpi_pkg_state pkg; |
struct acpi_thread_state thread; |
struct acpi_result_values results; |
struct acpi_notify_info notify; |
}; |
/***************************************************************************** |
* |
* Interpreter typedefs and structs |
* |
****************************************************************************/ |
typedef acpi_status(*acpi_execute_op) (struct acpi_walk_state * walk_state); |
/* Address Range info block */ |
struct acpi_address_range { |
struct acpi_address_range *next; |
struct acpi_namespace_node *region_node; |
acpi_physical_address start_address; |
acpi_physical_address end_address; |
}; |
/***************************************************************************** |
* |
* Parser typedefs and structs |
* |
****************************************************************************/ |
/* |
* AML opcode, name, and argument layout |
*/ |
struct acpi_opcode_info { |
#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) |
char *name; /* Opcode name (disassembler/debug only) */ |
#endif |
u32 parse_args; /* Grammar/Parse time arguments */ |
u32 runtime_args; /* Interpret time arguments */ |
u16 flags; /* Misc flags */ |
u8 object_type; /* Corresponding internal object type */ |
u8 class; /* Opcode class */ |
u8 type; /* Opcode type */ |
}; |
/* Value associated with the parse object */ |
union acpi_parse_value { |
u64 integer; /* Integer constant (Up to 64 bits) */ |
u32 size; /* bytelist or field size */ |
char *string; /* NULL terminated string */ |
u8 *buffer; /* buffer or string */ |
char *name; /* NULL terminated string */ |
union acpi_parse_object *arg; /* arguments and contained ops */ |
}; |
#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) |
#define ACPI_DISASM_ONLY_MEMBERS(a) a; |
#else |
#define ACPI_DISASM_ONLY_MEMBERS(a) |
#endif |
#define ACPI_PARSE_COMMON \ |
union acpi_parse_object *parent; /* Parent op */\ |
u8 descriptor_type; /* To differentiate various internal objs */\ |
u8 flags; /* Type of Op */\ |
u16 aml_opcode; /* AML opcode */\ |
u8 *aml; /* Address of declaration in AML */\ |
union acpi_parse_object *next; /* Next op */\ |
struct acpi_namespace_node *node; /* For use by interpreter */\ |
union acpi_parse_value value; /* Value or args associated with the opcode */\ |
u8 arg_list_length; /* Number of elements in the arg list */\ |
ACPI_DISASM_ONLY_MEMBERS (\ |
u8 disasm_flags; /* Used during AML disassembly */\ |
u8 disasm_opcode; /* Subtype used for disassembly */\ |
char *operator_symbol;/* Used for C-style operator name strings */\ |
char aml_op_name[16]) /* Op name (debug only) */ |
/* Flags for disasm_flags field above */ |
#define ACPI_DASM_BUFFER 0x00 /* Buffer is a simple data buffer */ |
#define ACPI_DASM_RESOURCE 0x01 /* Buffer is a Resource Descriptor */ |
#define ACPI_DASM_STRING 0x02 /* Buffer is a ASCII string */ |
#define ACPI_DASM_UNICODE 0x03 /* Buffer is a Unicode string */ |
#define ACPI_DASM_PLD_METHOD 0x04 /* Buffer is a _PLD method bit-packed buffer */ |
#define ACPI_DASM_UUID 0x05 /* Buffer is a UUID/GUID */ |
#define ACPI_DASM_EISAID 0x06 /* Integer is an EISAID */ |
#define ACPI_DASM_MATCHOP 0x07 /* Parent opcode is a Match() operator */ |
#define ACPI_DASM_LNOT_PREFIX 0x08 /* Start of a Lnot_equal (etc.) pair of opcodes */ |
#define ACPI_DASM_LNOT_SUFFIX 0x09 /* End of a Lnot_equal (etc.) pair of opcodes */ |
#define ACPI_DASM_HID_STRING 0x0A /* String is a _HID or _CID */ |
#define ACPI_DASM_IGNORE 0x0B /* Not used at this time */ |
/* |
* Generic operation (for example: If, While, Store) |
*/ |
struct acpi_parse_obj_common { |
ACPI_PARSE_COMMON}; |
/* |
* Extended Op for named ops (Scope, Method, etc.), deferred ops (Methods and op_regions), |
* and bytelists. |
*/ |
struct acpi_parse_obj_named { |
ACPI_PARSE_COMMON u8 *path; |
u8 *data; /* AML body or bytelist data */ |
u32 length; /* AML length */ |
u32 name; /* 4-byte name or zero if no name */ |
}; |
/* This version is used by the iASL compiler only */ |
#define ACPI_MAX_PARSEOP_NAME 20 |
struct acpi_parse_obj_asl { |
ACPI_PARSE_COMMON union acpi_parse_object *child; |
union acpi_parse_object *parent_method; |
char *filename; |
char *external_name; |
char *namepath; |
char name_seg[4]; |
u32 extra_value; |
u32 column; |
u32 line_number; |
u32 logical_line_number; |
u32 logical_byte_offset; |
u32 end_line; |
u32 end_logical_line; |
u32 acpi_btype; |
u32 aml_length; |
u32 aml_subtree_length; |
u32 final_aml_length; |
u32 final_aml_offset; |
u32 compile_flags; |
u16 parse_opcode; |
u8 aml_opcode_length; |
u8 aml_pkg_len_bytes; |
u8 extra; |
char parse_op_name[ACPI_MAX_PARSEOP_NAME]; |
}; |
union acpi_parse_object { |
struct acpi_parse_obj_common common; |
struct acpi_parse_obj_named named; |
struct acpi_parse_obj_asl asl; |
}; |
/* |
* Parse state - one state per parser invocation and each control |
* method. |
*/ |
struct acpi_parse_state { |
u8 *aml_start; /* First AML byte */ |
u8 *aml; /* Next AML byte */ |
u8 *aml_end; /* (last + 1) AML byte */ |
u8 *pkg_start; /* Current package begin */ |
u8 *pkg_end; /* Current package end */ |
union acpi_parse_object *start_op; /* Root of parse tree */ |
struct acpi_namespace_node *start_node; |
union acpi_generic_state *scope; /* Current scope */ |
union acpi_parse_object *start_scope; |
u32 aml_size; |
}; |
/* Parse object flags */ |
#define ACPI_PARSEOP_GENERIC 0x01 |
#define ACPI_PARSEOP_NAMED 0x02 |
#define ACPI_PARSEOP_DEFERRED 0x04 |
#define ACPI_PARSEOP_BYTELIST 0x08 |
#define ACPI_PARSEOP_IN_STACK 0x10 |
#define ACPI_PARSEOP_TARGET 0x20 |
#define ACPI_PARSEOP_IN_CACHE 0x80 |
/* Parse object disasm_flags */ |
#define ACPI_PARSEOP_IGNORE 0x01 |
#define ACPI_PARSEOP_PARAMLIST 0x02 |
#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04 |
#define ACPI_PARSEOP_PREDEF_CHECKED 0x08 |
#define ACPI_PARSEOP_CLOSING_PAREN 0x10 |
#define ACPI_PARSEOP_COMPOUND 0x20 |
#define ACPI_PARSEOP_ASSIGNMENT 0x40 |
/***************************************************************************** |
* |
* Hardware (ACPI registers) and PNP |
* |
****************************************************************************/ |
struct acpi_bit_register_info { |
u8 parent_register; |
u8 bit_position; |
u16 access_bit_mask; |
}; |
/* |
* Some ACPI registers have bits that must be ignored -- meaning that they |
* must be preserved. |
*/ |
#define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */ |
/* Write-only bits must be zeroed by software */ |
#define ACPI_PM1_CONTROL_WRITEONLY_BITS 0x2004 /* Bits 13, 2 */ |
/* For control registers, both ignored and reserved bits must be preserved */ |
/* |
* For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the |
* ACPI specification to be a "preserved" bit - "OSPM always preserves this |
* bit position", section 4.7.3.2.1. However, on some machines the OS must |
* write a one to this bit after resume for the machine to work properly. |
* To enable this, we no longer attempt to preserve this bit. No machines |
* are known to fail if the bit is not preserved. (May 2009) |
*/ |
#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bit 9 */ |
#define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ |
#define ACPI_PM1_CONTROL_PRESERVED_BITS \ |
(ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) |
#define ACPI_PM2_CONTROL_PRESERVED_BITS 0xFFFFFFFE /* All except bit 0 */ |
/* |
* Register IDs |
* These are the full ACPI registers |
*/ |
#define ACPI_REGISTER_PM1_STATUS 0x01 |
#define ACPI_REGISTER_PM1_ENABLE 0x02 |
#define ACPI_REGISTER_PM1_CONTROL 0x03 |
#define ACPI_REGISTER_PM2_CONTROL 0x04 |
#define ACPI_REGISTER_PM_TIMER 0x05 |
#define ACPI_REGISTER_PROCESSOR_BLOCK 0x06 |
#define ACPI_REGISTER_SMI_COMMAND_BLOCK 0x07 |
/* Masks used to access the bit_registers */ |
#define ACPI_BITMASK_TIMER_STATUS 0x0001 |
#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 |
#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 |
#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 |
#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 |
#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 |
#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ |
#define ACPI_BITMASK_WAKE_STATUS 0x8000 |
#define ACPI_BITMASK_ALL_FIXED_STATUS (\ |
ACPI_BITMASK_TIMER_STATUS | \ |
ACPI_BITMASK_BUS_MASTER_STATUS | \ |
ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ |
ACPI_BITMASK_POWER_BUTTON_STATUS | \ |
ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ |
ACPI_BITMASK_RT_CLOCK_STATUS | \ |
ACPI_BITMASK_PCIEXP_WAKE_STATUS | \ |
ACPI_BITMASK_WAKE_STATUS) |
#define ACPI_BITMASK_TIMER_ENABLE 0x0001 |
#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020 |
#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100 |
#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200 |
#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400 |
#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */ |
#define ACPI_BITMASK_SCI_ENABLE 0x0001 |
#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002 |
#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004 |
#define ACPI_BITMASK_SLEEP_TYPE 0x1C00 |
#define ACPI_BITMASK_SLEEP_ENABLE 0x2000 |
#define ACPI_BITMASK_ARB_DISABLE 0x0001 |
/* Raw bit position of each bit_register */ |
#define ACPI_BITPOSITION_TIMER_STATUS 0x00 |
#define ACPI_BITPOSITION_BUS_MASTER_STATUS 0x04 |
#define ACPI_BITPOSITION_GLOBAL_LOCK_STATUS 0x05 |
#define ACPI_BITPOSITION_POWER_BUTTON_STATUS 0x08 |
#define ACPI_BITPOSITION_SLEEP_BUTTON_STATUS 0x09 |
#define ACPI_BITPOSITION_RT_CLOCK_STATUS 0x0A |
#define ACPI_BITPOSITION_PCIEXP_WAKE_STATUS 0x0E /* ACPI 3.0 */ |
#define ACPI_BITPOSITION_WAKE_STATUS 0x0F |
#define ACPI_BITPOSITION_TIMER_ENABLE 0x00 |
#define ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE 0x05 |
#define ACPI_BITPOSITION_POWER_BUTTON_ENABLE 0x08 |
#define ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE 0x09 |
#define ACPI_BITPOSITION_RT_CLOCK_ENABLE 0x0A |
#define ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE 0x0E /* ACPI 3.0 */ |
#define ACPI_BITPOSITION_SCI_ENABLE 0x00 |
#define ACPI_BITPOSITION_BUS_MASTER_RLD 0x01 |
#define ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE 0x02 |
#define ACPI_BITPOSITION_SLEEP_TYPE 0x0A |
#define ACPI_BITPOSITION_SLEEP_ENABLE 0x0D |
#define ACPI_BITPOSITION_ARB_DISABLE 0x00 |
/* Structs and definitions for _OSI support and I/O port validation */ |
#define ACPI_ALWAYS_ILLEGAL 0x00 |
struct acpi_interface_info { |
char *name; |
struct acpi_interface_info *next; |
u8 flags; |
u8 value; |
}; |
#define ACPI_OSI_INVALID 0x01 |
#define ACPI_OSI_DYNAMIC 0x02 |
#define ACPI_OSI_FEATURE 0x04 |
#define ACPI_OSI_DEFAULT_INVALID 0x08 |
#define ACPI_OSI_OPTIONAL_FEATURE (ACPI_OSI_FEATURE | ACPI_OSI_DEFAULT_INVALID | ACPI_OSI_INVALID) |
struct acpi_port_info { |
char *name; |
u16 start; |
u16 end; |
u8 osi_dependency; |
}; |
/***************************************************************************** |
* |
* Resource descriptors |
* |
****************************************************************************/ |
/* resource_type values */ |
#define ACPI_ADDRESS_TYPE_MEMORY_RANGE 0 |
#define ACPI_ADDRESS_TYPE_IO_RANGE 1 |
#define ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE 2 |
/* Resource descriptor types and masks */ |
#define ACPI_RESOURCE_NAME_LARGE 0x80 |
#define ACPI_RESOURCE_NAME_SMALL 0x00 |
#define ACPI_RESOURCE_NAME_SMALL_MASK 0x78 /* Bits 6:3 contain the type */ |
#define ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK 0x07 /* Bits 2:0 contain the length */ |
#define ACPI_RESOURCE_NAME_LARGE_MASK 0x7F /* Bits 6:0 contain the type */ |
/* |
* Small resource descriptor "names" as defined by the ACPI specification. |
* Note: Bits 2:0 are used for the descriptor length |
*/ |
#define ACPI_RESOURCE_NAME_IRQ 0x20 |
#define ACPI_RESOURCE_NAME_DMA 0x28 |
#define ACPI_RESOURCE_NAME_START_DEPENDENT 0x30 |
#define ACPI_RESOURCE_NAME_END_DEPENDENT 0x38 |
#define ACPI_RESOURCE_NAME_IO 0x40 |
#define ACPI_RESOURCE_NAME_FIXED_IO 0x48 |
#define ACPI_RESOURCE_NAME_FIXED_DMA 0x50 |
#define ACPI_RESOURCE_NAME_RESERVED_S2 0x58 |
#define ACPI_RESOURCE_NAME_RESERVED_S3 0x60 |
#define ACPI_RESOURCE_NAME_RESERVED_S4 0x68 |
#define ACPI_RESOURCE_NAME_VENDOR_SMALL 0x70 |
#define ACPI_RESOURCE_NAME_END_TAG 0x78 |
/* |
* Large resource descriptor "names" as defined by the ACPI specification. |
* Note: includes the Large Descriptor bit in bit[7] |
*/ |
#define ACPI_RESOURCE_NAME_MEMORY24 0x81 |
#define ACPI_RESOURCE_NAME_GENERIC_REGISTER 0x82 |
#define ACPI_RESOURCE_NAME_RESERVED_L1 0x83 |
#define ACPI_RESOURCE_NAME_VENDOR_LARGE 0x84 |
#define ACPI_RESOURCE_NAME_MEMORY32 0x85 |
#define ACPI_RESOURCE_NAME_FIXED_MEMORY32 0x86 |
#define ACPI_RESOURCE_NAME_ADDRESS32 0x87 |
#define ACPI_RESOURCE_NAME_ADDRESS16 0x88 |
#define ACPI_RESOURCE_NAME_EXTENDED_IRQ 0x89 |
#define ACPI_RESOURCE_NAME_ADDRESS64 0x8A |
#define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B |
#define ACPI_RESOURCE_NAME_GPIO 0x8C |
#define ACPI_RESOURCE_NAME_SERIAL_BUS 0x8E |
#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8E |
/***************************************************************************** |
* |
* Miscellaneous |
* |
****************************************************************************/ |
#define ACPI_ASCII_ZERO 0x30 |
/***************************************************************************** |
* |
* Disassembler |
* |
****************************************************************************/ |
struct acpi_external_list { |
char *path; |
char *internal_path; |
struct acpi_external_list *next; |
u32 value; |
u16 length; |
u16 flags; |
u8 type; |
}; |
/* Values for Flags field above */ |
#define ACPI_EXT_RESOLVED_REFERENCE 0x01 /* Object was resolved during cross ref */ |
#define ACPI_EXT_ORIGIN_FROM_FILE 0x02 /* External came from a file */ |
#define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */ |
#define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */ |
struct acpi_external_file { |
char *path; |
struct acpi_external_file *next; |
}; |
/***************************************************************************** |
* |
* Debugger |
* |
****************************************************************************/ |
struct acpi_db_method_info { |
acpi_handle method; |
acpi_handle main_thread_gate; |
acpi_handle thread_complete_gate; |
acpi_handle info_gate; |
acpi_thread_id *threads; |
u32 num_threads; |
u32 num_created; |
u32 num_completed; |
char *name; |
u32 flags; |
u32 num_loops; |
char pathname[ACPI_DB_LINE_BUFFER_SIZE]; |
char **args; |
acpi_object_type *types; |
/* |
* Arguments to be passed to method for the command |
* Threads - |
* the Number of threads, ID of current thread and |
* Index of current thread inside all them created. |
*/ |
char init_args; |
#ifdef ACPI_DEBUGGER |
acpi_object_type arg_types[4]; |
#endif |
char *arguments[4]; |
char num_threads_str[11]; |
char id_of_thread_str[11]; |
char index_of_thread_str[11]; |
}; |
struct acpi_integrity_info { |
u32 nodes; |
u32 objects; |
}; |
#define ACPI_DB_DISABLE_OUTPUT 0x00 |
#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 |
#define ACPI_DB_CONSOLE_OUTPUT 0x02 |
#define ACPI_DB_DUPLICATE_OUTPUT 0x03 |
struct acpi_object_info { |
u32 types[ACPI_TOTAL_TYPES]; |
}; |
/***************************************************************************** |
* |
* Debug |
* |
****************************************************************************/ |
/* Entry for a memory allocation (debug only) */ |
#define ACPI_MEM_MALLOC 0 |
#define ACPI_MEM_CALLOC 1 |
#define ACPI_MAX_MODULE_NAME 16 |
#define ACPI_COMMON_DEBUG_MEM_HEADER \ |
struct acpi_debug_mem_block *previous; \ |
struct acpi_debug_mem_block *next; \ |
u32 size; \ |
u32 component; \ |
u32 line; \ |
char module[ACPI_MAX_MODULE_NAME]; \ |
u8 alloc_type; |
struct acpi_debug_mem_header { |
ACPI_COMMON_DEBUG_MEM_HEADER}; |
struct acpi_debug_mem_block { |
ACPI_COMMON_DEBUG_MEM_HEADER u64 user_space; |
}; |
#define ACPI_MEM_LIST_GLOBAL 0 |
#define ACPI_MEM_LIST_NSNODE 1 |
#define ACPI_MEM_LIST_MAX 1 |
#define ACPI_NUM_MEM_LISTS 2 |
/***************************************************************************** |
* |
* Info/help support |
* |
****************************************************************************/ |
struct ah_predefined_name { |
char *name; |
char *description; |
#ifndef ACPI_ASL_COMPILER |
char *action; |
#endif |
}; |
struct ah_device_id { |
char *name; |
char *description; |
}; |
struct ah_uuid { |
char *description; |
char *string; |
}; |
struct ah_table { |
char *signature; |
char *description; |
}; |
#endif /* __ACLOCAL_H__ */ |
/drivers/acpi/acpica/acmacros.h |
---|
0,0 → 1,428 |
/****************************************************************************** |
* |
* Name: acmacros.h - C macros for the entire subsystem. |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACMACROS_H__ |
#define __ACMACROS_H__ |
/* |
* Extract data using a pointer. Any more than a byte and we |
* get into potential aligment issues -- see the STORE macros below. |
* Use with care. |
*/ |
#define ACPI_CAST8(ptr) ACPI_CAST_PTR (u8, (ptr)) |
#define ACPI_CAST16(ptr) ACPI_CAST_PTR (u16, (ptr)) |
#define ACPI_CAST32(ptr) ACPI_CAST_PTR (u32, (ptr)) |
#define ACPI_CAST64(ptr) ACPI_CAST_PTR (u64, (ptr)) |
#define ACPI_GET8(ptr) (*ACPI_CAST8 (ptr)) |
#define ACPI_GET16(ptr) (*ACPI_CAST16 (ptr)) |
#define ACPI_GET32(ptr) (*ACPI_CAST32 (ptr)) |
#define ACPI_GET64(ptr) (*ACPI_CAST64 (ptr)) |
#define ACPI_SET8(ptr, val) (*ACPI_CAST8 (ptr) = (u8) (val)) |
#define ACPI_SET16(ptr, val) (*ACPI_CAST16 (ptr) = (u16) (val)) |
#define ACPI_SET32(ptr, val) (*ACPI_CAST32 (ptr) = (u32) (val)) |
#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val)) |
/* |
* printf() format helper. This macros is a workaround for the difficulties |
* with emitting 64-bit integers and 64-bit pointers with the same code |
* for both 32-bit and 64-bit hosts. |
*/ |
#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i) |
/* |
* Macros for moving data around to/from buffers that are possibly unaligned. |
* If the hardware supports the transfer of unaligned data, just do the store. |
* Otherwise, we have to move one byte at a time. |
*/ |
#ifdef ACPI_BIG_ENDIAN |
/* |
* Macros for big-endian machines |
*/ |
/* These macros reverse the bytes during the move, converting little-endian to big endian */ |
/* Big Endian <== Little Endian */ |
/* Hi...Lo Lo...Hi */ |
/* 16-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[1];\ |
(( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];} |
#define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d))=0;\ |
((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ |
((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} |
#define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ |
((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ |
((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} |
/* 32-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ |
#define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[3];\ |
(( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\ |
(( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ |
(( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} |
#define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ |
((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\ |
((u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[2];\ |
((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ |
((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} |
/* 64-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ |
#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ |
#define ACPI_MOVE_64_TO_64(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[7];\ |
(( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[6];\ |
(( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[5];\ |
(( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[4];\ |
(( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\ |
(( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[2];\ |
(( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ |
(( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} |
#else |
/* |
* Macros for little-endian machines |
*/ |
#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED |
/* The hardware supports unaligned transfers, just do the little-endian move */ |
/* 16-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_16_TO_16(d, s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s) |
#define ACPI_MOVE_16_TO_32(d, s) *(u32 *)(void *)(d) = *(u16 *)(void *)(s) |
#define ACPI_MOVE_16_TO_64(d, s) *(u64 *)(void *)(d) = *(u16 *)(void *)(s) |
/* 32-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ |
#define ACPI_MOVE_32_TO_32(d, s) *(u32 *)(void *)(d) = *(u32 *)(void *)(s) |
#define ACPI_MOVE_32_TO_64(d, s) *(u64 *)(void *)(d) = *(u32 *)(void *)(s) |
/* 64-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ |
#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ |
#define ACPI_MOVE_64_TO_64(d, s) *(u64 *)(void *)(d) = *(u64 *)(void *)(s) |
#else |
/* |
* The hardware does not support unaligned transfers. We must move the |
* data one byte at a time. These macros work whether the source or |
* the destination (or both) is/are unaligned. (Little-endian move) |
*/ |
/* 16-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ |
(( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];} |
#define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} |
#define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} |
/* 32-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ |
#define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ |
(( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\ |
(( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\ |
(( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];} |
#define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d)) = 0; ACPI_MOVE_32_TO_32(d, s);} |
/* 64-bit source, 16/32/64 destination */ |
#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ |
#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ |
#define ACPI_MOVE_64_TO_64(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ |
(( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\ |
(( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\ |
(( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];\ |
(( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[4];\ |
(( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[5];\ |
(( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[6];\ |
(( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[7];} |
#endif |
#endif |
/* |
* Fast power-of-two math macros for non-optimized compilers |
*/ |
#define _ACPI_DIV(value, power_of2) ((u32) ((value) >> (power_of2))) |
#define _ACPI_MUL(value, power_of2) ((u32) ((value) << (power_of2))) |
#define _ACPI_MOD(value, divisor) ((u32) ((value) & ((divisor) -1))) |
#define ACPI_DIV_2(a) _ACPI_DIV(a, 1) |
#define ACPI_MUL_2(a) _ACPI_MUL(a, 1) |
#define ACPI_MOD_2(a) _ACPI_MOD(a, 2) |
#define ACPI_DIV_4(a) _ACPI_DIV(a, 2) |
#define ACPI_MUL_4(a) _ACPI_MUL(a, 2) |
#define ACPI_MOD_4(a) _ACPI_MOD(a, 4) |
#define ACPI_DIV_8(a) _ACPI_DIV(a, 3) |
#define ACPI_MUL_8(a) _ACPI_MUL(a, 3) |
#define ACPI_MOD_8(a) _ACPI_MOD(a, 8) |
#define ACPI_DIV_16(a) _ACPI_DIV(a, 4) |
#define ACPI_MUL_16(a) _ACPI_MUL(a, 4) |
#define ACPI_MOD_16(a) _ACPI_MOD(a, 16) |
#define ACPI_DIV_32(a) _ACPI_DIV(a, 5) |
#define ACPI_MUL_32(a) _ACPI_MUL(a, 5) |
#define ACPI_MOD_32(a) _ACPI_MOD(a, 32) |
/* Test for ASCII character */ |
#define ACPI_IS_ASCII(c) ((c) < 0x80) |
/* Signed integers */ |
#define ACPI_SIGN_POSITIVE 0 |
#define ACPI_SIGN_NEGATIVE 1 |
/* |
* Rounding macros (Power of two boundaries only) |
*/ |
#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \ |
(~(((acpi_size) boundary)-1))) |
#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \ |
(((acpi_size) boundary)-1)) & \ |
(~(((acpi_size) boundary)-1))) |
/* Note: sizeof(acpi_size) evaluates to either 4 or 8 (32- vs 64-bit mode) */ |
#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a, 4) |
#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a, 8) |
#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a, sizeof(acpi_size)) |
#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a, 4) |
#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a, 8) |
#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a, sizeof(acpi_size)) |
#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) |
#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a)) |
#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) |
/* Generic (non-power-of-two) rounding */ |
#define ACPI_ROUND_UP_TO(value, boundary) (((value) + ((boundary)-1)) / (boundary)) |
#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) |
/* |
* Bitmask creation |
* Bit positions start at zero. |
* MASK_BITS_ABOVE creates a mask starting AT the position and above |
* MASK_BITS_BELOW creates a mask starting one bit BELOW the position |
*/ |
#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_UINT64_MAX) << ((u32) (position)))) |
#define ACPI_MASK_BITS_BELOW(position) ((ACPI_UINT64_MAX) << ((u32) (position))) |
/* Bitfields within ACPI registers */ |
#define ACPI_REGISTER_PREPARE_BITS(val, pos, mask) \ |
((val << pos) & mask) |
#define ACPI_REGISTER_INSERT_VALUE(reg, pos, mask, val) \ |
reg = (reg & (~(mask))) | ACPI_REGISTER_PREPARE_BITS(val, pos, mask) |
#define ACPI_INSERT_BITS(target, mask, source) \ |
target = ((target & (~(mask))) | (source & mask)) |
/* Generic bitfield macros and masks */ |
#define ACPI_GET_BITS(source_ptr, position, mask) \ |
((*source_ptr >> position) & mask) |
#define ACPI_SET_BITS(target_ptr, position, mask, value) \ |
(*target_ptr |= ((value & mask) << position)) |
#define ACPI_1BIT_MASK 0x00000001 |
#define ACPI_2BIT_MASK 0x00000003 |
#define ACPI_3BIT_MASK 0x00000007 |
#define ACPI_4BIT_MASK 0x0000000F |
#define ACPI_5BIT_MASK 0x0000001F |
#define ACPI_6BIT_MASK 0x0000003F |
#define ACPI_7BIT_MASK 0x0000007F |
#define ACPI_8BIT_MASK 0x000000FF |
#define ACPI_16BIT_MASK 0x0000FFFF |
#define ACPI_24BIT_MASK 0x00FFFFFF |
/* Macros to extract flag bits from position zero */ |
#define ACPI_GET_1BIT_FLAG(value) ((value) & ACPI_1BIT_MASK) |
#define ACPI_GET_2BIT_FLAG(value) ((value) & ACPI_2BIT_MASK) |
#define ACPI_GET_3BIT_FLAG(value) ((value) & ACPI_3BIT_MASK) |
#define ACPI_GET_4BIT_FLAG(value) ((value) & ACPI_4BIT_MASK) |
/* Macros to extract flag bits from position one and above */ |
#define ACPI_EXTRACT_1BIT_FLAG(field, position) (ACPI_GET_1BIT_FLAG ((field) >> position)) |
#define ACPI_EXTRACT_2BIT_FLAG(field, position) (ACPI_GET_2BIT_FLAG ((field) >> position)) |
#define ACPI_EXTRACT_3BIT_FLAG(field, position) (ACPI_GET_3BIT_FLAG ((field) >> position)) |
#define ACPI_EXTRACT_4BIT_FLAG(field, position) (ACPI_GET_4BIT_FLAG ((field) >> position)) |
/* ACPI Pathname helpers */ |
#define ACPI_IS_ROOT_PREFIX(c) ((c) == (u8) 0x5C) /* Backslash */ |
#define ACPI_IS_PARENT_PREFIX(c) ((c) == (u8) 0x5E) /* Carat */ |
#define ACPI_IS_PATH_SEPARATOR(c) ((c) == (u8) 0x2E) /* Period (dot) */ |
/* |
* An object of type struct acpi_namespace_node can appear in some contexts |
* where a pointer to an object of type union acpi_operand_object can also |
* appear. This macro is used to distinguish them. |
* |
* The "DescriptorType" field is the second field in both structures. |
*/ |
#define ACPI_GET_DESCRIPTOR_PTR(d) (((union acpi_descriptor *)(void *)(d))->common.common_pointer) |
#define ACPI_SET_DESCRIPTOR_PTR(d, p) (((union acpi_descriptor *)(void *)(d))->common.common_pointer = (p)) |
#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type) |
#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = (t)) |
/* |
* Macros for the master AML opcode table |
*/ |
#if defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT) |
#define ACPI_OP(name, Pargs, Iargs, obj_type, class, type, flags) \ |
{name, (u32)(Pargs), (u32)(Iargs), (u32)(flags), obj_type, class, type} |
#else |
#define ACPI_OP(name, Pargs, Iargs, obj_type, class, type, flags) \ |
{(u32)(Pargs), (u32)(Iargs), (u32)(flags), obj_type, class, type} |
#endif |
#define ARG_TYPE_WIDTH 5 |
#define ARG_1(x) ((u32)(x)) |
#define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH)) |
#define ARG_3(x) ((u32)(x) << (2 * ARG_TYPE_WIDTH)) |
#define ARG_4(x) ((u32)(x) << (3 * ARG_TYPE_WIDTH)) |
#define ARG_5(x) ((u32)(x) << (4 * ARG_TYPE_WIDTH)) |
#define ARG_6(x) ((u32)(x) << (5 * ARG_TYPE_WIDTH)) |
#define ARGI_LIST1(a) (ARG_1(a)) |
#define ARGI_LIST2(a, b) (ARG_1(b)|ARG_2(a)) |
#define ARGI_LIST3(a, b, c) (ARG_1(c)|ARG_2(b)|ARG_3(a)) |
#define ARGI_LIST4(a, b, c, d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a)) |
#define ARGI_LIST5(a, b, c, d, e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a)) |
#define ARGI_LIST6(a, b, c, d, e, f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a)) |
#define ARGP_LIST1(a) (ARG_1(a)) |
#define ARGP_LIST2(a, b) (ARG_1(a)|ARG_2(b)) |
#define ARGP_LIST3(a, b, c) (ARG_1(a)|ARG_2(b)|ARG_3(c)) |
#define ARGP_LIST4(a, b, c, d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)) |
#define ARGP_LIST5(a, b, c, d, e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)) |
#define ARGP_LIST6(a, b, c, d, e, f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f)) |
#define GET_CURRENT_ARG_TYPE(list) (list & ((u32) 0x1F)) |
#define INCREMENT_ARG_LIST(list) (list >>= ((u32) ARG_TYPE_WIDTH)) |
/* |
* Ascii error messages can be configured out |
*/ |
#ifndef ACPI_NO_ERROR_MESSAGES |
/* |
* Error reporting. Callers module and line number are inserted by AE_INFO, |
* the plist contains a set of parens to allow variable-length lists. |
* These macros are used for both the debug and non-debug versions of the code. |
*/ |
#define ACPI_ERROR_NAMESPACE(s, e) acpi_ut_namespace_error (AE_INFO, s, e); |
#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ut_method_error (AE_INFO, s, n, p, e); |
#define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist |
#define ACPI_INFO_PREDEFINED(plist) acpi_ut_predefined_info plist |
#define ACPI_BIOS_ERROR_PREDEFINED(plist) acpi_ut_predefined_bios_error plist |
#else |
/* No error messages */ |
#define ACPI_ERROR_NAMESPACE(s, e) |
#define ACPI_ERROR_METHOD(s, n, p, e) |
#define ACPI_WARN_PREDEFINED(plist) |
#define ACPI_INFO_PREDEFINED(plist) |
#define ACPI_BIOS_ERROR_PREDEFINED(plist) |
#endif /* ACPI_NO_ERROR_MESSAGES */ |
#if (!ACPI_REDUCED_HARDWARE) |
#define ACPI_HW_OPTIONAL_FUNCTION(addr) addr |
#else |
#define ACPI_HW_OPTIONAL_FUNCTION(addr) NULL |
#endif |
/* |
* Some code only gets executed when the debugger is built in. |
* Note that this is entirely independent of whether the |
* DEBUG_PRINT stuff (set by ACPI_DEBUG_OUTPUT) is on, or not. |
*/ |
#ifdef ACPI_DEBUGGER |
#define ACPI_DEBUGGER_EXEC(a) a |
#else |
#define ACPI_DEBUGGER_EXEC(a) |
#endif |
/* |
* Macros used for ACPICA utilities only |
*/ |
/* Generate a UUID */ |
#define ACPI_INIT_UUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ |
(a) & 0xFF, ((a) >> 8) & 0xFF, ((a) >> 16) & 0xFF, ((a) >> 24) & 0xFF, \ |
(b) & 0xFF, ((b) >> 8) & 0xFF, \ |
(c) & 0xFF, ((c) >> 8) & 0xFF, \ |
(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) |
#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) |
#endif /* ACMACROS_H */ |
/drivers/acpi/acpica/acnamesp.h |
---|
0,0 → 1,407 |
/****************************************************************************** |
* |
* Name: acnamesp.h - Namespace subcomponent prototypes and defines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACNAMESP_H__ |
#define __ACNAMESP_H__ |
/* To search the entire name space, pass this as search_base */ |
#define ACPI_NS_ALL ((acpi_handle)0) |
/* |
* Elements of acpi_ns_properties are bit significant |
* and should be one-to-one with values of acpi_object_type |
*/ |
#define ACPI_NS_NORMAL 0 |
#define ACPI_NS_NEWSCOPE 1 /* a definition of this type opens a name scope */ |
#define ACPI_NS_LOCAL 2 /* suppress search of enclosing scopes */ |
/* Flags for acpi_ns_lookup, acpi_ns_search_and_enter */ |
#define ACPI_NS_NO_UPSEARCH 0 |
#define ACPI_NS_SEARCH_PARENT 0x01 |
#define ACPI_NS_DONT_OPEN_SCOPE 0x02 |
#define ACPI_NS_NO_PEER_SEARCH 0x04 |
#define ACPI_NS_ERROR_IF_FOUND 0x08 |
#define ACPI_NS_PREFIX_IS_SCOPE 0x10 |
#define ACPI_NS_EXTERNAL 0x20 |
#define ACPI_NS_TEMPORARY 0x40 |
#define ACPI_NS_OVERRIDE_IF_FOUND 0x80 |
/* Flags for acpi_ns_walk_namespace */ |
#define ACPI_NS_WALK_NO_UNLOCK 0 |
#define ACPI_NS_WALK_UNLOCK 0x01 |
#define ACPI_NS_WALK_TEMP_NODES 0x02 |
/* Object is not a package element */ |
#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX |
/* Always emit warning message, not dependent on node flags */ |
#define ACPI_WARN_ALWAYS 0 |
/* |
* nsinit - Namespace initialization |
*/ |
acpi_status acpi_ns_initialize_objects(void); |
acpi_status acpi_ns_initialize_devices(void); |
/* |
* nsload - Namespace loading |
*/ |
acpi_status acpi_ns_load_namespace(void); |
acpi_status |
acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node); |
/* |
* nswalk - walk the namespace |
*/ |
acpi_status |
acpi_ns_walk_namespace(acpi_object_type type, |
acpi_handle start_object, |
u32 max_depth, |
u32 flags, |
acpi_walk_callback descending_callback, |
acpi_walk_callback ascending_callback, |
void *context, void **return_value); |
struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node |
*parent, |
struct acpi_namespace_node |
*child); |
struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, |
struct |
acpi_namespace_node |
*parent, |
struct |
acpi_namespace_node |
*child); |
/* |
* nsparse - table parsing |
*/ |
acpi_status |
acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node); |
acpi_status |
acpi_ns_one_complete_parse(u32 pass_number, |
u32 table_index, |
struct acpi_namespace_node *start_node); |
/* |
* nsaccess - Top-level namespace access |
*/ |
acpi_status acpi_ns_root_initialize(void); |
acpi_status |
acpi_ns_lookup(union acpi_generic_state *scope_info, |
char *name, |
acpi_object_type type, |
acpi_interpreter_mode interpreter_mode, |
u32 flags, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node **ret_node); |
/* |
* nsalloc - Named object allocation/deallocation |
*/ |
struct acpi_namespace_node *acpi_ns_create_node(u32 name); |
void acpi_ns_delete_node(struct acpi_namespace_node *node); |
void acpi_ns_remove_node(struct acpi_namespace_node *node); |
void |
acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_handle); |
void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id); |
void acpi_ns_detach_object(struct acpi_namespace_node *node); |
void acpi_ns_delete_children(struct acpi_namespace_node *parent); |
int acpi_ns_compare_names(char *name1, char *name2); |
/* |
* nsconvert - Dynamic object conversion routines |
*/ |
acpi_status |
acpi_ns_convert_to_integer(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object); |
acpi_status |
acpi_ns_convert_to_string(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object); |
acpi_status |
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object); |
acpi_status |
acpi_ns_convert_to_unicode(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object); |
acpi_status |
acpi_ns_convert_to_resource(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object); |
/* |
* nsdump - Namespace dump/print utilities |
*/ |
void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth); |
void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level); |
void |
acpi_ns_dump_pathname(acpi_handle handle, char *msg, u32 level, u32 component); |
void acpi_ns_print_pathname(u32 num_segments, char *pathname); |
acpi_status |
acpi_ns_dump_one_object(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
void |
acpi_ns_dump_objects(acpi_object_type type, |
u8 display_type, |
u32 max_depth, |
acpi_owner_id owner_id, acpi_handle start_handle); |
void |
acpi_ns_dump_object_paths(acpi_object_type type, |
u8 display_type, |
u32 max_depth, |
acpi_owner_id owner_id, acpi_handle start_handle); |
/* |
* nseval - Namespace evaluation functions |
*/ |
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info); |
void acpi_ns_exec_module_code_list(void); |
/* |
* nsarguments - Argument count/type checking for predefined/reserved names |
*/ |
void |
acpi_ns_check_argument_count(char *pathname, |
struct acpi_namespace_node *node, |
u32 user_param_count, |
const union acpi_predefined_info *info); |
void |
acpi_ns_check_acpi_compliance(char *pathname, |
struct acpi_namespace_node *node, |
const union acpi_predefined_info *predefined); |
void acpi_ns_check_argument_types(struct acpi_evaluate_info *info); |
/* |
* nspredef - Return value checking for predefined/reserved names |
*/ |
acpi_status |
acpi_ns_check_return_value(struct acpi_namespace_node *node, |
struct acpi_evaluate_info *info, |
u32 user_param_count, |
acpi_status return_status, |
union acpi_operand_object **return_object); |
acpi_status |
acpi_ns_check_object_type(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr, |
u32 expected_btypes, u32 package_index); |
/* |
* nsprepkg - Validation of predefined name packages |
*/ |
acpi_status |
acpi_ns_check_package(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
/* |
* nsnames - Name and Scope manipulation |
*/ |
u32 acpi_ns_opens_scope(acpi_object_type type); |
char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node); |
u32 |
acpi_ns_build_normalized_path(struct acpi_namespace_node *node, |
char *full_path, u32 path_size, u8 no_trailing); |
char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, |
u8 no_trailing); |
char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state); |
acpi_status |
acpi_ns_handle_to_pathname(acpi_handle target_handle, |
struct acpi_buffer *buffer, u8 no_trailing); |
u8 |
acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for); |
acpi_status |
acpi_ns_get_node(struct acpi_namespace_node *prefix_node, |
const char *external_pathname, |
u32 flags, struct acpi_namespace_node **out_node); |
acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node); |
/* |
* nsobject - Object management for namespace nodes |
*/ |
acpi_status |
acpi_ns_attach_object(struct acpi_namespace_node *node, |
union acpi_operand_object *object, acpi_object_type type); |
union acpi_operand_object *acpi_ns_get_attached_object(struct |
acpi_namespace_node |
*node); |
union acpi_operand_object *acpi_ns_get_secondary_object(union |
acpi_operand_object |
*obj_desc); |
acpi_status |
acpi_ns_attach_data(struct acpi_namespace_node *node, |
acpi_object_handler handler, void *data); |
acpi_status |
acpi_ns_detach_data(struct acpi_namespace_node *node, |
acpi_object_handler handler); |
acpi_status |
acpi_ns_get_attached_data(struct acpi_namespace_node *node, |
acpi_object_handler handler, void **data); |
/* |
* nsrepair - General return object repair for all |
* predefined methods/objects |
*/ |
acpi_status |
acpi_ns_simple_repair(struct acpi_evaluate_info *info, |
u32 expected_btypes, |
u32 package_index, |
union acpi_operand_object **return_object_ptr); |
acpi_status |
acpi_ns_wrap_with_package(struct acpi_evaluate_info *info, |
union acpi_operand_object *original_object, |
union acpi_operand_object **obj_desc_ptr); |
acpi_status |
acpi_ns_repair_null_element(struct acpi_evaluate_info *info, |
u32 expected_btypes, |
u32 package_index, |
union acpi_operand_object **return_object_ptr); |
void |
acpi_ns_remove_null_elements(struct acpi_evaluate_info *info, |
u8 package_type, |
union acpi_operand_object *obj_desc); |
/* |
* nsrepair2 - Return object repair for specific |
* predefined methods/objects |
*/ |
acpi_status |
acpi_ns_complex_repairs(struct acpi_evaluate_info *info, |
struct acpi_namespace_node *node, |
acpi_status validate_status, |
union acpi_operand_object **return_object_ptr); |
/* |
* nssearch - Namespace searching and entry |
*/ |
acpi_status |
acpi_ns_search_and_enter(u32 entry_name, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node *node, |
acpi_interpreter_mode interpreter_mode, |
acpi_object_type type, |
u32 flags, struct acpi_namespace_node **ret_node); |
acpi_status |
acpi_ns_search_one_scope(u32 entry_name, |
struct acpi_namespace_node *node, |
acpi_object_type type, |
struct acpi_namespace_node **ret_node); |
void |
acpi_ns_install_node(struct acpi_walk_state *walk_state, |
struct acpi_namespace_node *parent_node, |
struct acpi_namespace_node *node, acpi_object_type type); |
/* |
* nsutils - Utility functions |
*/ |
acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node); |
u32 acpi_ns_local(acpi_object_type type); |
void |
acpi_ns_print_node_pathname(struct acpi_namespace_node *node, const char *msg); |
acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info); |
void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info); |
acpi_status |
acpi_ns_internalize_name(const char *dotted_name, char **converted_name); |
acpi_status |
acpi_ns_externalize_name(u32 internal_name_length, |
const char *internal_name, |
u32 * converted_name_length, char **converted_name); |
struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle); |
void acpi_ns_terminate(void); |
#endif /* __ACNAMESP_H__ */ |
/drivers/acpi/acpica/acobject.h |
---|
0,0 → 1,465 |
/****************************************************************************** |
* |
* Name: acobject.h - Definition of union acpi_operand_object (Internal object only) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef _ACOBJECT_H |
#define _ACOBJECT_H |
/* acpisrc:struct_defs -- for acpisrc conversion */ |
/* |
* The union acpi_operand_object is used to pass AML operands from the dispatcher |
* to the interpreter, and to keep track of the various handlers such as |
* address space handlers and notify handlers. The object is a constant |
* size in order to allow it to be cached and reused. |
* |
* Note: The object is optimized to be aligned and will not work if it is |
* byte-packed. |
*/ |
#if ACPI_MACHINE_WIDTH == 64 |
#pragma pack(8) |
#else |
#pragma pack(4) |
#endif |
/******************************************************************************* |
* |
* Common Descriptors |
* |
******************************************************************************/ |
/* |
* Common area for all objects. |
* |
* descriptor_type is used to differentiate between internal descriptors, and |
* must be in the same place across all descriptors |
* |
* Note: The descriptor_type and Type fields must appear in the identical |
* position in both the struct acpi_namespace_node and union acpi_operand_object |
* structures. |
*/ |
#define ACPI_OBJECT_COMMON_HEADER \ |
union acpi_operand_object *next_object; /* Objects linked to parent NS node */\ |
u8 descriptor_type; /* To differentiate various internal objs */\ |
u8 type; /* acpi_object_type */\ |
u16 reference_count; /* For object deletion management */\ |
u8 flags; |
/* |
* Note: There are 3 bytes available here before the |
* next natural alignment boundary (for both 32/64 cases) |
*/ |
/* Values for Flag byte above */ |
#define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */ |
#define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */ |
#define AOPOBJ_DATA_VALID 0x04 /* Object is initialized and data is valid */ |
#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */ |
#define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */ |
#define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */ |
/****************************************************************************** |
* |
* Basic data types |
* |
*****************************************************************************/ |
struct acpi_object_common { |
ACPI_OBJECT_COMMON_HEADER}; |
struct acpi_object_integer { |
ACPI_OBJECT_COMMON_HEADER u8 fill[3]; /* Prevent warning on some compilers */ |
u64 value; |
}; |
/* |
* Note: The String and Buffer object must be identical through the |
* pointer and length elements. There is code that depends on this. |
* |
* Fields common to both Strings and Buffers |
*/ |
#define ACPI_COMMON_BUFFER_INFO(_type) \ |
_type *pointer; \ |
u32 length; |
struct acpi_object_string { /* Null terminated, ASCII characters only */ |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(char) /* String in AML stream or allocated string */ |
}; |
struct acpi_object_buffer { |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(u8) /* Buffer in AML stream or allocated buffer */ |
u32 aml_length; |
u8 *aml_start; |
struct acpi_namespace_node *node; /* Link back to parent node */ |
}; |
struct acpi_object_package { |
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Link back to parent node */ |
union acpi_operand_object **elements; /* Array of pointers to acpi_objects */ |
u8 *aml_start; |
u32 aml_length; |
u32 count; /* # of elements in package */ |
}; |
/****************************************************************************** |
* |
* Complex data types |
* |
*****************************************************************************/ |
struct acpi_object_event { |
ACPI_OBJECT_COMMON_HEADER acpi_semaphore os_semaphore; /* Actual OS synchronization object */ |
}; |
struct acpi_object_mutex { |
ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */ |
u16 acquisition_depth; /* Allow multiple Acquires, same thread */ |
acpi_mutex os_mutex; /* Actual OS synchronization object */ |
acpi_thread_id thread_id; /* Current owner of the mutex */ |
struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ |
union acpi_operand_object *prev; /* Link for list of acquired mutexes */ |
union acpi_operand_object *next; /* Link for list of acquired mutexes */ |
struct acpi_namespace_node *node; /* Containing namespace node */ |
u8 original_sync_level; /* Owner's original sync level (0-15) */ |
}; |
struct acpi_object_region { |
ACPI_OBJECT_COMMON_HEADER u8 space_id; |
struct acpi_namespace_node *node; /* Containing namespace node */ |
union acpi_operand_object *handler; /* Handler for region access */ |
union acpi_operand_object *next; |
acpi_physical_address address; |
u32 length; |
}; |
struct acpi_object_method { |
ACPI_OBJECT_COMMON_HEADER u8 info_flags; |
u8 param_count; |
u8 sync_level; |
union acpi_operand_object *mutex; |
union acpi_operand_object *node; |
u8 *aml_start; |
union { |
acpi_internal_method implementation; |
union acpi_operand_object *handler; |
} dispatch; |
u32 aml_length; |
u8 thread_count; |
acpi_owner_id owner_id; |
}; |
/* Flags for info_flags field above */ |
#define ACPI_METHOD_MODULE_LEVEL 0x01 /* Method is actually module-level code */ |
#define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */ |
#define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */ |
#define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */ |
#define ACPI_METHOD_IGNORE_SYNC_LEVEL 0x10 /* Method was auto-serialized at table load time */ |
#define ACPI_METHOD_MODIFIED_NAMESPACE 0x20 /* Method modified the namespace */ |
/****************************************************************************** |
* |
* Objects that can be notified. All share a common notify_info area. |
* |
*****************************************************************************/ |
/* |
* Common fields for objects that support ASL notifications |
*/ |
#define ACPI_COMMON_NOTIFY_INFO \ |
union acpi_operand_object *notify_list[2]; /* Handlers for system/device notifies */\ |
union acpi_operand_object *handler; /* Handler for Address space */ |
struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; |
struct acpi_object_device { |
ACPI_OBJECT_COMMON_HEADER |
ACPI_COMMON_NOTIFY_INFO struct acpi_gpe_block_info *gpe_block; |
}; |
struct acpi_object_power_resource { |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO u32 system_level; |
u32 resource_order; |
}; |
struct acpi_object_processor { |
ACPI_OBJECT_COMMON_HEADER |
/* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */ |
u8 proc_id; |
u8 length; |
ACPI_COMMON_NOTIFY_INFO acpi_io_address address; |
}; |
struct acpi_object_thermal_zone { |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; |
/****************************************************************************** |
* |
* Fields. All share a common header/info field. |
* |
*****************************************************************************/ |
/* |
* Common bitfield for the field objects |
* "Field Datum" -- a datum from the actual field object |
* "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field |
*/ |
#define ACPI_COMMON_FIELD_INFO \ |
u8 field_flags; /* Access, update, and lock bits */\ |
u8 attribute; /* From access_as keyword */\ |
u8 access_byte_width; /* Read/Write size in bytes */\ |
struct acpi_namespace_node *node; /* Link back to parent node */\ |
u32 bit_length; /* Length of field in bits */\ |
u32 base_byte_offset; /* Byte offset within containing object */\ |
u32 value; /* Value to store into the Bank or Index register */\ |
u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ |
u8 access_length; /* For serial regions/fields */ |
struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */ |
}; |
struct acpi_object_region_field { |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; |
union acpi_operand_object *region_obj; /* Containing op_region object */ |
u8 *resource_buffer; /* resource_template for serial regions/fields */ |
u16 pin_number_index; /* Index relative to previous Connection/Template */ |
}; |
struct acpi_object_bank_field { |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */ |
union acpi_operand_object *bank_obj; /* bank_select Register object */ |
}; |
struct acpi_object_index_field { |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO |
/* |
* No "RegionObj" pointer needed since the Index and Data registers |
* are each field definitions unto themselves. |
*/ |
union acpi_operand_object *index_obj; /* Index register */ |
union acpi_operand_object *data_obj; /* Data register */ |
}; |
/* The buffer_field is different in that it is part of a Buffer, not an op_region */ |
struct acpi_object_buffer_field { |
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *buffer_obj; /* Containing Buffer object */ |
}; |
/****************************************************************************** |
* |
* Objects for handlers |
* |
*****************************************************************************/ |
struct acpi_object_notify_handler { |
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */ |
u32 handler_type; /* Type: Device/System/Both */ |
acpi_notify_handler handler; /* Handler address */ |
void *context; |
union acpi_operand_object *next[2]; /* Device and System handler lists */ |
}; |
struct acpi_object_addr_handler { |
ACPI_OBJECT_COMMON_HEADER u8 space_id; |
u8 handler_flags; |
acpi_adr_space_handler handler; |
struct acpi_namespace_node *node; /* Parent device */ |
void *context; |
acpi_adr_space_setup setup; |
union acpi_operand_object *region_list; /* Regions using this handler */ |
union acpi_operand_object *next; |
}; |
/* Flags for address handler (handler_flags) */ |
#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x01 |
/****************************************************************************** |
* |
* Special internal objects |
* |
*****************************************************************************/ |
/* |
* The Reference object is used for these opcodes: |
* Arg[0-6], Local[0-7], index_op, name_op, ref_of_op, load_op, load_table_op, debug_op |
* The Reference.Class differentiates these types. |
*/ |
struct acpi_object_reference { |
ACPI_OBJECT_COMMON_HEADER u8 class; /* Reference Class */ |
u8 target_type; /* Used for Index Op */ |
u8 reserved; |
void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */ |
struct acpi_namespace_node *node; /* ref_of or Namepath */ |
union acpi_operand_object **where; /* Target of Index */ |
u8 *index_pointer; /* Used for Buffers and Strings */ |
u32 value; /* Used for Local/Arg/Index/ddb_handle */ |
}; |
/* Values for Reference.Class above */ |
typedef enum { |
ACPI_REFCLASS_LOCAL = 0, /* Method local */ |
ACPI_REFCLASS_ARG = 1, /* Method argument */ |
ACPI_REFCLASS_REFOF = 2, /* Result of ref_of() TBD: Split to Ref/Node and Ref/operand_obj? */ |
ACPI_REFCLASS_INDEX = 3, /* Result of Index() */ |
ACPI_REFCLASS_TABLE = 4, /* ddb_handle - Load(), load_table() */ |
ACPI_REFCLASS_NAME = 5, /* Reference to a named object */ |
ACPI_REFCLASS_DEBUG = 6, /* Debug object */ |
ACPI_REFCLASS_MAX = 6 |
} ACPI_REFERENCE_CLASSES; |
/* |
* Extra object is used as additional storage for types that |
* have AML code in their declarations (term_args) that must be |
* evaluated at run time. |
* |
* Currently: Region and field_unit types |
*/ |
struct acpi_object_extra { |
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */ |
struct acpi_namespace_node *scope_node; |
void *region_context; /* Region-specific data */ |
u8 *aml_start; |
u32 aml_length; |
}; |
/* Additional data that can be attached to namespace nodes */ |
struct acpi_object_data { |
ACPI_OBJECT_COMMON_HEADER acpi_object_handler handler; |
void *pointer; |
}; |
/* Structure used when objects are cached for reuse */ |
struct acpi_object_cache_list { |
ACPI_OBJECT_COMMON_HEADER union acpi_operand_object *next; /* Link for object cache and internal lists */ |
}; |
/****************************************************************************** |
* |
* union acpi_operand_object descriptor - a giant union of all of the above |
* |
*****************************************************************************/ |
union acpi_operand_object { |
struct acpi_object_common common; |
struct acpi_object_integer integer; |
struct acpi_object_string string; |
struct acpi_object_buffer buffer; |
struct acpi_object_package package; |
struct acpi_object_event event; |
struct acpi_object_method method; |
struct acpi_object_mutex mutex; |
struct acpi_object_region region; |
struct acpi_object_notify_common common_notify; |
struct acpi_object_device device; |
struct acpi_object_power_resource power_resource; |
struct acpi_object_processor processor; |
struct acpi_object_thermal_zone thermal_zone; |
struct acpi_object_field_common common_field; |
struct acpi_object_region_field field; |
struct acpi_object_buffer_field buffer_field; |
struct acpi_object_bank_field bank_field; |
struct acpi_object_index_field index_field; |
struct acpi_object_notify_handler notify; |
struct acpi_object_addr_handler address_space; |
struct acpi_object_reference reference; |
struct acpi_object_extra extra; |
struct acpi_object_data data; |
struct acpi_object_cache_list cache; |
/* |
* Add namespace node to union in order to simplify code that accepts both |
* ACPI_OPERAND_OBJECTs and ACPI_NAMESPACE_NODEs. The structures share |
* a common descriptor_type field in order to differentiate them. |
*/ |
struct acpi_namespace_node node; |
}; |
/****************************************************************************** |
* |
* union acpi_descriptor - objects that share a common descriptor identifier |
* |
*****************************************************************************/ |
/* Object descriptor types */ |
#define ACPI_DESC_TYPE_CACHED 0x01 /* Used only when object is cached */ |
#define ACPI_DESC_TYPE_STATE 0x02 |
#define ACPI_DESC_TYPE_STATE_UPDATE 0x03 |
#define ACPI_DESC_TYPE_STATE_PACKAGE 0x04 |
#define ACPI_DESC_TYPE_STATE_CONTROL 0x05 |
#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x06 |
#define ACPI_DESC_TYPE_STATE_PSCOPE 0x07 |
#define ACPI_DESC_TYPE_STATE_WSCOPE 0x08 |
#define ACPI_DESC_TYPE_STATE_RESULT 0x09 |
#define ACPI_DESC_TYPE_STATE_NOTIFY 0x0A |
#define ACPI_DESC_TYPE_STATE_THREAD 0x0B |
#define ACPI_DESC_TYPE_WALK 0x0C |
#define ACPI_DESC_TYPE_PARSER 0x0D |
#define ACPI_DESC_TYPE_OPERAND 0x0E |
#define ACPI_DESC_TYPE_NAMED 0x0F |
#define ACPI_DESC_TYPE_MAX 0x0F |
struct acpi_common_descriptor { |
void *common_pointer; |
u8 descriptor_type; /* To differentiate various internal objs */ |
}; |
union acpi_descriptor { |
struct acpi_common_descriptor common; |
union acpi_operand_object object; |
struct acpi_namespace_node node; |
union acpi_parse_object op; |
}; |
#pragma pack() |
#endif /* _ACOBJECT_H */ |
/drivers/acpi/acpica/acopcode.h |
---|
0,0 → 1,329 |
/****************************************************************************** |
* |
* Name: acopcode.h - AML opcode information for the AML parser and interpreter |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACOPCODE_H__ |
#define __ACOPCODE_H__ |
#define MAX_EXTENDED_OPCODE 0x88 |
#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1) |
#define MAX_INTERNAL_OPCODE |
#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1) |
/* Used for non-assigned opcodes */ |
#define _UNK 0x6B |
/* |
* Reserved ASCII characters. Do not use any of these for |
* internal opcodes, since they are used to differentiate |
* name strings from AML opcodes |
*/ |
#define _ASC 0x6C |
#define _NAM 0x6C |
#define _PFX 0x6D |
/* |
* All AML opcodes and the parse-time arguments for each. Used by the AML |
* parser Each list is compressed into a 32-bit number and stored in the |
* master opcode table (in psopcode.c). |
*/ |
#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA) |
#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME) |
#define ARGP_ARG0 ARG_NONE |
#define ARGP_ARG1 ARG_NONE |
#define ARGP_ARG2 ARG_NONE |
#define ARGP_ARG3 ARG_NONE |
#define ARGP_ARG4 ARG_NONE |
#define ARGP_ARG5 ARG_NONE |
#define ARGP_ARG6 ARG_NONE |
#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST) |
#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_BREAK_OP ARG_NONE |
#define ARGP_BREAK_POINT_OP ARG_NONE |
#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) |
#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA) |
#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) |
#define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_CONTINUE_OP ARG_NONE |
#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) |
#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) |
#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) |
#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) |
#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) |
#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) |
#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) |
#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_DEBUG_OP ARG_NONE |
#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) |
#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) |
#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) |
#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) |
#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) |
#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) |
#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_BYTEDATA) |
#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) |
#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) |
#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) |
#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST) |
#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) |
#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME) |
#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_LOCAL0 ARG_NONE |
#define ARGP_LOCAL1 ARG_NONE |
#define ARGP_LOCAL2 ARG_NONE |
#define ARGP_LOCAL3 ARG_NONE |
#define ARGP_LOCAL4 ARG_NONE |
#define ARGP_LOCAL5 ARG_NONE |
#define ARGP_LOCAL6 ARG_NONE |
#define ARGP_LOCAL7 ARG_NONE |
#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST) |
#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA) |
#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ) |
#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_NOOP_OP ARG_NONE |
#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) |
#define ARGP_ONE_OP ARG_NONE |
#define ARGP_ONES_OP ARG_NONE |
#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) |
#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) |
#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) |
#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) |
#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) |
#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) |
#define ARGP_REVISION_OP ARG_NONE |
#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) |
#define ARGP_SERIALFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG) |
#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG) |
#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING) |
#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME) |
#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST) |
#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) |
#define ARGP_TIMER_OP ARG_NONE |
#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) |
#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) |
#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) |
#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) |
#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) |
#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) |
#define ARGP_ZERO_OP ARG_NONE |
/* |
* All AML opcodes and the runtime arguments for each. Used by the AML |
* interpreter Each list is compressed into a 32-bit number and stored |
* in the master opcode table (in psopcode.c). |
* |
* (Used by prep_operands procedure and the ASL Compiler) |
*/ |
#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE |
#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER) |
#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE |
#define ARGI_ARG0 ARG_NONE |
#define ARGI_ARG1 ARG_NONE |
#define ARGI_ARG2 ARG_NONE |
#define ARGI_ARG3 ARG_NONE |
#define ARGI_ARG4 ARG_NONE |
#define ARGI_ARG5 ARG_NONE |
#define ARGI_ARG6 ARG_NONE |
#define ARGI_BANK_FIELD_OP ARGI_LIST1 (ARGI_INTEGER) |
#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_BREAK_OP ARG_NONE |
#define ARGI_BREAK_POINT_OP ARG_NONE |
#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) |
#define ARGI_BYTE_OP ARGI_INVALID_OPCODE |
#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE |
#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) |
#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) |
#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) |
#define ARGI_CONNECTFIELD_OP ARGI_INVALID_OPCODE |
#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE |
#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) |
#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) |
#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) |
#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) |
#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) |
#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) |
#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) |
#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) |
#define ARGI_DEBUG_OP ARG_NONE |
#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) |
#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) |
#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE |
#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) |
#define ARGI_DWORD_OP ARGI_INVALID_OPCODE |
#define ARGI_ELSE_OP ARGI_INVALID_OPCODE |
#define ARGI_EVENT_OP ARGI_INVALID_OPCODE |
#define ARGI_EXTERNAL_OP ARGI_LIST3 (ARGI_STRING, ARGI_INTEGER, ARGI_INTEGER) |
#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) |
#define ARGI_FIELD_OP ARGI_INVALID_OPCODE |
#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) |
#define ARGI_IF_OP ARGI_INVALID_OPCODE |
#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) |
#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE |
#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) |
#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) |
#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) |
#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE |
#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) |
#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE |
#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) |
#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE |
#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF) |
#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) |
#define ARGI_LOCAL0 ARG_NONE |
#define ARGI_LOCAL1 ARG_NONE |
#define ARGI_LOCAL2 ARG_NONE |
#define ARGI_LOCAL3 ARG_NONE |
#define ARGI_LOCAL4 ARG_NONE |
#define ARGI_LOCAL5 ARG_NONE |
#define ARGI_LOCAL6 ARG_NONE |
#define ARGI_LOCAL7 ARG_NONE |
#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) |
#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER) |
#define ARGI_METHOD_OP ARGI_INVALID_OPCODE |
#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE |
#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE |
#define ARGI_NAME_OP ARGI_INVALID_OPCODE |
#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE |
#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE |
#define ARGI_NOOP_OP ARG_NONE |
#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) |
#define ARGI_ONE_OP ARG_NONE |
#define ARGI_ONES_OP ARG_NONE |
#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) |
#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE |
#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE |
#define ARGI_QWORD_OP ARGI_INVALID_OPCODE |
#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF) |
#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) |
#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) |
#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE |
#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) |
#define ARGI_RETURN_OP ARGI_INVALID_OPCODE |
#define ARGI_REVISION_OP ARG_NONE |
#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE |
#define ARGI_SERIALFIELD_OP ARGI_INVALID_OPCODE |
#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) |
#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) |
#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER) |
#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER) |
#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE |
#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_STORE_TARGET) |
#define ARGI_STRING_OP ARGI_INVALID_OPCODE |
#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) |
#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE |
#define ARGI_TIMER_OP ARG_NONE |
#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) |
#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) |
#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) |
#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) |
#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) |
#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) |
#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) |
#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) |
#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) |
#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) |
#define ARGI_WHILE_OP ARGI_INVALID_OPCODE |
#define ARGI_WORD_OP ARGI_INVALID_OPCODE |
#define ARGI_ZERO_OP ARG_NONE |
#endif /* __ACOPCODE_H__ */ |
/drivers/acpi/acpica/acparser.h |
---|
0,0 → 1,253 |
/****************************************************************************** |
* |
* Module Name: acparser.h - AML Parser subcomponent prototypes and defines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACPARSER_H__ |
#define __ACPARSER_H__ |
#define OP_HAS_RETURN_VALUE 1 |
/* Variable number of arguments. This field must be 32 bits */ |
#define ACPI_VAR_ARGS ACPI_UINT32_MAX |
#define ACPI_PARSE_DELETE_TREE 0x0001 |
#define ACPI_PARSE_NO_TREE_DELETE 0x0000 |
#define ACPI_PARSE_TREE_MASK 0x0001 |
#define ACPI_PARSE_LOAD_PASS1 0x0010 |
#define ACPI_PARSE_LOAD_PASS2 0x0020 |
#define ACPI_PARSE_EXECUTE 0x0030 |
#define ACPI_PARSE_MODE_MASK 0x0030 |
#define ACPI_PARSE_DEFERRED_OP 0x0100 |
#define ACPI_PARSE_DISASSEMBLE 0x0200 |
#define ACPI_PARSE_MODULE_LEVEL 0x0400 |
/****************************************************************************** |
* |
* Parser interfaces |
* |
*****************************************************************************/ |
extern const u8 acpi_gbl_short_op_index[]; |
extern const u8 acpi_gbl_long_op_index[]; |
/* |
* psxface - Parser external interfaces |
*/ |
acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info); |
/* |
* psargs - Parse AML opcode arguments |
*/ |
u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state); |
char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state); |
void |
acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, |
u32 arg_type, union acpi_parse_object *arg); |
acpi_status |
acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, |
struct acpi_parse_state *parser_state, |
union acpi_parse_object *arg, u8 method_call); |
acpi_status |
acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, |
struct acpi_parse_state *parser_state, |
u32 arg_type, union acpi_parse_object **return_arg); |
/* |
* psfind |
*/ |
union acpi_parse_object *acpi_ps_find_name(union acpi_parse_object *scope, |
u32 name, u32 opcode); |
union acpi_parse_object *acpi_ps_get_parent(union acpi_parse_object *op); |
/* |
* psobject - support for parse object processing |
*/ |
acpi_status |
acpi_ps_build_named_op(struct acpi_walk_state *walk_state, |
u8 *aml_op_start, |
union acpi_parse_object *unnamed_op, |
union acpi_parse_object **op); |
acpi_status |
acpi_ps_create_op(struct acpi_walk_state *walk_state, |
u8 *aml_op_start, union acpi_parse_object **new_op); |
acpi_status |
acpi_ps_complete_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object **op, acpi_status status); |
acpi_status |
acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, acpi_status status); |
/* |
* psopinfo - AML Opcode information |
*/ |
const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode); |
char *acpi_ps_get_opcode_name(u16 opcode); |
u8 acpi_ps_get_argument_count(u32 op_type); |
/* |
* psparse - top level parsing routines |
*/ |
acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state); |
u32 acpi_ps_get_opcode_size(u32 opcode); |
u16 acpi_ps_peek_opcode(struct acpi_parse_state *state); |
acpi_status |
acpi_ps_complete_this_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
acpi_status |
acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
acpi_status callback_status); |
/* |
* psloop - main parse loop |
*/ |
acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state); |
/* |
* psscope - Scope stack management routines |
*/ |
acpi_status |
acpi_ps_init_scope(struct acpi_parse_state *parser_state, |
union acpi_parse_object *root); |
union acpi_parse_object *acpi_ps_get_parent_scope(struct acpi_parse_state |
*state); |
u8 acpi_ps_has_completed_scope(struct acpi_parse_state *parser_state); |
void |
acpi_ps_pop_scope(struct acpi_parse_state *parser_state, |
union acpi_parse_object **op, u32 *arg_list, u32 *arg_count); |
acpi_status |
acpi_ps_push_scope(struct acpi_parse_state *parser_state, |
union acpi_parse_object *op, |
u32 remaining_args, u32 arg_count); |
void acpi_ps_cleanup_scope(struct acpi_parse_state *state); |
/* |
* pstree - parse tree manipulation routines |
*/ |
void |
acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg); |
union acpi_parse_object *acpi_ps_find(union acpi_parse_object *scope, |
char *path, u16 opcode, u32 create); |
union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn); |
union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, |
union acpi_parse_object *op); |
/* |
* pswalk - parse tree walk routines |
*/ |
acpi_status |
acpi_ps_walk_parsed_aml(union acpi_parse_object *start_op, |
union acpi_parse_object *end_op, |
union acpi_operand_object *mth_desc, |
struct acpi_namespace_node *start_node, |
union acpi_operand_object **params, |
union acpi_operand_object **caller_return_desc, |
acpi_owner_id owner_id, |
acpi_parse_downwards descending_callback, |
acpi_parse_upwards ascending_callback); |
acpi_status |
acpi_ps_get_next_walk_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
acpi_parse_upwards ascending_callback); |
acpi_status acpi_ps_delete_completed_op(struct acpi_walk_state *walk_state); |
void acpi_ps_delete_parse_tree(union acpi_parse_object *root); |
/* |
* psutils - parser utilities |
*/ |
union acpi_parse_object *acpi_ps_create_scope_op(u8 *aml); |
void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode); |
union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml); |
void acpi_ps_free_op(union acpi_parse_object *op); |
u8 acpi_ps_is_leading_char(u32 c); |
u32 acpi_ps_get_name(union acpi_parse_object *op); |
void acpi_ps_set_name(union acpi_parse_object *op, u32 name); |
/* |
* psdump - display parser tree |
*/ |
u32 |
acpi_ps_sprint_path(char *buffer_start, |
u32 buffer_size, union acpi_parse_object *op); |
u32 |
acpi_ps_sprint_op(char *buffer_start, |
u32 buffer_size, union acpi_parse_object *op); |
void acpi_ps_show(union acpi_parse_object *op); |
#endif /* __ACPARSER_H__ */ |
/drivers/acpi/acpica/acpredef.h |
---|
0,0 → 1,1140 |
/****************************************************************************** |
* |
* Name: acpredef - Information table for ACPI predefined methods and objects |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACPREDEF_H__ |
#define __ACPREDEF_H__ |
/****************************************************************************** |
* |
* Return Package types |
* |
* 1) PTYPE1 packages do not contain subpackages. |
* |
* ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types: |
* object type |
* count |
* object type |
* count |
* |
* ACPI_PTYPE1_VAR: Variable-length length. Zero-length package is allowed: |
* object type (Int/Buf/Ref) |
* |
* ACPI_PTYPE1_OPTION: Package has some required and some optional elements |
* (Used for _PRW) |
* |
* |
* 2) PTYPE2 packages contain a Variable-length number of subpackages. Each |
* of the different types describe the contents of each of the subpackages. |
* |
* ACPI_PTYPE2: Each subpackage contains 1 or 2 object types. Zero-length |
* parent package is allowed: |
* object type |
* count |
* object type |
* count |
* (Used for _ALR,_MLS,_PSS,_TRT,_TSS) |
* |
* ACPI_PTYPE2_COUNT: Each subpackage has a count as first element. |
* Zero-length parent package is allowed: |
* object type |
* (Used for _CSD,_PSD,_TSD) |
* |
* ACPI_PTYPE2_PKG_COUNT: Count of subpackages at start, 1 or 2 object types: |
* object type |
* count |
* object type |
* count |
* (Used for _CST) |
* |
* ACPI_PTYPE2_FIXED: Each subpackage is of Fixed-length. Zero-length |
* parent package is allowed. |
* (Used for _PRT) |
* |
* ACPI_PTYPE2_MIN: Each subpackage has a Variable-length but minimum length. |
* Zero-length parent package is allowed: |
* (Used for _HPX) |
* |
* ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length |
* (Used for _ART, _FPS) |
* |
* ACPI_PTYPE2_FIX_VAR: Each subpackage consists of some fixed-length elements |
* followed by an optional element. Zero-length parent package is allowed. |
* object type |
* count |
* object type |
* count = 0 (optional) |
* (Used for _DLM) |
* |
* ACPI_PTYPE2_VAR_VAR: Variable number of subpackages, each of either a |
* constant or variable length. The subpackages are preceded by a |
* constant number of objects. |
* (Used for _LPI, _RDI) |
* |
* ACPI_PTYPE2_UUID_PAIR: Each subpackage is preceded by a UUID Buffer. The UUID |
* defines the format of the package. Zero-length parent package is |
* allowed. |
* (Used for _DSD) |
* |
*****************************************************************************/ |
enum acpi_return_package_types { |
ACPI_PTYPE1_FIXED = 1, |
ACPI_PTYPE1_VAR = 2, |
ACPI_PTYPE1_OPTION = 3, |
ACPI_PTYPE2 = 4, |
ACPI_PTYPE2_COUNT = 5, |
ACPI_PTYPE2_PKG_COUNT = 6, |
ACPI_PTYPE2_FIXED = 7, |
ACPI_PTYPE2_MIN = 8, |
ACPI_PTYPE2_REV_FIXED = 9, |
ACPI_PTYPE2_FIX_VAR = 10, |
ACPI_PTYPE2_VAR_VAR = 11, |
ACPI_PTYPE2_UUID_PAIR = 12 |
}; |
/* Support macros for users of the predefined info table */ |
#define METHOD_PREDEF_ARGS_MAX 4 |
#define METHOD_ARG_BIT_WIDTH 3 |
#define METHOD_ARG_MASK 0x0007 |
#define ARG_COUNT_IS_MINIMUM 0x8000 |
#define METHOD_MAX_ARG_TYPE ACPI_TYPE_PACKAGE |
#define METHOD_GET_ARG_COUNT(arg_list) ((arg_list) & METHOD_ARG_MASK) |
#define METHOD_GET_NEXT_TYPE(arg_list) (((arg_list) >>= METHOD_ARG_BIT_WIDTH) & METHOD_ARG_MASK) |
/* Macros used to build the predefined info table */ |
#define METHOD_0ARGS 0 |
#define METHOD_1ARGS(a1) (1 | (a1 << 3)) |
#define METHOD_2ARGS(a1,a2) (2 | (a1 << 3) | (a2 << 6)) |
#define METHOD_3ARGS(a1,a2,a3) (3 | (a1 << 3) | (a2 << 6) | (a3 << 9)) |
#define METHOD_4ARGS(a1,a2,a3,a4) (4 | (a1 << 3) | (a2 << 6) | (a3 << 9) | (a4 << 12)) |
#define METHOD_RETURNS(type) (type) |
#define METHOD_NO_RETURN_VALUE 0 |
#define PACKAGE_INFO(a,b,c,d,e,f) {{{(a),(b),(c),(d)}, ((((u16)(f)) << 8) | (e)), 0}} |
/* Support macros for the resource descriptor info table */ |
#define WIDTH_1 0x0001 |
#define WIDTH_2 0x0002 |
#define WIDTH_3 0x0004 |
#define WIDTH_8 0x0008 |
#define WIDTH_16 0x0010 |
#define WIDTH_32 0x0020 |
#define WIDTH_64 0x0040 |
#define VARIABLE_DATA 0x0080 |
#define NUM_RESOURCE_WIDTHS 8 |
#define WIDTH_ADDRESS WIDTH_16 | WIDTH_32 | WIDTH_64 |
#ifdef ACPI_CREATE_PREDEFINED_TABLE |
/****************************************************************************** |
* |
* Predefined method/object information table. |
* |
* These are the names that can actually be evaluated via acpi_evaluate_object. |
* Not present in this table are the following: |
* |
* 1) Predefined/Reserved names that are not usually evaluated via |
* acpi_evaluate_object: |
* _Lxx and _Exx GPE methods |
* _Qxx EC methods |
* _T_x compiler temporary variables |
* _Wxx wake events |
* |
* 2) Predefined names that never actually exist within the AML code: |
* Predefined resource descriptor field names |
* |
* 3) Predefined names that are implemented within ACPICA: |
* _OSI |
* |
* The main entries in the table each contain the following items: |
* |
* name - The ACPI reserved name |
* argument_list - Contains (in 16 bits), the number of required |
* arguments to the method (3 bits), and a 3-bit type |
* field for each argument (up to 4 arguments). The |
* METHOD_?ARGS macros generate the correct packed data. |
* expected_btypes - Allowed type(s) for the return value. |
* 0 means that no return value is expected. |
* |
* For methods that return packages, the next entry in the table contains |
* information about the expected structure of the package. This information |
* is saved here (rather than in a separate table) in order to minimize the |
* overall size of the stored data. |
* |
* Note: The additional braces are intended to promote portability. |
* |
* Note2: Table is used by the kernel-resident subsystem, the iASL compiler, |
* and the acpi_help utility. |
* |
* TBD: _PRT - currently ignore reversed entries. Attempt to fix in nsrepair. |
* Possibly fixing package elements like _BIF, etc. |
* |
*****************************************************************************/ |
const union acpi_predefined_info acpi_gbl_predefined_methods[] = { |
{{"_AC0", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC1", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC2", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC3", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC4", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC5", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC6", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC7", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC8", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AC9", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_ADR", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_AEI", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_AL0", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL1", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL2", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL3", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL4", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL5", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL6", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL7", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL8", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_AL9", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_ALC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_ALI", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_ALP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_ALR", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 (Ints) */ |
PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2, 0, 0, 0), |
{{"_ALT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_ART", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Ref/11 Int) */ |
PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_REFERENCE, 2, |
ACPI_RTYPE_INTEGER, 11, 0), |
{{"_BBN", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_BCL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0), |
{{"_BCM", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_BCT", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_BDN", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_BFS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_BIF", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (9 Int),(4 Str) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, |
ACPI_RTYPE_STRING, 4, 0), |
{{"_BIX", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int),(4 Str) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, |
ACPI_RTYPE_STRING, 4, 0), |
{{"_BLT", |
METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_BMA", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_BMC", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_BMD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (5 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0), |
{{"_BMS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_BQC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_BST", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0), |
{{"_BTH", METHOD_1ARGS(ACPI_TYPE_INTEGER), /* ACPI 6.0 */ |
METHOD_NO_RETURN_VALUE}}, |
{{"_BTM", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_BTP", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_CBA", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See PCI firmware spec 3.0 */ |
{{"_CCA", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* ACPI 5.1 */ |
{{"_CDM", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_CID", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Strs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, |
0, 0, 0), |
{{"_CLS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0, 0, 0), |
{{"_CPC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Bufs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0, |
0, 0, 0), |
{{"_CR3", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_CRS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_CRT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_CSD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n-1 Int) */ |
PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0), |
{{"_CST", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */ |
PACKAGE_INFO(ACPI_PTYPE2_PKG_COUNT, ACPI_RTYPE_BUFFER, 1, |
ACPI_RTYPE_INTEGER, 3, 0), |
{{"_CWS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_DCK", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_DCS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_DDC", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER)}}, |
{{"_DDN", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_STRING)}}, |
{{"_DEP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_DGS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_DIS", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_DLM", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */ |
PACKAGE_INFO(ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1, |
ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER, 0, 0), |
{{"_DMA", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_DOD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0), |
{{"_DOS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_DSD", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Buf, 1 Pkg */ |
PACKAGE_INFO(ACPI_PTYPE2_UUID_PAIR, ACPI_RTYPE_BUFFER, 1, |
ACPI_RTYPE_PACKAGE, 1, 0), |
{{"_DSM", |
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, |
ACPI_TYPE_PACKAGE), |
METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */ |
{{"_DSS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_DSW", |
METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_DTI", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_EC_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_EDL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_EJ0", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_EJ1", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_EJ2", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_EJ3", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_EJ4", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_EJD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_STRING)}}, |
{{"_ERR", |
METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_STRING, ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* Internal use only, used by ACPICA test suites */ |
{{"_EVT", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_FDE", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_FDI", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, 0, 0, 0), |
{{"_FDM", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_FIF", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0), |
{{"_FIX", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0), |
{{"_FPS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (5 Int) */ |
PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0), |
{{"_FSL", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_FST", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0, 0, 0), |
{{"_GAI", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_GCP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_GHL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_GLK", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_GPD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_GPE", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* _GPE method, not _GPE scope */ |
{{"_GRT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_GSB", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_GTF", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_GTM", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_GTS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_GWS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_HID", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, |
{{"_HOT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_HPP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0), |
/* |
* For _HPX, a single package is returned, containing a variable-length number |
* of subpackages. Each subpackage contains a PCI record setting. |
* There are several different type of record settings, of different |
* lengths, but all elements of all settings are Integers. |
*/ |
{{"_HPX", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (var Ints) */ |
PACKAGE_INFO(ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5, 0, 0, 0), |
{{"_HRV", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_IFT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */ |
{{"_INI", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_IRC", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_LCK", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_LID", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_LPD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */ |
PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0), |
{{"_LPI", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (3 Int, n Pkg (10 Int/Buf) */ |
PACKAGE_INFO(ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 3, |
ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER | ACPI_RTYPE_STRING, |
10, 0), |
{{"_MAT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_MBM", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (8 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8, 0, 0, 0), |
{{"_MLS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Str/1 Buf) */ |
PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, ACPI_RTYPE_BUFFER, 1, |
0), |
{{"_MSG", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_MSM", |
METHOD_4ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, |
ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_MTL", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_NTT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_OFF", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_ON_", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_OS_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_STRING)}}, |
{{"_OSC", |
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, |
ACPI_TYPE_BUFFER), |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_OST", |
METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_PAI", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PCL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PCT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0), |
{{"_PDC", METHOD_1ARGS(ACPI_TYPE_BUFFER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_PDL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PIC", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_PIF", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int),(3 Str) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, |
ACPI_RTYPE_STRING, 3, 0), |
{{"_PLD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Bufs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0, 0, 0, 0), |
{{"_PMC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (11 Int),(3 Str) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 11, |
ACPI_RTYPE_STRING, 3, 0), |
{{"_PMD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PMM", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PPC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PPE", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See dig64 spec */ |
{{"_PR0", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PR1", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PR2", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PR3", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PRE", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PRL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PRR", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Ref) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_REFERENCE, 1, 0, 0, 0), |
{{"_PRS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
/* |
* For _PRT, many BIOSs reverse the 3rd and 4th Package elements (Source |
* and source_index). This bug is so prevalent that there is code in the |
* ACPICA Resource Manager to detect this and switch them back. For now, |
* do not allow and issue a warning. To allow this and eliminate the |
* warning, add the ACPI_RTYPE_REFERENCE type to the 4th element (index 3) |
* in the statement below. |
*/ |
{{"_PRT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */ |
PACKAGE_INFO(ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER, |
ACPI_RTYPE_INTEGER, |
ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, |
ACPI_RTYPE_INTEGER), |
{{"_PRW", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_OPTION, 2, |
ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE, |
ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0), |
{{"_PS0", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_PS1", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_PS2", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_PS3", METHOD_0ARGS, |
METHOD_NO_RETURN_VALUE}}, |
{{"_PSC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PSD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (5 Int) with count */ |
PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0), |
{{"_PSE", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_PSL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_PSR", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PSS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (6 Int) */ |
PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6, 0, 0, 0), |
{{"_PSV", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PSW", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_PTC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0), |
{{"_PTP", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_PTS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_PUR", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0), |
{{"_PXM", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_RDI", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int, n Pkg (m Ref)) */ |
PACKAGE_INFO(ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 1, |
ACPI_RTYPE_REFERENCE, 0, 0), |
{{"_REG", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_REV", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_RMV", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_ROM", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_RST", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_NO_RETURN_VALUE}}, |
{{"_RTV", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
/* |
* For _S0_ through _S5_, the ACPI spec defines a return Package |
* containing 1 Integer, but most DSDTs have it wrong - 2,3, or 4 integers. |
* Allow this by making the objects "Variable-length length", but all elements |
* must be Integers. |
*/ |
{{"_S0_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0), |
{{"_S1_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0), |
{{"_S2_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0), |
{{"_S3_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0), |
{{"_S4_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0), |
{{"_S5_", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0), |
{{"_S1D", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S2D", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S3D", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S4D", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S0W", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S1W", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S2W", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S3W", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_S4W", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SBS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SCP", METHOD_1ARGS(ACPI_TYPE_INTEGER) | ARG_COUNT_IS_MINIMUM, |
METHOD_NO_RETURN_VALUE}}, /* Acpi 1.0 allowed 1 integer arg. Acpi 3.0 expanded to 3 args. Allow both. */ |
{{"_SDD", METHOD_1ARGS(ACPI_TYPE_BUFFER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_SEG", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SHL", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SLI", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_SPD", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SRS", METHOD_1ARGS(ACPI_TYPE_BUFFER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_SRT", METHOD_1ARGS(ACPI_TYPE_BUFFER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SRV", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */ |
{{"_SST", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_STA", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_STM", |
METHOD_3ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_STP", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_STR", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_STV", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SUB", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_STRING)}}, |
{{"_SUN", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_SWS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TC1", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TC2", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TDL", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TFP", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TIP", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TIV", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TMP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TPC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TPT", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_TRT", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 Ref/6 Int */ |
PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER, |
6, 0), |
{{"_TSD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int with count */ |
PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0), |
{{"_TSN", METHOD_0ARGS, /* ACPI 6.0 */ |
METHOD_RETURNS(ACPI_RTYPE_REFERENCE)}}, |
{{"_TSP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TSS", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int */ |
PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5, 0, 0, 0), |
{{"_TST", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_TTS", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_NO_RETURN_VALUE}}, |
{{"_TZD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ |
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), |
{{"_TZM", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_REFERENCE)}}, |
{{"_TZP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_UID", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, |
{{"_UPC", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0), |
{{"_UPD", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_UPP", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
{{"_VPO", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, |
/* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */ |
{{"_WAK", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | |
ACPI_RTYPE_PACKAGE)}}, |
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0), /* Fixed-length (2 Int), but is optional */ |
/* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */ |
{{"_WDG", METHOD_0ARGS, |
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, |
{{"_WED", METHOD_1ARGS(ACPI_TYPE_INTEGER), |
METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | |
ACPI_RTYPE_BUFFER)}}, |
PACKAGE_INFO(0, 0, 0, 0, 0, 0) /* Table terminator */ |
}; |
#else |
extern const union acpi_predefined_info acpi_gbl_predefined_methods[]; |
#endif |
#if (defined ACPI_CREATE_RESOURCE_TABLE && defined ACPI_APPLICATION) |
/****************************************************************************** |
* |
* Predefined names for use in Resource Descriptors. These names do not |
* appear in the global Predefined Name table (since these names never |
* appear in actual AML byte code, only in the original ASL) |
* |
* Note: Used by iASL compiler and acpi_help utility only. |
* |
*****************************************************************************/ |
const union acpi_predefined_info acpi_gbl_resource_names[] = { |
{{"_ADR", WIDTH_16 | WIDTH_64, 0}}, |
{{"_ALN", WIDTH_8 | WIDTH_16 | WIDTH_32, 0}}, |
{{"_ASI", WIDTH_8, 0}}, |
{{"_ASZ", WIDTH_8, 0}}, |
{{"_ATT", WIDTH_64, 0}}, |
{{"_BAS", WIDTH_16 | WIDTH_32, 0}}, |
{{"_BM_", WIDTH_1, 0}}, |
{{"_DBT", WIDTH_16, 0}}, /* Acpi 5.0 */ |
{{"_DEC", WIDTH_1, 0}}, |
{{"_DMA", WIDTH_8, 0}}, |
{{"_DPL", WIDTH_1, 0}}, /* Acpi 5.0 */ |
{{"_DRS", WIDTH_16, 0}}, /* Acpi 5.0 */ |
{{"_END", WIDTH_1, 0}}, /* Acpi 5.0 */ |
{{"_FLC", WIDTH_2, 0}}, /* Acpi 5.0 */ |
{{"_GRA", WIDTH_ADDRESS, 0}}, |
{{"_HE_", WIDTH_1, 0}}, |
{{"_INT", WIDTH_16 | WIDTH_32, 0}}, |
{{"_IOR", WIDTH_2, 0}}, /* Acpi 5.0 */ |
{{"_LEN", WIDTH_8 | WIDTH_ADDRESS, 0}}, |
{{"_LIN", WIDTH_8, 0}}, /* Acpi 5.0 */ |
{{"_LL_", WIDTH_1, 0}}, |
{{"_MAF", WIDTH_1, 0}}, |
{{"_MAX", WIDTH_ADDRESS, 0}}, |
{{"_MEM", WIDTH_2, 0}}, |
{{"_MIF", WIDTH_1, 0}}, |
{{"_MIN", WIDTH_ADDRESS, 0}}, |
{{"_MOD", WIDTH_1, 0}}, /* Acpi 5.0 */ |
{{"_MTP", WIDTH_2, 0}}, |
{{"_PAR", WIDTH_8, 0}}, /* Acpi 5.0 */ |
{{"_PHA", WIDTH_1, 0}}, /* Acpi 5.0 */ |
{{"_PIN", WIDTH_16, 0}}, /* Acpi 5.0 */ |
{{"_PPI", WIDTH_8, 0}}, /* Acpi 5.0 */ |
{{"_POL", WIDTH_1 | WIDTH_2, 0}}, /* Acpi 5.0 */ |
{{"_RBO", WIDTH_8, 0}}, |
{{"_RBW", WIDTH_8, 0}}, |
{{"_RNG", WIDTH_1, 0}}, |
{{"_RT_", WIDTH_8, 0}}, /* Acpi 3.0 */ |
{{"_RW_", WIDTH_1, 0}}, |
{{"_RXL", WIDTH_16, 0}}, /* Acpi 5.0 */ |
{{"_SHR", WIDTH_2, 0}}, |
{{"_SIZ", WIDTH_2, 0}}, |
{{"_SLV", WIDTH_1, 0}}, /* Acpi 5.0 */ |
{{"_SPE", WIDTH_32, 0}}, /* Acpi 5.0 */ |
{{"_STB", WIDTH_2, 0}}, /* Acpi 5.0 */ |
{{"_TRA", WIDTH_ADDRESS, 0}}, |
{{"_TRS", WIDTH_1, 0}}, |
{{"_TSF", WIDTH_8, 0}}, /* Acpi 3.0 */ |
{{"_TTP", WIDTH_1, 0}}, |
{{"_TXL", WIDTH_16, 0}}, /* Acpi 5.0 */ |
{{"_TYP", WIDTH_2 | WIDTH_16, 0}}, |
{{"_VEN", VARIABLE_DATA, 0}}, /* Acpi 5.0 */ |
PACKAGE_INFO(0, 0, 0, 0, 0, 0) /* Table terminator */ |
}; |
static const union acpi_predefined_info acpi_gbl_scope_names[] = { |
{{"_GPE", 0, 0}}, |
{{"_PR_", 0, 0}}, |
{{"_SB_", 0, 0}}, |
{{"_SI_", 0, 0}}, |
{{"_TZ_", 0, 0}}, |
PACKAGE_INFO(0, 0, 0, 0, 0, 0) /* Table terminator */ |
}; |
#else |
extern const union acpi_predefined_info acpi_gbl_resource_names[]; |
#endif |
#endif |
/drivers/acpi/acpica/acresrc.h |
---|
0,0 → 1,383 |
/****************************************************************************** |
* |
* Name: acresrc.h - Resource Manager function prototypes |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACRESRC_H__ |
#define __ACRESRC_H__ |
/* Need the AML resource descriptor structs */ |
#include "amlresrc.h" |
/* |
* If possible, pack the following structures to byte alignment, since we |
* don't care about performance for debug output. Two cases where we cannot |
* pack the structures: |
* |
* 1) Hardware does not support misaligned memory transfers |
* 2) Compiler does not support pointers within packed structures |
*/ |
#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) |
#pragma pack(1) |
#endif |
/* |
* Individual entry for the resource conversion tables |
*/ |
typedef const struct acpi_rsconvert_info { |
u8 opcode; |
u8 resource_offset; |
u8 aml_offset; |
u8 value; |
} acpi_rsconvert_info; |
/* Resource conversion opcodes */ |
typedef enum { |
ACPI_RSC_INITGET = 0, |
ACPI_RSC_INITSET, |
ACPI_RSC_FLAGINIT, |
ACPI_RSC_1BITFLAG, |
ACPI_RSC_2BITFLAG, |
ACPI_RSC_3BITFLAG, |
ACPI_RSC_ADDRESS, |
ACPI_RSC_BITMASK, |
ACPI_RSC_BITMASK16, |
ACPI_RSC_COUNT, |
ACPI_RSC_COUNT16, |
ACPI_RSC_COUNT_GPIO_PIN, |
ACPI_RSC_COUNT_GPIO_RES, |
ACPI_RSC_COUNT_GPIO_VEN, |
ACPI_RSC_COUNT_SERIAL_RES, |
ACPI_RSC_COUNT_SERIAL_VEN, |
ACPI_RSC_DATA8, |
ACPI_RSC_EXIT_EQ, |
ACPI_RSC_EXIT_LE, |
ACPI_RSC_EXIT_NE, |
ACPI_RSC_LENGTH, |
ACPI_RSC_MOVE_GPIO_PIN, |
ACPI_RSC_MOVE_GPIO_RES, |
ACPI_RSC_MOVE_SERIAL_RES, |
ACPI_RSC_MOVE_SERIAL_VEN, |
ACPI_RSC_MOVE8, |
ACPI_RSC_MOVE16, |
ACPI_RSC_MOVE32, |
ACPI_RSC_MOVE64, |
ACPI_RSC_SET8, |
ACPI_RSC_SOURCE, |
ACPI_RSC_SOURCEX |
} ACPI_RSCONVERT_OPCODES; |
/* Resource Conversion sub-opcodes */ |
#define ACPI_RSC_COMPARE_AML_LENGTH 0 |
#define ACPI_RSC_COMPARE_VALUE 1 |
#define ACPI_RSC_TABLE_SIZE(d) (sizeof (d) / sizeof (struct acpi_rsconvert_info)) |
#define ACPI_RS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_resource,f) |
#define AML_OFFSET(f) (u8) ACPI_OFFSET (union aml_resource,f) |
/* |
* Individual entry for the resource dump tables |
*/ |
typedef const struct acpi_rsdump_info { |
u8 opcode; |
u8 offset; |
char *name; |
const char **pointer; |
} acpi_rsdump_info; |
/* Values for the Opcode field above */ |
typedef enum { |
ACPI_RSD_TITLE = 0, |
ACPI_RSD_1BITFLAG, |
ACPI_RSD_2BITFLAG, |
ACPI_RSD_3BITFLAG, |
ACPI_RSD_ADDRESS, |
ACPI_RSD_DWORDLIST, |
ACPI_RSD_LITERAL, |
ACPI_RSD_LONGLIST, |
ACPI_RSD_SHORTLIST, |
ACPI_RSD_SHORTLISTX, |
ACPI_RSD_SOURCE, |
ACPI_RSD_STRING, |
ACPI_RSD_UINT8, |
ACPI_RSD_UINT16, |
ACPI_RSD_UINT32, |
ACPI_RSD_UINT64, |
ACPI_RSD_WORDLIST |
} ACPI_RSDUMP_OPCODES; |
/* restore default alignment */ |
#pragma pack() |
/* Resource tables indexed by internal resource type */ |
extern const u8 acpi_gbl_aml_resource_sizes[]; |
extern const u8 acpi_gbl_aml_resource_serial_bus_sizes[]; |
extern struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[]; |
/* Resource tables indexed by raw AML resource descriptor type */ |
extern const u8 acpi_gbl_resource_struct_sizes[]; |
extern const u8 acpi_gbl_resource_struct_serial_bus_sizes[]; |
extern struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[]; |
extern struct acpi_rsconvert_info |
*acpi_gbl_convert_resource_serial_bus_dispatch[]; |
struct acpi_vendor_walk_info { |
struct acpi_vendor_uuid *uuid; |
struct acpi_buffer *buffer; |
acpi_status status; |
}; |
/* |
* rscreate |
*/ |
acpi_status |
acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, |
struct acpi_buffer *output_buffer); |
acpi_status |
acpi_rs_create_aml_resources(struct acpi_buffer *resource_list, |
struct acpi_buffer *output_buffer); |
acpi_status |
acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, |
struct acpi_buffer *output_buffer); |
/* |
* rsutils |
*/ |
acpi_status |
acpi_rs_get_prt_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer); |
acpi_status |
acpi_rs_get_crs_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer); |
acpi_status |
acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer); |
acpi_status |
acpi_rs_get_method_data(acpi_handle handle, |
char *path, struct acpi_buffer *ret_buffer); |
acpi_status |
acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer); |
acpi_status |
acpi_rs_get_aei_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer); |
/* |
* rscalc |
*/ |
acpi_status |
acpi_rs_get_list_length(u8 * aml_buffer, |
u32 aml_buffer_length, acpi_size * size_needed); |
acpi_status |
acpi_rs_get_aml_length(struct acpi_resource *resource_list, |
acpi_size resource_list_size, acpi_size * size_needed); |
acpi_status |
acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, |
acpi_size * buffer_size_needed); |
acpi_status |
acpi_rs_convert_aml_to_resources(u8 * aml, |
u32 length, |
u32 offset, u8 resource_index, void **context); |
acpi_status |
acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, |
acpi_size aml_size_needed, u8 * output_buffer); |
/* |
* rsaddr |
*/ |
void |
acpi_rs_set_address_common(union aml_resource *aml, |
struct acpi_resource *resource); |
u8 |
acpi_rs_get_address_common(struct acpi_resource *resource, |
union aml_resource *aml); |
/* |
* rsmisc |
*/ |
acpi_status |
acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, |
union aml_resource *aml, |
struct acpi_rsconvert_info *info); |
acpi_status |
acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, |
union aml_resource *aml, |
struct acpi_rsconvert_info *info); |
/* |
* rsutils |
*/ |
void |
acpi_rs_move_data(void *destination, |
void *source, u16 item_count, u8 move_type); |
u8 acpi_rs_decode_bitmask(u16 mask, u8 * list); |
u16 acpi_rs_encode_bitmask(u8 * list, u8 count); |
acpi_rs_length |
acpi_rs_get_resource_source(acpi_rs_length resource_length, |
acpi_rs_length minimum_length, |
struct acpi_resource_source *resource_source, |
union aml_resource *aml, char *string_ptr); |
acpi_rsdesc_size |
acpi_rs_set_resource_source(union aml_resource *aml, |
acpi_rs_length minimum_length, |
struct acpi_resource_source *resource_source); |
void |
acpi_rs_set_resource_header(u8 descriptor_type, |
acpi_rsdesc_size total_length, |
union aml_resource *aml); |
void |
acpi_rs_set_resource_length(acpi_rsdesc_size total_length, |
union aml_resource *aml); |
/* |
* rsdump - Debugger support |
*/ |
#ifdef ACPI_DEBUGGER |
void acpi_rs_dump_resource_list(struct acpi_resource *resource); |
void acpi_rs_dump_irq_list(u8 *route_table); |
#endif |
/* |
* Resource conversion tables |
*/ |
extern struct acpi_rsconvert_info acpi_rs_convert_dma[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_end_dpf[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_io[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_fixed_io[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_end_tag[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_memory24[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_generic_reg[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_memory32[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_fixed_memory32[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_address32[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_address16[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_ext_irq[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_address64[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_ext_address64[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_gpio[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[]; |
extern struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[]; |
/* These resources require separate get/set tables */ |
extern struct acpi_rsconvert_info acpi_rs_get_irq[]; |
extern struct acpi_rsconvert_info acpi_rs_get_start_dpf[]; |
extern struct acpi_rsconvert_info acpi_rs_get_vendor_small[]; |
extern struct acpi_rsconvert_info acpi_rs_get_vendor_large[]; |
extern struct acpi_rsconvert_info acpi_rs_set_irq[]; |
extern struct acpi_rsconvert_info acpi_rs_set_start_dpf[]; |
extern struct acpi_rsconvert_info acpi_rs_set_vendor[]; |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
/* |
* rsinfo |
*/ |
extern struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[]; |
extern struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[]; |
/* |
* rsdumpinfo |
*/ |
extern struct acpi_rsdump_info acpi_rs_dump_irq[]; |
extern struct acpi_rsdump_info acpi_rs_dump_prt[]; |
extern struct acpi_rsdump_info acpi_rs_dump_dma[]; |
extern struct acpi_rsdump_info acpi_rs_dump_start_dpf[]; |
extern struct acpi_rsdump_info acpi_rs_dump_end_dpf[]; |
extern struct acpi_rsdump_info acpi_rs_dump_io[]; |
extern struct acpi_rsdump_info acpi_rs_dump_io_flags[]; |
extern struct acpi_rsdump_info acpi_rs_dump_fixed_io[]; |
extern struct acpi_rsdump_info acpi_rs_dump_vendor[]; |
extern struct acpi_rsdump_info acpi_rs_dump_end_tag[]; |
extern struct acpi_rsdump_info acpi_rs_dump_memory24[]; |
extern struct acpi_rsdump_info acpi_rs_dump_memory32[]; |
extern struct acpi_rsdump_info acpi_rs_dump_memory_flags[]; |
extern struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[]; |
extern struct acpi_rsdump_info acpi_rs_dump_address16[]; |
extern struct acpi_rsdump_info acpi_rs_dump_address32[]; |
extern struct acpi_rsdump_info acpi_rs_dump_address64[]; |
extern struct acpi_rsdump_info acpi_rs_dump_ext_address64[]; |
extern struct acpi_rsdump_info acpi_rs_dump_ext_irq[]; |
extern struct acpi_rsdump_info acpi_rs_dump_generic_reg[]; |
extern struct acpi_rsdump_info acpi_rs_dump_gpio[]; |
extern struct acpi_rsdump_info acpi_rs_dump_fixed_dma[]; |
extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[]; |
extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[]; |
extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[]; |
extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[]; |
extern struct acpi_rsdump_info acpi_rs_dump_general_flags[]; |
#endif |
#endif /* __ACRESRC_H__ */ |
/drivers/acpi/acpica/acstruct.h |
---|
0,0 → 1,243 |
/****************************************************************************** |
* |
* Name: acstruct.h - Internal structs |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACSTRUCT_H__ |
#define __ACSTRUCT_H__ |
/* acpisrc:struct_defs -- for acpisrc conversion */ |
/***************************************************************************** |
* |
* Tree walking typedefs and structs |
* |
****************************************************************************/ |
/* |
* Walk state - current state of a parse tree walk. Used for both a leisurely |
* stroll through the tree (for whatever reason), and for control method |
* execution. |
*/ |
#define ACPI_NEXT_OP_DOWNWARD 1 |
#define ACPI_NEXT_OP_UPWARD 2 |
/* |
* Groups of definitions for walk_type used for different implementations of |
* walkers (never simultaneously) - flags for interpreter: |
*/ |
#define ACPI_WALK_NON_METHOD 0 |
#define ACPI_WALK_METHOD 0x01 |
#define ACPI_WALK_METHOD_RESTART 0x02 |
struct acpi_walk_state { |
struct acpi_walk_state *next; /* Next walk_state in list */ |
u8 descriptor_type; /* To differentiate various internal objs */ |
u8 walk_type; |
u16 opcode; /* Current AML opcode */ |
u8 next_op_info; /* Info about next_op */ |
u8 num_operands; /* Stack pointer for Operands[] array */ |
u8 operand_index; /* Index into operand stack, to be used by acpi_ds_obj_stack_push */ |
acpi_owner_id owner_id; /* Owner of objects created during the walk */ |
u8 last_predicate; /* Result of last predicate */ |
u8 current_result; |
u8 return_used; |
u8 scope_depth; |
u8 pass_number; /* Parse pass during table load */ |
u8 namespace_override; /* Override existing objects */ |
u8 result_size; /* Total elements for the result stack */ |
u8 result_count; /* Current number of occupied elements of result stack */ |
u8 *aml; |
u32 arg_types; |
u32 method_breakpoint; /* For single stepping */ |
u32 user_breakpoint; /* User AML breakpoint */ |
u32 parse_flags; |
struct acpi_parse_state parser_state; /* Current state of parser */ |
u32 prev_arg_types; |
u32 arg_count; /* push for fixed or var args */ |
struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ |
struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ |
union acpi_operand_object *operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */ |
union acpi_operand_object **params; |
u8 *aml_last_while; |
union acpi_operand_object **caller_return_desc; |
union acpi_generic_state *control_state; /* List of control states (nested IFs) */ |
struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ |
union acpi_operand_object *implicit_return_obj; |
struct acpi_namespace_node *method_call_node; /* Called method Node */ |
union acpi_parse_object *method_call_op; /* method_call Op if running a method */ |
union acpi_operand_object *method_desc; /* Method descriptor if running a method */ |
struct acpi_namespace_node *method_node; /* Method node if running a method. */ |
union acpi_parse_object *op; /* Current parser op */ |
const struct acpi_opcode_info *op_info; /* Info on current opcode */ |
union acpi_parse_object *origin; /* Start of walk [Obsolete] */ |
union acpi_operand_object *result_obj; |
union acpi_generic_state *results; /* Stack of accumulated results */ |
union acpi_operand_object *return_desc; /* Return object, if any */ |
union acpi_generic_state *scope_info; /* Stack of nested scopes */ |
union acpi_parse_object *prev_op; /* Last op that was processed */ |
union acpi_parse_object *next_op; /* next op to be processed */ |
struct acpi_thread_state *thread; |
acpi_parse_downwards descending_callback; |
acpi_parse_upwards ascending_callback; |
}; |
/* Info used by acpi_ns_initialize_objects and acpi_ds_initialize_objects */ |
struct acpi_init_walk_info { |
u32 table_index; |
u32 object_count; |
u32 method_count; |
u32 serial_method_count; |
u32 non_serial_method_count; |
u32 serialized_method_count; |
u32 device_count; |
u32 op_region_count; |
u32 field_count; |
u32 buffer_count; |
u32 package_count; |
u32 op_region_init; |
u32 field_init; |
u32 buffer_init; |
u32 package_init; |
acpi_owner_id owner_id; |
}; |
struct acpi_get_devices_info { |
acpi_walk_callback user_function; |
void *context; |
const char *hid; |
}; |
union acpi_aml_operands { |
union acpi_operand_object *operands[7]; |
struct { |
struct acpi_object_integer *type; |
struct acpi_object_integer *code; |
struct acpi_object_integer *argument; |
} fatal; |
struct { |
union acpi_operand_object *source; |
struct acpi_object_integer *index; |
union acpi_operand_object *target; |
} index; |
struct { |
union acpi_operand_object *source; |
struct acpi_object_integer *index; |
struct acpi_object_integer *length; |
union acpi_operand_object *target; |
} mid; |
}; |
/* |
* Structure used to pass object evaluation information and parameters. |
* Purpose is to reduce CPU stack use. |
*/ |
struct acpi_evaluate_info { |
/* The first 3 elements are passed by the caller to acpi_ns_evaluate */ |
struct acpi_namespace_node *prefix_node; /* Input: starting node */ |
char *relative_pathname; /* Input: path relative to prefix_node */ |
union acpi_operand_object **parameters; /* Input: argument list */ |
struct acpi_namespace_node *node; /* Resolved node (prefix_node:relative_pathname) */ |
union acpi_operand_object *obj_desc; /* Object attached to the resolved node */ |
char *full_pathname; /* Full pathname of the resolved node */ |
const union acpi_predefined_info *predefined; /* Used if Node is a predefined name */ |
union acpi_operand_object *return_object; /* Object returned from the evaluation */ |
union acpi_operand_object *parent_package; /* Used if return object is a Package */ |
u32 return_flags; /* Used for return value analysis */ |
u32 return_btype; /* Bitmapped type of the returned object */ |
u16 param_count; /* Count of the input argument list */ |
u8 pass_number; /* Parser pass number */ |
u8 return_object_type; /* Object type of the returned object */ |
u8 node_flags; /* Same as Node->Flags */ |
u8 flags; /* General flags */ |
}; |
/* Values for Flags above */ |
#define ACPI_IGNORE_RETURN_VALUE 1 |
/* Defines for return_flags field above */ |
#define ACPI_OBJECT_REPAIRED 1 |
#define ACPI_OBJECT_WRAPPED 2 |
/* Info used by acpi_ns_initialize_devices */ |
struct acpi_device_walk_info { |
struct acpi_table_desc *table_desc; |
struct acpi_evaluate_info *evaluate_info; |
u32 device_count; |
u32 num_STA; |
u32 num_INI; |
}; |
/* TBD: [Restructure] Merge with struct above */ |
struct acpi_walk_info { |
u32 debug_level; |
u32 count; |
acpi_owner_id owner_id; |
u8 display_type; |
}; |
/* Display Types */ |
#define ACPI_DISPLAY_SUMMARY (u8) 0 |
#define ACPI_DISPLAY_OBJECTS (u8) 1 |
#define ACPI_DISPLAY_MASK (u8) 1 |
#define ACPI_DISPLAY_SHORT (u8) 2 |
#endif |
/drivers/acpi/acpica/actables.h |
---|
0,0 → 1,171 |
/****************************************************************************** |
* |
* Name: actables.h - ACPI table management |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __ACTABLES_H__ |
#define __ACTABLES_H__ |
acpi_status acpi_allocate_root_table(u32 initial_table_count); |
/* |
* tbxfroot - Root pointer utilities |
*/ |
u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp); |
acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); |
u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); |
/* |
* tbdata - table data structure management |
*/ |
acpi_status |
acpi_tb_get_next_table_descriptor(u32 *table_index, |
struct acpi_table_desc **table_desc); |
void |
acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, |
acpi_physical_address address, |
u8 flags, struct acpi_table_header *table); |
acpi_status |
acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, |
acpi_physical_address address, u8 flags); |
void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); |
acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc); |
acpi_status |
acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature); |
u8 acpi_tb_is_table_loaded(u32 table_index); |
void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); |
/* |
* tbfadt - FADT parse/convert/validate |
*/ |
void acpi_tb_parse_fadt(void); |
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length); |
/* |
* tbfind - find ACPI table |
*/ |
acpi_status |
acpi_tb_find_table(char *signature, |
char *oem_id, char *oem_table_id, u32 *table_index); |
/* |
* tbinstal - Table removal and deletion |
*/ |
acpi_status acpi_tb_resize_root_table_list(void); |
acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc); |
void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc); |
void acpi_tb_override_table(struct acpi_table_desc *old_table_desc); |
acpi_status |
acpi_tb_acquire_table(struct acpi_table_desc *table_desc, |
struct acpi_table_header **table_ptr, |
u32 *table_length, u8 *table_flags); |
void |
acpi_tb_release_table(struct acpi_table_header *table, |
u32 table_length, u8 table_flags); |
acpi_status |
acpi_tb_install_standard_table(acpi_physical_address address, |
u8 flags, |
u8 reload, u8 override, u32 *table_index); |
void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc); |
void acpi_tb_terminate(void); |
acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index); |
acpi_status acpi_tb_allocate_owner_id(u32 table_index); |
acpi_status acpi_tb_release_owner_id(u32 table_index); |
acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id); |
/* |
* tbutils - table manager utilities |
*/ |
acpi_status acpi_tb_initialize_facs(void); |
void |
acpi_tb_print_table_header(acpi_physical_address address, |
struct acpi_table_header *header); |
u8 acpi_tb_checksum(u8 *buffer, u32 length); |
acpi_status |
acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); |
void acpi_tb_check_dsdt_header(void); |
struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index); |
void |
acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, |
u8 override, u32 *table_index); |
acpi_status |
acpi_tb_install_fixed_table(acpi_physical_address address, |
char *signature, u32 *table_index); |
acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); |
u8 acpi_is_valid_signature(char *signature); |
/* |
* tbxfload |
*/ |
acpi_status acpi_tb_load_namespace(void); |
#endif /* __ACTABLES_H__ */ |
/drivers/acpi/acpica/acutils.h |
---|
0,0 → 1,733 |
/****************************************************************************** |
* |
* Name: acutils.h -- prototypes for the common (subsystem-wide) procedures |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef _ACUTILS_H |
#define _ACUTILS_H |
extern const u8 acpi_gbl_resource_aml_sizes[]; |
extern const u8 acpi_gbl_resource_aml_serial_bus_sizes[]; |
/* Strings used by the disassembler and debugger resource dump routines */ |
#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) |
extern const char *acpi_gbl_bm_decode[]; |
extern const char *acpi_gbl_config_decode[]; |
extern const char *acpi_gbl_consume_decode[]; |
extern const char *acpi_gbl_dec_decode[]; |
extern const char *acpi_gbl_he_decode[]; |
extern const char *acpi_gbl_io_decode[]; |
extern const char *acpi_gbl_ll_decode[]; |
extern const char *acpi_gbl_max_decode[]; |
extern const char *acpi_gbl_mem_decode[]; |
extern const char *acpi_gbl_min_decode[]; |
extern const char *acpi_gbl_mtp_decode[]; |
extern const char *acpi_gbl_rng_decode[]; |
extern const char *acpi_gbl_rw_decode[]; |
extern const char *acpi_gbl_shr_decode[]; |
extern const char *acpi_gbl_siz_decode[]; |
extern const char *acpi_gbl_trs_decode[]; |
extern const char *acpi_gbl_ttp_decode[]; |
extern const char *acpi_gbl_typ_decode[]; |
extern const char *acpi_gbl_ppc_decode[]; |
extern const char *acpi_gbl_ior_decode[]; |
extern const char *acpi_gbl_dts_decode[]; |
extern const char *acpi_gbl_ct_decode[]; |
extern const char *acpi_gbl_sbt_decode[]; |
extern const char *acpi_gbl_am_decode[]; |
extern const char *acpi_gbl_sm_decode[]; |
extern const char *acpi_gbl_wm_decode[]; |
extern const char *acpi_gbl_cph_decode[]; |
extern const char *acpi_gbl_cpo_decode[]; |
extern const char *acpi_gbl_dp_decode[]; |
extern const char *acpi_gbl_ed_decode[]; |
extern const char *acpi_gbl_bpb_decode[]; |
extern const char *acpi_gbl_sb_decode[]; |
extern const char *acpi_gbl_fc_decode[]; |
extern const char *acpi_gbl_pt_decode[]; |
#endif |
/* |
* For the iASL compiler case, the output is redirected to stderr so that |
* any of the various ACPI errors and warnings do not appear in the output |
* files, for either the compiler or disassembler portions of the tool. |
*/ |
#ifdef ACPI_ASL_COMPILER |
#include <stdio.h> |
#define ACPI_MSG_REDIRECT_BEGIN \ |
FILE *output_file = acpi_gbl_output_file; \ |
acpi_os_redirect_output (stderr); |
#define ACPI_MSG_REDIRECT_END \ |
acpi_os_redirect_output (output_file); |
#else |
/* |
* non-iASL case - no redirection, nothing to do |
*/ |
#define ACPI_MSG_REDIRECT_BEGIN |
#define ACPI_MSG_REDIRECT_END |
#endif |
/* |
* Common error message prefixes |
*/ |
#define ACPI_MSG_ERROR "ACPI Error: " |
#define ACPI_MSG_EXCEPTION "ACPI Exception: " |
#define ACPI_MSG_WARNING "ACPI Warning: " |
#define ACPI_MSG_INFO "ACPI: " |
#define ACPI_MSG_BIOS_ERROR "ACPI BIOS Error (bug): " |
#define ACPI_MSG_BIOS_WARNING "ACPI BIOS Warning (bug): " |
/* |
* Common message suffix |
*/ |
#define ACPI_MSG_SUFFIX \ |
acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number) |
/* Types for Resource descriptor entries */ |
#define ACPI_INVALID_RESOURCE 0 |
#define ACPI_FIXED_LENGTH 1 |
#define ACPI_VARIABLE_LENGTH 2 |
#define ACPI_SMALL_VARIABLE_LENGTH 3 |
typedef |
acpi_status(*acpi_walk_aml_callback) (u8 *aml, |
u32 length, |
u32 offset, |
u8 resource_index, void **context); |
typedef |
acpi_status(*acpi_pkg_callback) (u8 object_type, |
union acpi_operand_object *source_object, |
union acpi_generic_state * state, |
void *context); |
struct acpi_pkg_info { |
u8 *free_space; |
acpi_size length; |
u32 object_space; |
u32 num_packages; |
}; |
/* Object reference counts */ |
#define REF_INCREMENT (u16) 0 |
#define REF_DECREMENT (u16) 1 |
/* acpi_ut_dump_buffer */ |
#define DB_BYTE_DISPLAY 1 |
#define DB_WORD_DISPLAY 2 |
#define DB_DWORD_DISPLAY 4 |
#define DB_QWORD_DISPLAY 8 |
/* |
* utnonansi - Non-ANSI C library functions |
*/ |
void acpi_ut_strupr(char *src_string); |
void acpi_ut_strlwr(char *src_string); |
int acpi_ut_stricmp(char *string1, char *string2); |
acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); |
/* |
* utglobal - Global data structures and procedures |
*/ |
acpi_status acpi_ut_init_globals(void); |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
char *acpi_ut_get_mutex_name(u32 mutex_id); |
const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type); |
#endif |
char *acpi_ut_get_type_name(acpi_object_type type); |
char *acpi_ut_get_node_name(void *object); |
char *acpi_ut_get_descriptor_name(void *object); |
const char *acpi_ut_get_reference_name(union acpi_operand_object *object); |
char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc); |
char *acpi_ut_get_region_name(u8 space_id); |
char *acpi_ut_get_event_name(u32 event_id); |
char acpi_ut_hex_to_ascii_char(u64 integer, u32 position); |
u8 acpi_ut_ascii_char_to_hex(int hex_char); |
u8 acpi_ut_valid_object_type(acpi_object_type type); |
/* |
* utinit - miscellaneous initialization and shutdown |
*/ |
acpi_status acpi_ut_hardware_initialize(void); |
void acpi_ut_subsystem_shutdown(void); |
/* |
* utcopy - Object construction and conversion interfaces |
*/ |
acpi_status |
acpi_ut_build_simple_object(union acpi_operand_object *obj, |
union acpi_object *user_obj, |
u8 *data_space, u32 *buffer_space_used); |
acpi_status |
acpi_ut_build_package_object(union acpi_operand_object *obj, |
u8 *buffer, u32 *space_used); |
acpi_status |
acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *obj, |
struct acpi_buffer *ret_buffer); |
acpi_status |
acpi_ut_copy_eobject_to_iobject(union acpi_object *obj, |
union acpi_operand_object **internal_obj); |
acpi_status |
acpi_ut_copy_isimple_to_isimple(union acpi_operand_object *source_obj, |
union acpi_operand_object *dest_obj); |
acpi_status |
acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc, |
union acpi_operand_object **dest_desc, |
struct acpi_walk_state *walk_state); |
/* |
* utcreate - Object creation |
*/ |
acpi_status |
acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action); |
/* |
* utdebug - Debug interfaces |
*/ |
void acpi_ut_init_stack_ptr_trace(void); |
void acpi_ut_track_stack_ptr(void); |
void |
acpi_ut_trace(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id); |
void |
acpi_ut_trace_ptr(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, void *pointer); |
void |
acpi_ut_trace_u32(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, u32 integer); |
void |
acpi_ut_trace_str(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, char *string); |
void |
acpi_ut_exit(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id); |
void |
acpi_ut_status_exit(u32 line_number, |
const char *function_name, |
const char *module_name, |
u32 component_id, acpi_status status); |
void |
acpi_ut_value_exit(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, u64 value); |
void |
acpi_ut_ptr_exit(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, u8 *ptr); |
void |
acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id); |
void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 offset); |
#ifdef ACPI_APPLICATION |
void |
acpi_ut_dump_buffer_to_file(ACPI_FILE file, |
u8 *buffer, |
u32 count, u32 display, u32 base_offset); |
#endif |
void acpi_ut_report_error(char *module_name, u32 line_number); |
void acpi_ut_report_info(char *module_name, u32 line_number); |
void acpi_ut_report_warning(char *module_name, u32 line_number); |
/* |
* utdelete - Object deletion and reference counts |
*/ |
void acpi_ut_add_reference(union acpi_operand_object *object); |
void acpi_ut_remove_reference(union acpi_operand_object *object); |
void acpi_ut_delete_internal_package_object(union acpi_operand_object *object); |
void acpi_ut_delete_internal_simple_object(union acpi_operand_object *object); |
void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list); |
/* |
* uteval - object evaluation |
*/ |
acpi_status |
acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, |
char *path, |
u32 expected_return_btypes, |
union acpi_operand_object **return_desc); |
acpi_status |
acpi_ut_evaluate_numeric_object(char *object_name, |
struct acpi_namespace_node *device_node, |
u64 *value); |
acpi_status |
acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 *status_flags); |
acpi_status |
acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, |
const char **method_names, |
u8 method_count, u8 *out_values); |
/* |
* utfileio - file operations |
*/ |
#ifdef ACPI_APPLICATION |
acpi_status |
acpi_ut_read_table_from_file(char *filename, struct acpi_table_header **table); |
#endif |
/* |
* utids - device ID support |
*/ |
acpi_status |
acpi_ut_execute_HID(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id ** return_id); |
acpi_status |
acpi_ut_execute_UID(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id ** return_id); |
acpi_status |
acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id **return_id); |
acpi_status |
acpi_ut_execute_CID(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id_list ** return_cid_list); |
acpi_status |
acpi_ut_execute_CLS(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id **return_id); |
/* |
* utlock - reader/writer locks |
*/ |
acpi_status acpi_ut_create_rw_lock(struct acpi_rw_lock *lock); |
void acpi_ut_delete_rw_lock(struct acpi_rw_lock *lock); |
acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock); |
acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock); |
acpi_status acpi_ut_acquire_write_lock(struct acpi_rw_lock *lock); |
void acpi_ut_release_write_lock(struct acpi_rw_lock *lock); |
/* |
* utobject - internal object create/delete/cache routines |
*/ |
union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char |
*module_name, |
u32 line_number, |
u32 component_id, |
acpi_object_type |
type); |
void *acpi_ut_allocate_object_desc_dbg(const char *module_name, |
u32 line_number, u32 component_id); |
#define acpi_ut_create_internal_object(t) acpi_ut_create_internal_object_dbg (_acpi_module_name,__LINE__,_COMPONENT,t) |
#define acpi_ut_allocate_object_desc() acpi_ut_allocate_object_desc_dbg (_acpi_module_name,__LINE__,_COMPONENT) |
void acpi_ut_delete_object_desc(union acpi_operand_object *object); |
u8 acpi_ut_valid_internal_object(void *object); |
union acpi_operand_object *acpi_ut_create_package_object(u32 count); |
union acpi_operand_object *acpi_ut_create_integer_object(u64 value); |
union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size); |
union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size); |
acpi_status |
acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length); |
/* |
* utosi - Support for the _OSI predefined control method |
*/ |
acpi_status acpi_ut_initialize_interfaces(void); |
acpi_status acpi_ut_interface_terminate(void); |
acpi_status acpi_ut_install_interface(acpi_string interface_name); |
acpi_status acpi_ut_remove_interface(acpi_string interface_name); |
acpi_status acpi_ut_update_interfaces(u8 action); |
struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name); |
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state); |
/* |
* utpredef - support for predefined names |
*/ |
const union acpi_predefined_info *acpi_ut_get_next_predefined_method(const union |
acpi_predefined_info |
*this_name); |
const union acpi_predefined_info *acpi_ut_match_predefined_method(char *name); |
void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes); |
#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP) |
const union acpi_predefined_info *acpi_ut_match_resource_name(char *name); |
void |
acpi_ut_display_predefined_method(char *buffer, |
const union acpi_predefined_info *this_name, |
u8 multi_line); |
u32 acpi_ut_get_resource_bit_width(char *buffer, u16 types); |
#endif |
/* |
* utstate - Generic state creation/cache routines |
*/ |
void |
acpi_ut_push_generic_state(union acpi_generic_state **list_head, |
union acpi_generic_state *state); |
union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state |
**list_head); |
union acpi_generic_state *acpi_ut_create_generic_state(void); |
struct acpi_thread_state *acpi_ut_create_thread_state(void); |
union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object |
*object, u16 action); |
union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, |
void *external_object, |
u16 index); |
acpi_status |
acpi_ut_create_update_state_and_push(union acpi_operand_object *object, |
u16 action, |
union acpi_generic_state **state_list); |
union acpi_generic_state *acpi_ut_create_control_state(void); |
void acpi_ut_delete_generic_state(union acpi_generic_state *state); |
/* |
* utmath |
*/ |
acpi_status |
acpi_ut_divide(u64 in_dividend, |
u64 in_divisor, u64 *out_quotient, u64 *out_remainder); |
acpi_status |
acpi_ut_short_divide(u64 in_dividend, |
u32 divisor, u64 *out_quotient, u32 *out_remainder); |
/* |
* utmisc |
*/ |
const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status |
status); |
u8 acpi_ut_is_pci_root_bridge(char *id); |
#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_NAMES_APP) |
u8 acpi_ut_is_aml_table(struct acpi_table_header *table); |
#endif |
acpi_status |
acpi_ut_walk_package_tree(union acpi_operand_object *source_object, |
void *target_object, |
acpi_pkg_callback walk_callback, void *context); |
/* Values for Base above (16=Hex, 10=Decimal) */ |
#define ACPI_ANY_BASE 0 |
u32 acpi_ut_dword_byte_swap(u32 value); |
void acpi_ut_set_integer_width(u8 revision); |
#ifdef ACPI_DEBUG_OUTPUT |
void |
acpi_ut_display_init_pathname(u8 type, |
struct acpi_namespace_node *obj_handle, |
char *path); |
#endif |
/* |
* utownerid - Support for Table/Method Owner IDs |
*/ |
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id); |
void acpi_ut_release_owner_id(acpi_owner_id * owner_id); |
/* |
* utresrc |
*/ |
acpi_status |
acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, |
u8 *aml, |
acpi_size aml_length, |
acpi_walk_aml_callback user_function, |
void **context); |
acpi_status |
acpi_ut_validate_resource(struct acpi_walk_state *walk_state, |
void *aml, u8 *return_index); |
u32 acpi_ut_get_descriptor_length(void *aml); |
u16 acpi_ut_get_resource_length(void *aml); |
u8 acpi_ut_get_resource_header_length(void *aml); |
u8 acpi_ut_get_resource_type(void *aml); |
acpi_status |
acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag); |
/* |
* utstring - String and character utilities |
*/ |
void acpi_ut_print_string(char *string, u16 max_length); |
#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP |
void ut_convert_backslashes(char *pathname); |
#endif |
u8 acpi_ut_valid_acpi_name(char *name); |
u8 acpi_ut_valid_acpi_char(char character, u32 position); |
void acpi_ut_repair_name(char *name); |
#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) |
u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source); |
u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source); |
u8 |
acpi_ut_safe_strncat(char *dest, |
acpi_size dest_size, |
char *source, acpi_size max_transfer_length); |
#endif |
/* |
* utmutex - mutex support |
*/ |
acpi_status acpi_ut_mutex_initialize(void); |
void acpi_ut_mutex_terminate(void); |
acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id); |
acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id); |
/* |
* utalloc - memory allocation and object caching |
*/ |
acpi_status acpi_ut_create_caches(void); |
acpi_status acpi_ut_delete_caches(void); |
acpi_status acpi_ut_validate_buffer(struct acpi_buffer *buffer); |
acpi_status |
acpi_ut_initialize_buffer(struct acpi_buffer *buffer, |
acpi_size required_length); |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
void *acpi_ut_allocate_and_track(acpi_size size, |
u32 component, const char *module, u32 line); |
void *acpi_ut_allocate_zeroed_and_track(acpi_size size, |
u32 component, |
const char *module, u32 line); |
void |
acpi_ut_free_and_track(void *address, |
u32 component, const char *module, u32 line); |
void acpi_ut_dump_allocation_info(void); |
void acpi_ut_dump_allocations(u32 component, const char *module); |
acpi_status |
acpi_ut_create_list(char *list_name, |
u16 object_size, struct acpi_memory_list **return_cache); |
#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ |
/* |
* utaddress - address range check |
*/ |
acpi_status |
acpi_ut_add_address_range(acpi_adr_space_type space_id, |
acpi_physical_address address, |
u32 length, struct acpi_namespace_node *region_node); |
void |
acpi_ut_remove_address_range(acpi_adr_space_type space_id, |
struct acpi_namespace_node *region_node); |
u32 |
acpi_ut_check_address_range(acpi_adr_space_type space_id, |
acpi_physical_address address, u32 length, u8 warn); |
void acpi_ut_delete_address_lists(void); |
/* |
* utxferror - various error/warning output functions |
*/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_ut_predefined_warning(const char *module_name, |
u32 line_number, |
char *pathname, |
u8 node_flags, const char *format, ...); |
void ACPI_INTERNAL_VAR_XFACE |
acpi_ut_predefined_info(const char *module_name, |
u32 line_number, |
char *pathname, u8 node_flags, const char *format, ...); |
void ACPI_INTERNAL_VAR_XFACE |
acpi_ut_predefined_bios_error(const char *module_name, |
u32 line_number, |
char *pathname, |
u8 node_flags, const char *format, ...); |
void |
acpi_ut_namespace_error(const char *module_name, |
u32 line_number, |
const char *internal_name, acpi_status lookup_status); |
void |
acpi_ut_method_error(const char *module_name, |
u32 line_number, |
const char *message, |
struct acpi_namespace_node *node, |
const char *path, acpi_status lookup_status); |
/* |
* Utility functions for ACPI names and IDs |
*/ |
const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg); |
const struct ah_device_id *acpi_ah_match_hardware_id(char *hid); |
const char *acpi_ah_match_uuid(u8 *data); |
/* |
* utprint - printf/vprintf output functions |
*/ |
const char *acpi_ut_scan_number(const char *string, u64 *number_ptr); |
const char *acpi_ut_print_number(char *string, u64 number); |
int |
acpi_ut_vsnprintf(char *string, |
acpi_size size, const char *format, va_list args); |
int acpi_ut_snprintf(char *string, acpi_size size, const char *format, ...); |
#ifdef ACPI_APPLICATION |
int acpi_ut_file_vprintf(ACPI_FILE file, const char *format, va_list args); |
int acpi_ut_file_printf(ACPI_FILE file, const char *format, ...); |
#endif |
/* |
* utuuid -- UUID support functions |
*/ |
#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP) |
void acpi_ut_convert_string_to_uuid(char *in_string, u8 *uuid_buffer); |
#endif |
#endif /* _ACUTILS_H */ |
/drivers/acpi/acpica/amlcode.h |
---|
0,0 → 1,488 |
/****************************************************************************** |
* |
* Name: amlcode.h - Definitions for AML, as included in "definition blocks" |
* Declarations and definitions contained herein are derived |
* directly from the ACPI specification. |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#ifndef __AMLCODE_H__ |
#define __AMLCODE_H__ |
/* primary opcodes */ |
#define AML_NULL_CHAR (u16) 0x00 |
#define AML_ZERO_OP (u16) 0x00 |
#define AML_ONE_OP (u16) 0x01 |
#define AML_UNASSIGNED (u16) 0x02 |
#define AML_ALIAS_OP (u16) 0x06 |
#define AML_NAME_OP (u16) 0x08 |
#define AML_BYTE_OP (u16) 0x0a |
#define AML_WORD_OP (u16) 0x0b |
#define AML_DWORD_OP (u16) 0x0c |
#define AML_STRING_OP (u16) 0x0d |
#define AML_QWORD_OP (u16) 0x0e /* ACPI 2.0 */ |
#define AML_SCOPE_OP (u16) 0x10 |
#define AML_BUFFER_OP (u16) 0x11 |
#define AML_PACKAGE_OP (u16) 0x12 |
#define AML_VAR_PACKAGE_OP (u16) 0x13 /* ACPI 2.0 */ |
#define AML_METHOD_OP (u16) 0x14 |
#define AML_EXTERNAL_OP (u16) 0x15 /* ACPI 6.0 */ |
#define AML_DUAL_NAME_PREFIX (u16) 0x2e |
#define AML_MULTI_NAME_PREFIX_OP (u16) 0x2f |
#define AML_NAME_CHAR_SUBSEQ (u16) 0x30 |
#define AML_NAME_CHAR_FIRST (u16) 0x41 |
#define AML_EXTENDED_OP_PREFIX (u16) 0x5b |
#define AML_ROOT_PREFIX (u16) 0x5c |
#define AML_PARENT_PREFIX (u16) 0x5e |
#define AML_LOCAL_OP (u16) 0x60 |
#define AML_LOCAL0 (u16) 0x60 |
#define AML_LOCAL1 (u16) 0x61 |
#define AML_LOCAL2 (u16) 0x62 |
#define AML_LOCAL3 (u16) 0x63 |
#define AML_LOCAL4 (u16) 0x64 |
#define AML_LOCAL5 (u16) 0x65 |
#define AML_LOCAL6 (u16) 0x66 |
#define AML_LOCAL7 (u16) 0x67 |
#define AML_ARG_OP (u16) 0x68 |
#define AML_ARG0 (u16) 0x68 |
#define AML_ARG1 (u16) 0x69 |
#define AML_ARG2 (u16) 0x6a |
#define AML_ARG3 (u16) 0x6b |
#define AML_ARG4 (u16) 0x6c |
#define AML_ARG5 (u16) 0x6d |
#define AML_ARG6 (u16) 0x6e |
#define AML_STORE_OP (u16) 0x70 |
#define AML_REF_OF_OP (u16) 0x71 |
#define AML_ADD_OP (u16) 0x72 |
#define AML_CONCAT_OP (u16) 0x73 |
#define AML_SUBTRACT_OP (u16) 0x74 |
#define AML_INCREMENT_OP (u16) 0x75 |
#define AML_DECREMENT_OP (u16) 0x76 |
#define AML_MULTIPLY_OP (u16) 0x77 |
#define AML_DIVIDE_OP (u16) 0x78 |
#define AML_SHIFT_LEFT_OP (u16) 0x79 |
#define AML_SHIFT_RIGHT_OP (u16) 0x7a |
#define AML_BIT_AND_OP (u16) 0x7b |
#define AML_BIT_NAND_OP (u16) 0x7c |
#define AML_BIT_OR_OP (u16) 0x7d |
#define AML_BIT_NOR_OP (u16) 0x7e |
#define AML_BIT_XOR_OP (u16) 0x7f |
#define AML_BIT_NOT_OP (u16) 0x80 |
#define AML_FIND_SET_LEFT_BIT_OP (u16) 0x81 |
#define AML_FIND_SET_RIGHT_BIT_OP (u16) 0x82 |
#define AML_DEREF_OF_OP (u16) 0x83 |
#define AML_CONCAT_RES_OP (u16) 0x84 /* ACPI 2.0 */ |
#define AML_MOD_OP (u16) 0x85 /* ACPI 2.0 */ |
#define AML_NOTIFY_OP (u16) 0x86 |
#define AML_SIZE_OF_OP (u16) 0x87 |
#define AML_INDEX_OP (u16) 0x88 |
#define AML_MATCH_OP (u16) 0x89 |
#define AML_CREATE_DWORD_FIELD_OP (u16) 0x8a |
#define AML_CREATE_WORD_FIELD_OP (u16) 0x8b |
#define AML_CREATE_BYTE_FIELD_OP (u16) 0x8c |
#define AML_CREATE_BIT_FIELD_OP (u16) 0x8d |
#define AML_TYPE_OP (u16) 0x8e |
#define AML_CREATE_QWORD_FIELD_OP (u16) 0x8f /* ACPI 2.0 */ |
#define AML_LAND_OP (u16) 0x90 |
#define AML_LOR_OP (u16) 0x91 |
#define AML_LNOT_OP (u16) 0x92 |
#define AML_LEQUAL_OP (u16) 0x93 |
#define AML_LGREATER_OP (u16) 0x94 |
#define AML_LLESS_OP (u16) 0x95 |
#define AML_TO_BUFFER_OP (u16) 0x96 /* ACPI 2.0 */ |
#define AML_TO_DECSTRING_OP (u16) 0x97 /* ACPI 2.0 */ |
#define AML_TO_HEXSTRING_OP (u16) 0x98 /* ACPI 2.0 */ |
#define AML_TO_INTEGER_OP (u16) 0x99 /* ACPI 2.0 */ |
#define AML_TO_STRING_OP (u16) 0x9c /* ACPI 2.0 */ |
#define AML_COPY_OP (u16) 0x9d /* ACPI 2.0 */ |
#define AML_MID_OP (u16) 0x9e /* ACPI 2.0 */ |
#define AML_CONTINUE_OP (u16) 0x9f /* ACPI 2.0 */ |
#define AML_IF_OP (u16) 0xa0 |
#define AML_ELSE_OP (u16) 0xa1 |
#define AML_WHILE_OP (u16) 0xa2 |
#define AML_NOOP_OP (u16) 0xa3 |
#define AML_RETURN_OP (u16) 0xa4 |
#define AML_BREAK_OP (u16) 0xa5 |
#define AML_BREAK_POINT_OP (u16) 0xcc |
#define AML_ONES_OP (u16) 0xff |
/* prefixed opcodes */ |
#define AML_EXTENDED_OPCODE (u16) 0x5b00 /* prefix for 2-byte opcodes */ |
#define AML_MUTEX_OP (u16) 0x5b01 |
#define AML_EVENT_OP (u16) 0x5b02 |
#define AML_SHIFT_RIGHT_BIT_OP (u16) 0x5b10 |
#define AML_SHIFT_LEFT_BIT_OP (u16) 0x5b11 |
#define AML_COND_REF_OF_OP (u16) 0x5b12 |
#define AML_CREATE_FIELD_OP (u16) 0x5b13 |
#define AML_LOAD_TABLE_OP (u16) 0x5b1f /* ACPI 2.0 */ |
#define AML_LOAD_OP (u16) 0x5b20 |
#define AML_STALL_OP (u16) 0x5b21 |
#define AML_SLEEP_OP (u16) 0x5b22 |
#define AML_ACQUIRE_OP (u16) 0x5b23 |
#define AML_SIGNAL_OP (u16) 0x5b24 |
#define AML_WAIT_OP (u16) 0x5b25 |
#define AML_RESET_OP (u16) 0x5b26 |
#define AML_RELEASE_OP (u16) 0x5b27 |
#define AML_FROM_BCD_OP (u16) 0x5b28 |
#define AML_TO_BCD_OP (u16) 0x5b29 |
#define AML_UNLOAD_OP (u16) 0x5b2a |
#define AML_REVISION_OP (u16) 0x5b30 |
#define AML_DEBUG_OP (u16) 0x5b31 |
#define AML_FATAL_OP (u16) 0x5b32 |
#define AML_TIMER_OP (u16) 0x5b33 /* ACPI 3.0 */ |
#define AML_REGION_OP (u16) 0x5b80 |
#define AML_FIELD_OP (u16) 0x5b81 |
#define AML_DEVICE_OP (u16) 0x5b82 |
#define AML_PROCESSOR_OP (u16) 0x5b83 |
#define AML_POWER_RES_OP (u16) 0x5b84 |
#define AML_THERMAL_ZONE_OP (u16) 0x5b85 |
#define AML_INDEX_FIELD_OP (u16) 0x5b86 |
#define AML_BANK_FIELD_OP (u16) 0x5b87 |
#define AML_DATA_REGION_OP (u16) 0x5b88 /* ACPI 2.0 */ |
/* |
* Combination opcodes (actually two one-byte opcodes) |
* Used by the disassembler and iASL compiler |
*/ |
#define AML_LGREATEREQUAL_OP (u16) 0x9295 |
#define AML_LLESSEQUAL_OP (u16) 0x9294 |
#define AML_LNOTEQUAL_OP (u16) 0x9293 |
/* |
* Opcodes for "Field" operators |
*/ |
#define AML_FIELD_OFFSET_OP (u8) 0x00 |
#define AML_FIELD_ACCESS_OP (u8) 0x01 |
#define AML_FIELD_CONNECTION_OP (u8) 0x02 /* ACPI 5.0 */ |
#define AML_FIELD_EXT_ACCESS_OP (u8) 0x03 /* ACPI 5.0 */ |
/* |
* Internal opcodes |
* Use only "Unknown" AML opcodes, don't attempt to use |
* any valid ACPI ASCII values (A-Z, 0-9, '-') |
*/ |
#define AML_INT_NAMEPATH_OP (u16) 0x002d |
#define AML_INT_NAMEDFIELD_OP (u16) 0x0030 |
#define AML_INT_RESERVEDFIELD_OP (u16) 0x0031 |
#define AML_INT_ACCESSFIELD_OP (u16) 0x0032 |
#define AML_INT_BYTELIST_OP (u16) 0x0033 |
#define AML_INT_METHODCALL_OP (u16) 0x0035 |
#define AML_INT_RETURN_VALUE_OP (u16) 0x0036 |
#define AML_INT_EVAL_SUBTREE_OP (u16) 0x0037 |
#define AML_INT_CONNECTION_OP (u16) 0x0038 |
#define AML_INT_EXTACCESSFIELD_OP (u16) 0x0039 |
#define ARG_NONE 0x0 |
/* |
* Argument types for the AML Parser |
* Each field in the arg_types u32 is 5 bits, allowing for a maximum of 6 arguments. |
* There can be up to 31 unique argument types |
* Zero is reserved as end-of-list indicator |
*/ |
#define ARGP_BYTEDATA 0x01 |
#define ARGP_BYTELIST 0x02 |
#define ARGP_CHARLIST 0x03 |
#define ARGP_DATAOBJ 0x04 |
#define ARGP_DATAOBJLIST 0x05 |
#define ARGP_DWORDDATA 0x06 |
#define ARGP_FIELDLIST 0x07 |
#define ARGP_NAME 0x08 |
#define ARGP_NAMESTRING 0x09 |
#define ARGP_OBJLIST 0x0A |
#define ARGP_PKGLENGTH 0x0B |
#define ARGP_SUPERNAME 0x0C |
#define ARGP_TARGET 0x0D |
#define ARGP_TERMARG 0x0E |
#define ARGP_TERMLIST 0x0F |
#define ARGP_WORDDATA 0x10 |
#define ARGP_QWORDDATA 0x11 |
#define ARGP_SIMPLENAME 0x12 |
/* |
* Resolved argument types for the AML Interpreter |
* Each field in the arg_types u32 is 5 bits, allowing for a maximum of 6 arguments. |
* There can be up to 31 unique argument types (0 is end-of-arg-list indicator) |
* |
* Note1: These values are completely independent from the ACPI_TYPEs |
* i.e., ARGI_INTEGER != ACPI_TYPE_INTEGER |
* |
* Note2: If and when 5 bits becomes insufficient, it would probably be best |
* to convert to a 6-byte array of argument types, allowing 8 bits per argument. |
*/ |
/* Single, simple types */ |
#define ARGI_ANYTYPE 0x01 /* Don't care */ |
#define ARGI_PACKAGE 0x02 |
#define ARGI_EVENT 0x03 |
#define ARGI_MUTEX 0x04 |
#define ARGI_DDBHANDLE 0x05 |
/* Interchangeable types (via implicit conversion) */ |
#define ARGI_INTEGER 0x06 |
#define ARGI_STRING 0x07 |
#define ARGI_BUFFER 0x08 |
#define ARGI_BUFFER_OR_STRING 0x09 /* Used by MID op only */ |
#define ARGI_COMPUTEDATA 0x0A /* Buffer, String, or Integer */ |
/* Reference objects */ |
#define ARGI_INTEGER_REF 0x0B |
#define ARGI_OBJECT_REF 0x0C |
#define ARGI_DEVICE_REF 0x0D |
#define ARGI_REFERENCE 0x0E |
#define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */ |
#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */ |
#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */ |
#define ARGI_STORE_TARGET 0x12 /* Target for store is TARGETREF + package objects */ |
/* Multiple/complex types */ |
#define ARGI_DATAOBJECT 0x13 /* Buffer, String, package or reference to a node - Used only by size_of operator */ |
#define ARGI_COMPLEXOBJ 0x14 /* Buffer, String, or package (Used by INDEX op only) */ |
#define ARGI_REF_OR_STRING 0x15 /* Reference or String (Used by DEREFOF op only) */ |
#define ARGI_REGION_OR_BUFFER 0x16 /* Used by LOAD op only */ |
#define ARGI_DATAREFOBJ 0x17 |
/* Note: types above can expand to 0x1F maximum */ |
#define ARGI_INVALID_OPCODE 0xFFFFFFFF |
/* |
* hash offsets |
*/ |
#define AML_EXTOP_HASH_OFFSET 22 |
#define AML_LNOT_HASH_OFFSET 19 |
/* |
* opcode groups and types |
*/ |
#define OPGRP_NAMED 0x01 |
#define OPGRP_FIELD 0x02 |
#define OPGRP_BYTELIST 0x04 |
/* |
* Opcode information |
*/ |
/* Opcode flags */ |
#define AML_LOGICAL 0x0001 |
#define AML_LOGICAL_NUMERIC 0x0002 |
#define AML_MATH 0x0004 |
#define AML_CREATE 0x0008 |
#define AML_FIELD 0x0010 |
#define AML_DEFER 0x0020 |
#define AML_NAMED 0x0040 |
#define AML_NSNODE 0x0080 |
#define AML_NSOPCODE 0x0100 |
#define AML_NSOBJECT 0x0200 |
#define AML_HAS_RETVAL 0x0400 |
#define AML_HAS_TARGET 0x0800 |
#define AML_HAS_ARGS 0x1000 |
#define AML_CONSTANT 0x2000 |
#define AML_NO_OPERAND_RESOLVE 0x4000 |
/* Convenient flag groupings */ |
#define AML_FLAGS_EXEC_0A_0T_1R AML_HAS_RETVAL |
#define AML_FLAGS_EXEC_1A_0T_0R AML_HAS_ARGS /* Monadic1 */ |
#define AML_FLAGS_EXEC_1A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Monadic2 */ |
#define AML_FLAGS_EXEC_1A_1T_0R AML_HAS_ARGS | AML_HAS_TARGET |
#define AML_FLAGS_EXEC_1A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* monadic2_r */ |
#define AML_FLAGS_EXEC_2A_0T_0R AML_HAS_ARGS /* Dyadic1 */ |
#define AML_FLAGS_EXEC_2A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Dyadic2 */ |
#define AML_FLAGS_EXEC_2A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* dyadic2_r */ |
#define AML_FLAGS_EXEC_2A_2T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL |
#define AML_FLAGS_EXEC_3A_0T_0R AML_HAS_ARGS |
#define AML_FLAGS_EXEC_3A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL |
#define AML_FLAGS_EXEC_6A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL |
/* |
* The opcode Type is used in a dispatch table, do not change |
* without updating the table. |
*/ |
#define AML_TYPE_EXEC_0A_0T_1R 0x00 |
#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* Monadic1 */ |
#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* Monadic2 */ |
#define AML_TYPE_EXEC_1A_1T_0R 0x03 |
#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* monadic2_r */ |
#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* Dyadic1 */ |
#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* Dyadic2 */ |
#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* dyadic2_r */ |
#define AML_TYPE_EXEC_2A_2T_1R 0x08 |
#define AML_TYPE_EXEC_3A_0T_0R 0x09 |
#define AML_TYPE_EXEC_3A_1T_1R 0x0A |
#define AML_TYPE_EXEC_6A_0T_1R 0x0B |
/* End of types used in dispatch table */ |
#define AML_TYPE_LITERAL 0x0B |
#define AML_TYPE_CONSTANT 0x0C |
#define AML_TYPE_METHOD_ARGUMENT 0x0D |
#define AML_TYPE_LOCAL_VARIABLE 0x0E |
#define AML_TYPE_DATA_TERM 0x0F |
/* Generic for an op that returns a value */ |
#define AML_TYPE_METHOD_CALL 0x10 |
/* Misc */ |
#define AML_TYPE_CREATE_FIELD 0x11 |
#define AML_TYPE_CREATE_OBJECT 0x12 |
#define AML_TYPE_CONTROL 0x13 |
#define AML_TYPE_NAMED_NO_OBJ 0x14 |
#define AML_TYPE_NAMED_FIELD 0x15 |
#define AML_TYPE_NAMED_SIMPLE 0x16 |
#define AML_TYPE_NAMED_COMPLEX 0x17 |
#define AML_TYPE_RETURN 0x18 |
#define AML_TYPE_UNDEFINED 0x19 |
#define AML_TYPE_BOGUS 0x1A |
/* AML Package Length encodings */ |
#define ACPI_AML_PACKAGE_TYPE1 0x40 |
#define ACPI_AML_PACKAGE_TYPE2 0x4000 |
#define ACPI_AML_PACKAGE_TYPE3 0x400000 |
#define ACPI_AML_PACKAGE_TYPE4 0x40000000 |
/* |
* Opcode classes |
*/ |
#define AML_CLASS_EXECUTE 0x00 |
#define AML_CLASS_CREATE 0x01 |
#define AML_CLASS_ARGUMENT 0x02 |
#define AML_CLASS_NAMED_OBJECT 0x03 |
#define AML_CLASS_CONTROL 0x04 |
#define AML_CLASS_ASCII 0x05 |
#define AML_CLASS_PREFIX 0x06 |
#define AML_CLASS_INTERNAL 0x07 |
#define AML_CLASS_RETURN_VALUE 0x08 |
#define AML_CLASS_METHOD_CALL 0x09 |
#define AML_CLASS_UNKNOWN 0x0A |
/* Comparison operation codes for match_op operator */ |
typedef enum { |
MATCH_MTR = 0, |
MATCH_MEQ = 1, |
MATCH_MLE = 2, |
MATCH_MLT = 3, |
MATCH_MGE = 4, |
MATCH_MGT = 5 |
} AML_MATCH_OPERATOR; |
#define MAX_MATCH_OPERATOR 5 |
/* |
* field_flags |
* |
* This byte is extracted from the AML and includes three separate |
* pieces of information about the field: |
* 1) The field access type |
* 2) The field update rule |
* 3) The lock rule for the field |
* |
* Bits 00 - 03 : access_type (any_acc, byte_acc, etc.) |
* 04 : lock_rule (1 == Lock) |
* 05 - 06 : update_rule |
*/ |
#define AML_FIELD_ACCESS_TYPE_MASK 0x0F |
#define AML_FIELD_LOCK_RULE_MASK 0x10 |
#define AML_FIELD_UPDATE_RULE_MASK 0x60 |
/* 1) Field Access Types */ |
typedef enum { |
AML_FIELD_ACCESS_ANY = 0x00, |
AML_FIELD_ACCESS_BYTE = 0x01, |
AML_FIELD_ACCESS_WORD = 0x02, |
AML_FIELD_ACCESS_DWORD = 0x03, |
AML_FIELD_ACCESS_QWORD = 0x04, /* ACPI 2.0 */ |
AML_FIELD_ACCESS_BUFFER = 0x05 /* ACPI 2.0 */ |
} AML_ACCESS_TYPE; |
/* 2) Field Lock Rules */ |
typedef enum { |
AML_FIELD_LOCK_NEVER = 0x00, |
AML_FIELD_LOCK_ALWAYS = 0x10 |
} AML_LOCK_RULE; |
/* 3) Field Update Rules */ |
typedef enum { |
AML_FIELD_UPDATE_PRESERVE = 0x00, |
AML_FIELD_UPDATE_WRITE_AS_ONES = 0x20, |
AML_FIELD_UPDATE_WRITE_AS_ZEROS = 0x40 |
} AML_UPDATE_RULE; |
/* |
* Field Access Attributes. |
* This byte is extracted from the AML via the |
* access_as keyword |
*/ |
typedef enum { |
AML_FIELD_ATTRIB_QUICK = 0x02, |
AML_FIELD_ATTRIB_SEND_RCV = 0x04, |
AML_FIELD_ATTRIB_BYTE = 0x06, |
AML_FIELD_ATTRIB_WORD = 0x08, |
AML_FIELD_ATTRIB_BLOCK = 0x0A, |
AML_FIELD_ATTRIB_MULTIBYTE = 0x0B, |
AML_FIELD_ATTRIB_WORD_CALL = 0x0C, |
AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D, |
AML_FIELD_ATTRIB_RAW_BYTES = 0x0E, |
AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F |
} AML_ACCESS_ATTRIBUTE; |
/* Bit fields in the AML method_flags byte */ |
#define AML_METHOD_ARG_COUNT 0x07 |
#define AML_METHOD_SERIALIZED 0x08 |
#define AML_METHOD_SYNC_LEVEL 0xF0 |
#endif /* __AMLCODE_H__ */ |
/drivers/acpi/acpica/amlresrc.h |
---|
0,0 → 1,486 |
/****************************************************************************** |
* |
* Module Name: amlresrc.h - AML resource descriptors |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
/* acpisrc:struct_defs -- for acpisrc conversion */ |
#ifndef __AMLRESRC_H |
#define __AMLRESRC_H |
/* |
* Resource descriptor tags, as defined in the ACPI specification. |
* Used to symbolically reference fields within a descriptor. |
*/ |
#define ACPI_RESTAG_ADDRESS "_ADR" |
#define ACPI_RESTAG_ALIGNMENT "_ALN" |
#define ACPI_RESTAG_ADDRESSSPACE "_ASI" |
#define ACPI_RESTAG_ACCESSSIZE "_ASZ" |
#define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT" |
#define ACPI_RESTAG_BASEADDRESS "_BAS" |
#define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */ |
#define ACPI_RESTAG_DEBOUNCETIME "_DBT" |
#define ACPI_RESTAG_DECODE "_DEC" |
#define ACPI_RESTAG_DEVICEPOLARITY "_DPL" |
#define ACPI_RESTAG_DMA "_DMA" |
#define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ |
#define ACPI_RESTAG_DRIVESTRENGTH "_DRS" |
#define ACPI_RESTAG_ENDIANNESS "_END" |
#define ACPI_RESTAG_FLOWCONTROL "_FLC" |
#define ACPI_RESTAG_GRANULARITY "_GRA" |
#define ACPI_RESTAG_INTERRUPT "_INT" |
#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ |
#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */ |
#define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ |
#define ACPI_RESTAG_IORESTRICTION "_IOR" |
#define ACPI_RESTAG_LENGTH "_LEN" |
#define ACPI_RESTAG_LINE "_LIN" |
#define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ |
#define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ |
#define ACPI_RESTAG_MAXADDR "_MAX" |
#define ACPI_RESTAG_MINADDR "_MIN" |
#define ACPI_RESTAG_MAXTYPE "_MAF" |
#define ACPI_RESTAG_MINTYPE "_MIF" |
#define ACPI_RESTAG_MODE "_MOD" |
#define ACPI_RESTAG_PARITY "_PAR" |
#define ACPI_RESTAG_PHASE "_PHA" |
#define ACPI_RESTAG_PIN "_PIN" |
#define ACPI_RESTAG_PINCONFIG "_PPI" |
#define ACPI_RESTAG_POLARITY "_POL" |
#define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" |
#define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" |
#define ACPI_RESTAG_RANGETYPE "_RNG" |
#define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */ |
#define ACPI_RESTAG_LENGTH_RX "_RXL" |
#define ACPI_RESTAG_LENGTH_TX "_TXL" |
#define ACPI_RESTAG_SLAVEMODE "_SLV" |
#define ACPI_RESTAG_SPEED "_SPE" |
#define ACPI_RESTAG_STOPBITS "_STB" |
#define ACPI_RESTAG_TRANSLATION "_TRA" |
#define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ |
#define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ |
#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8And16(1), 16(2) */ |
#define ACPI_RESTAG_VENDORDATA "_VEN" |
/* Default sizes for "small" resource descriptors */ |
#define ASL_RDESC_IRQ_SIZE 0x02 |
#define ASL_RDESC_DMA_SIZE 0x02 |
#define ASL_RDESC_ST_DEPEND_SIZE 0x00 |
#define ASL_RDESC_END_DEPEND_SIZE 0x00 |
#define ASL_RDESC_IO_SIZE 0x07 |
#define ASL_RDESC_FIXED_IO_SIZE 0x03 |
#define ASL_RDESC_FIXED_DMA_SIZE 0x05 |
#define ASL_RDESC_END_TAG_SIZE 0x01 |
struct asl_resource_node { |
u32 buffer_length; |
void *buffer; |
struct asl_resource_node *next; |
}; |
struct asl_resource_info { |
union acpi_parse_object *descriptor_type_op; /* Resource descriptor parse node */ |
union acpi_parse_object *mapping_op; /* Used for mapfile support */ |
u32 current_byte_offset; /* Offset in resource template */ |
}; |
/* Macros used to generate AML resource length fields */ |
#define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (struct aml_resource_large_header)) |
#define ACPI_AML_SIZE_SMALL(r) (sizeof (r) - sizeof (struct aml_resource_small_header)) |
/* |
* Resource descriptors defined in the ACPI specification. |
* |
* Packing/alignment must be BYTE because these descriptors |
* are used to overlay the raw AML byte stream. |
*/ |
#pragma pack(1) |
/* |
* SMALL descriptors |
*/ |
#define AML_RESOURCE_SMALL_HEADER_COMMON \ |
u8 descriptor_type; |
struct aml_resource_small_header { |
AML_RESOURCE_SMALL_HEADER_COMMON}; |
struct aml_resource_irq { |
AML_RESOURCE_SMALL_HEADER_COMMON u16 irq_mask; |
u8 flags; |
}; |
struct aml_resource_irq_noflags { |
AML_RESOURCE_SMALL_HEADER_COMMON u16 irq_mask; |
}; |
struct aml_resource_dma { |
AML_RESOURCE_SMALL_HEADER_COMMON u8 dma_channel_mask; |
u8 flags; |
}; |
struct aml_resource_start_dependent { |
AML_RESOURCE_SMALL_HEADER_COMMON u8 flags; |
}; |
struct aml_resource_start_dependent_noprio { |
AML_RESOURCE_SMALL_HEADER_COMMON}; |
struct aml_resource_end_dependent { |
AML_RESOURCE_SMALL_HEADER_COMMON}; |
struct aml_resource_io { |
AML_RESOURCE_SMALL_HEADER_COMMON u8 flags; |
u16 minimum; |
u16 maximum; |
u8 alignment; |
u8 address_length; |
}; |
struct aml_resource_fixed_io { |
AML_RESOURCE_SMALL_HEADER_COMMON u16 address; |
u8 address_length; |
}; |
struct aml_resource_vendor_small { |
AML_RESOURCE_SMALL_HEADER_COMMON}; |
struct aml_resource_end_tag { |
AML_RESOURCE_SMALL_HEADER_COMMON u8 checksum; |
}; |
struct aml_resource_fixed_dma { |
AML_RESOURCE_SMALL_HEADER_COMMON u16 request_lines; |
u16 channels; |
u8 width; |
}; |
/* |
* LARGE descriptors |
*/ |
#define AML_RESOURCE_LARGE_HEADER_COMMON \ |
u8 descriptor_type;\ |
u16 resource_length; |
struct aml_resource_large_header { |
AML_RESOURCE_LARGE_HEADER_COMMON}; |
/* General Flags for address space resource descriptors */ |
#define ACPI_RESOURCE_FLAG_DEC 2 |
#define ACPI_RESOURCE_FLAG_MIF 4 |
#define ACPI_RESOURCE_FLAG_MAF 8 |
struct aml_resource_memory24 { |
AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; |
u16 minimum; |
u16 maximum; |
u16 alignment; |
u16 address_length; |
}; |
struct aml_resource_vendor_large { |
AML_RESOURCE_LARGE_HEADER_COMMON}; |
struct aml_resource_memory32 { |
AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; |
u32 minimum; |
u32 maximum; |
u32 alignment; |
u32 address_length; |
}; |
struct aml_resource_fixed_memory32 { |
AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; |
u32 address; |
u32 address_length; |
}; |
#define AML_RESOURCE_ADDRESS_COMMON \ |
u8 resource_type; \ |
u8 flags; \ |
u8 specific_flags; |
struct aml_resource_address { |
AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_ADDRESS_COMMON}; |
struct aml_resource_extended_address64 { |
AML_RESOURCE_LARGE_HEADER_COMMON |
AML_RESOURCE_ADDRESS_COMMON u8 revision_ID; |
u8 reserved; |
u64 granularity; |
u64 minimum; |
u64 maximum; |
u64 translation_offset; |
u64 address_length; |
u64 type_specific; |
}; |
#define AML_RESOURCE_EXTENDED_ADDRESS_REVISION 1 /* ACPI 3.0 */ |
struct aml_resource_address64 { |
AML_RESOURCE_LARGE_HEADER_COMMON |
AML_RESOURCE_ADDRESS_COMMON u64 granularity; |
u64 minimum; |
u64 maximum; |
u64 translation_offset; |
u64 address_length; |
}; |
struct aml_resource_address32 { |
AML_RESOURCE_LARGE_HEADER_COMMON |
AML_RESOURCE_ADDRESS_COMMON u32 granularity; |
u32 minimum; |
u32 maximum; |
u32 translation_offset; |
u32 address_length; |
}; |
struct aml_resource_address16 { |
AML_RESOURCE_LARGE_HEADER_COMMON |
AML_RESOURCE_ADDRESS_COMMON u16 granularity; |
u16 minimum; |
u16 maximum; |
u16 translation_offset; |
u16 address_length; |
}; |
struct aml_resource_extended_irq { |
AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; |
u8 interrupt_count; |
u32 interrupts[1]; |
/* res_source_index, res_source optional fields follow */ |
}; |
struct aml_resource_generic_register { |
AML_RESOURCE_LARGE_HEADER_COMMON u8 address_space_id; |
u8 bit_width; |
u8 bit_offset; |
u8 access_size; /* ACPI 3.0, was previously Reserved */ |
u64 address; |
}; |
/* Common descriptor for gpio_int and gpio_io (ACPI 5.0) */ |
struct aml_resource_gpio { |
AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; |
u8 connection_type; |
u16 flags; |
u16 int_flags; |
u8 pin_config; |
u16 drive_strength; |
u16 debounce_timeout; |
u16 pin_table_offset; |
u8 res_source_index; |
u16 res_source_offset; |
u16 vendor_offset; |
u16 vendor_length; |
/* |
* Optional fields follow immediately: |
* 1) PIN list (Words) |
* 2) Resource Source String |
* 3) Vendor Data bytes |
*/ |
}; |
#define AML_RESOURCE_GPIO_REVISION 1 /* ACPI 5.0 */ |
/* Values for connection_type above */ |
#define AML_RESOURCE_GPIO_TYPE_INT 0 |
#define AML_RESOURCE_GPIO_TYPE_IO 1 |
#define AML_RESOURCE_MAX_GPIOTYPE 1 |
/* Common preamble for all serial descriptors (ACPI 5.0) */ |
#define AML_RESOURCE_SERIAL_COMMON \ |
u8 revision_id; \ |
u8 res_source_index; \ |
u8 type; \ |
u8 flags; \ |
u16 type_specific_flags; \ |
u8 type_revision_id; \ |
u16 type_data_length; \ |
/* Values for the type field above */ |
#define AML_RESOURCE_I2C_SERIALBUSTYPE 1 |
#define AML_RESOURCE_SPI_SERIALBUSTYPE 2 |
#define AML_RESOURCE_UART_SERIALBUSTYPE 3 |
#define AML_RESOURCE_MAX_SERIALBUSTYPE 3 |
#define AML_RESOURCE_VENDOR_SERIALBUSTYPE 192 /* Vendor defined is 0xC0-0xFF (NOT SUPPORTED) */ |
struct aml_resource_common_serialbus { |
AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_SERIAL_COMMON}; |
struct aml_resource_i2c_serialbus { |
AML_RESOURCE_LARGE_HEADER_COMMON |
AML_RESOURCE_SERIAL_COMMON u32 connection_speed; |
u16 slave_address; |
/* |
* Optional fields follow immediately: |
* 1) Vendor Data bytes |
* 2) Resource Source String |
*/ |
}; |
#define AML_RESOURCE_I2C_REVISION 1 /* ACPI 5.0 */ |
#define AML_RESOURCE_I2C_TYPE_REVISION 1 /* ACPI 5.0 */ |
#define AML_RESOURCE_I2C_MIN_DATA_LEN 6 |
struct aml_resource_spi_serialbus { |
AML_RESOURCE_LARGE_HEADER_COMMON |
AML_RESOURCE_SERIAL_COMMON u32 connection_speed; |
u8 data_bit_length; |
u8 clock_phase; |
u8 clock_polarity; |
u16 device_selection; |
/* |
* Optional fields follow immediately: |
* 1) Vendor Data bytes |
* 2) Resource Source String |
*/ |
}; |
#define AML_RESOURCE_SPI_REVISION 1 /* ACPI 5.0 */ |
#define AML_RESOURCE_SPI_TYPE_REVISION 1 /* ACPI 5.0 */ |
#define AML_RESOURCE_SPI_MIN_DATA_LEN 9 |
struct aml_resource_uart_serialbus { |
AML_RESOURCE_LARGE_HEADER_COMMON |
AML_RESOURCE_SERIAL_COMMON u32 default_baud_rate; |
u16 rx_fifo_size; |
u16 tx_fifo_size; |
u8 parity; |
u8 lines_enabled; |
/* |
* Optional fields follow immediately: |
* 1) Vendor Data bytes |
* 2) Resource Source String |
*/ |
}; |
#define AML_RESOURCE_UART_REVISION 1 /* ACPI 5.0 */ |
#define AML_RESOURCE_UART_TYPE_REVISION 1 /* ACPI 5.0 */ |
#define AML_RESOURCE_UART_MIN_DATA_LEN 10 |
/* restore default alignment */ |
#pragma pack() |
/* Union of all resource descriptors, so we can allocate the worst case */ |
union aml_resource { |
/* Descriptor headers */ |
u8 descriptor_type; |
struct aml_resource_small_header small_header; |
struct aml_resource_large_header large_header; |
/* Small resource descriptors */ |
struct aml_resource_irq irq; |
struct aml_resource_dma dma; |
struct aml_resource_start_dependent start_dpf; |
struct aml_resource_end_dependent end_dpf; |
struct aml_resource_io io; |
struct aml_resource_fixed_io fixed_io; |
struct aml_resource_fixed_dma fixed_dma; |
struct aml_resource_vendor_small vendor_small; |
struct aml_resource_end_tag end_tag; |
/* Large resource descriptors */ |
struct aml_resource_memory24 memory24; |
struct aml_resource_generic_register generic_reg; |
struct aml_resource_vendor_large vendor_large; |
struct aml_resource_memory32 memory32; |
struct aml_resource_fixed_memory32 fixed_memory32; |
struct aml_resource_address16 address16; |
struct aml_resource_address32 address32; |
struct aml_resource_address64 address64; |
struct aml_resource_extended_address64 ext_address64; |
struct aml_resource_extended_irq extended_irq; |
struct aml_resource_gpio gpio; |
struct aml_resource_i2c_serialbus i2c_serial_bus; |
struct aml_resource_spi_serialbus spi_serial_bus; |
struct aml_resource_uart_serialbus uart_serial_bus; |
struct aml_resource_common_serialbus common_serial_bus; |
/* Utility overlays */ |
struct aml_resource_address address; |
u32 dword_item; |
u16 word_item; |
u8 byte_item; |
}; |
/* Interfaces used by both the disassembler and compiler */ |
void |
mp_save_gpio_info(union acpi_parse_object *op, |
union aml_resource *resource, |
u32 pin_count, u16 *pin_list, char *device_name); |
void |
mp_save_serial_info(union acpi_parse_object *op, |
union aml_resource *resource, char *device_name); |
char *mp_get_hid_from_parse_tree(struct acpi_namespace_node *hid_node); |
char *mp_get_hid_via_namestring(char *device_name); |
char *mp_get_connection_info(union acpi_parse_object *op, |
u32 pin_index, |
struct acpi_namespace_node **target_node, |
char **target_name); |
char *mp_get_parent_device_hid(union acpi_parse_object *op, |
struct acpi_namespace_node **target_node, |
char **parent_device_name); |
char *mp_get_ddn_value(char *device_name); |
char *mp_get_hid_value(struct acpi_namespace_node *device_node); |
#endif |
/drivers/acpi/acpica/dbcmds.c |
---|
0,0 → 1,1187 |
/******************************************************************************* |
* |
* Module Name: dbcmds - Miscellaneous debug commands and output routines |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acdebug.h" |
#include "acnamesp.h" |
#include "acresrc.h" |
#include "actables.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbcmds") |
/* Local prototypes */ |
static void |
acpi_dm_compare_aml_resources(u8 *aml1_buffer, |
acpi_rsdesc_size aml1_buffer_length, |
u8 *aml2_buffer, |
acpi_rsdesc_size aml2_buffer_length); |
static acpi_status |
acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name); |
static acpi_status |
acpi_db_resource_callback(struct acpi_resource *resource, void *context); |
static acpi_status |
acpi_db_device_resources(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value); |
static void acpi_db_do_one_sleep_state(u8 sleep_state); |
static char *acpi_db_trace_method_name = NULL; |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_convert_to_node |
* |
* PARAMETERS: in_string - String to convert |
* |
* RETURN: Pointer to a NS node |
* |
* DESCRIPTION: Convert a string to a valid NS pointer. Handles numeric or |
* alphanumeric strings. |
* |
******************************************************************************/ |
struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string) |
{ |
struct acpi_namespace_node *node; |
acpi_size address; |
if ((*in_string >= 0x30) && (*in_string <= 0x39)) { |
/* Numeric argument, convert */ |
address = strtoul(in_string, NULL, 16); |
node = ACPI_TO_POINTER(address); |
if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) { |
acpi_os_printf("Address %p is invalid", node); |
return (NULL); |
} |
/* Make sure pointer is valid NS node */ |
if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { |
acpi_os_printf |
("Address %p is not a valid namespace node [%s]\n", |
node, acpi_ut_get_descriptor_name(node)); |
return (NULL); |
} |
} else { |
/* |
* Alpha argument: The parameter is a name string that must be |
* resolved to a Namespace object. |
*/ |
node = acpi_db_local_ns_lookup(in_string); |
if (!node) { |
acpi_os_printf |
("Could not find [%s] in namespace, defaulting to root node\n", |
in_string); |
node = acpi_gbl_root_node; |
} |
} |
return (node); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_sleep |
* |
* PARAMETERS: object_arg - Desired sleep state (0-5). NULL means |
* invoke all possible sleep states. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Simulate sleep/wake sequences |
* |
******************************************************************************/ |
acpi_status acpi_db_sleep(char *object_arg) |
{ |
u8 sleep_state; |
u32 i; |
ACPI_FUNCTION_TRACE(acpi_db_sleep); |
/* Null input (no arguments) means to invoke all sleep states */ |
if (!object_arg) { |
acpi_os_printf("Invoking all possible sleep states, 0-%d\n", |
ACPI_S_STATES_MAX); |
for (i = 0; i <= ACPI_S_STATES_MAX; i++) { |
acpi_db_do_one_sleep_state((u8)i); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* Convert argument to binary and invoke the sleep state */ |
sleep_state = (u8)strtoul(object_arg, NULL, 0); |
acpi_db_do_one_sleep_state(sleep_state); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_do_one_sleep_state |
* |
* PARAMETERS: sleep_state - Desired sleep state (0-5) |
* |
* RETURN: None |
* |
* DESCRIPTION: Simulate a sleep/wake sequence |
* |
******************************************************************************/ |
static void acpi_db_do_one_sleep_state(u8 sleep_state) |
{ |
acpi_status status; |
u8 sleep_type_a; |
u8 sleep_type_b; |
/* Validate parameter */ |
if (sleep_state > ACPI_S_STATES_MAX) { |
acpi_os_printf("Sleep state %d out of range (%d max)\n", |
sleep_state, ACPI_S_STATES_MAX); |
return; |
} |
acpi_os_printf("\n---- Invoking sleep state S%d (%s):\n", |
sleep_state, acpi_gbl_sleep_state_names[sleep_state]); |
/* Get the values for the sleep type registers (for display only) */ |
status = |
acpi_get_sleep_type_data(sleep_state, &sleep_type_a, &sleep_type_b); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not evaluate [%s] method, %s\n", |
acpi_gbl_sleep_state_names[sleep_state], |
acpi_format_exception(status)); |
return; |
} |
acpi_os_printf |
("Register values for sleep state S%d: Sleep-A: %.2X, Sleep-B: %.2X\n", |
sleep_state, sleep_type_a, sleep_type_b); |
/* Invoke the various sleep/wake interfaces */ |
acpi_os_printf("**** Sleep: Prepare to sleep (S%d) ****\n", |
sleep_state); |
status = acpi_enter_sleep_state_prep(sleep_state); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
acpi_os_printf("**** Sleep: Going to sleep (S%d) ****\n", sleep_state); |
status = acpi_enter_sleep_state(sleep_state); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
acpi_os_printf("**** Wake: Prepare to return from sleep (S%d) ****\n", |
sleep_state); |
status = acpi_leave_sleep_state_prep(sleep_state); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
acpi_os_printf("**** Wake: Return from sleep (S%d) ****\n", |
sleep_state); |
status = acpi_leave_sleep_state(sleep_state); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
return; |
error_exit: |
ACPI_EXCEPTION((AE_INFO, status, "During invocation of sleep state S%d", |
sleep_state)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_locks |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display information about internal mutexes. |
* |
******************************************************************************/ |
void acpi_db_display_locks(void) |
{ |
u32 i; |
for (i = 0; i < ACPI_MAX_MUTEX; i++) { |
acpi_os_printf("%26s : %s\n", acpi_ut_get_mutex_name(i), |
acpi_gbl_mutex_info[i].thread_id == |
ACPI_MUTEX_NOT_ACQUIRED ? "Locked" : "Unlocked"); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_table_info |
* |
* PARAMETERS: table_arg - Name of table to be displayed |
* |
* RETURN: None |
* |
* DESCRIPTION: Display information about loaded tables. Current |
* implementation displays all loaded tables. |
* |
******************************************************************************/ |
void acpi_db_display_table_info(char *table_arg) |
{ |
u32 i; |
struct acpi_table_desc *table_desc; |
acpi_status status; |
/* Header */ |
acpi_os_printf("Idx ID Status Type " |
"TableHeader (Sig, Address, Length, Misc)\n"); |
/* Walk the entire root table list */ |
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { |
table_desc = &acpi_gbl_root_table_list.tables[i]; |
/* Index and Table ID */ |
acpi_os_printf("%3u %.2u ", i, table_desc->owner_id); |
/* Decode the table flags */ |
if (!(table_desc->flags & ACPI_TABLE_IS_LOADED)) { |
acpi_os_printf("NotLoaded "); |
} else { |
acpi_os_printf(" Loaded "); |
} |
switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { |
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: |
acpi_os_printf("External/virtual "); |
break; |
case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: |
acpi_os_printf("Internal/physical "); |
break; |
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: |
acpi_os_printf("Internal/virtual "); |
break; |
default: |
acpi_os_printf("INVALID TYPE "); |
break; |
} |
/* Make sure that the table is mapped */ |
status = acpi_tb_validate_table(table_desc); |
if (ACPI_FAILURE(status)) { |
return; |
} |
/* Dump the table header */ |
if (table_desc->pointer) { |
acpi_tb_print_table_header(table_desc->address, |
table_desc->pointer); |
} else { |
/* If the pointer is null, the table has been unloaded */ |
ACPI_INFO((AE_INFO, "%4.4s - Table has been unloaded", |
table_desc->signature.ascii)); |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_unload_acpi_table |
* |
* PARAMETERS: object_name - Namespace pathname for an object that |
* is owned by the table to be unloaded |
* |
* RETURN: None |
* |
* DESCRIPTION: Unload an ACPI table, via any namespace node that is owned |
* by the table. |
* |
******************************************************************************/ |
void acpi_db_unload_acpi_table(char *object_name) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
/* Translate name to an Named object */ |
node = acpi_db_convert_to_node(object_name); |
if (!node) { |
return; |
} |
status = acpi_unload_parent_table(ACPI_CAST_PTR(acpi_handle, node)); |
if (ACPI_SUCCESS(status)) { |
acpi_os_printf("Parent of [%s] (%p) unloaded and uninstalled\n", |
object_name, node); |
} else { |
acpi_os_printf("%s, while unloading parent table of [%s]\n", |
acpi_format_exception(status), object_name); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_send_notify |
* |
* PARAMETERS: name - Name of ACPI object where to send notify |
* value - Value of the notify to send. |
* |
* RETURN: None |
* |
* DESCRIPTION: Send an ACPI notification. The value specified is sent to the |
* named object as an ACPI notify. |
* |
******************************************************************************/ |
void acpi_db_send_notify(char *name, u32 value) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
/* Translate name to an Named object */ |
node = acpi_db_convert_to_node(name); |
if (!node) { |
return; |
} |
/* Dispatch the notify if legal */ |
if (acpi_ev_is_notify_object(node)) { |
status = acpi_ev_queue_notify_request(node, value); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not queue notify\n"); |
} |
} else { |
acpi_os_printf("Named object [%4.4s] Type %s, " |
"must be Device/Thermal/Processor type\n", |
acpi_ut_get_node_name(node), |
acpi_ut_get_type_name(node->type)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_interfaces |
* |
* PARAMETERS: action_arg - Null, "install", or "remove" |
* interface_name_arg - Name for install/remove options |
* |
* RETURN: None |
* |
* DESCRIPTION: Display or modify the global _OSI interface list |
* |
******************************************************************************/ |
void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg) |
{ |
struct acpi_interface_info *next_interface; |
char *sub_string; |
acpi_status status; |
/* If no arguments, just display current interface list */ |
if (!action_arg) { |
(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, |
ACPI_WAIT_FOREVER); |
next_interface = acpi_gbl_supported_interfaces; |
while (next_interface) { |
if (!(next_interface->flags & ACPI_OSI_INVALID)) { |
acpi_os_printf("%s\n", next_interface->name); |
} |
next_interface = next_interface->next; |
} |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
return; |
} |
/* If action_arg exists, so must interface_name_arg */ |
if (!interface_name_arg) { |
acpi_os_printf("Missing Interface Name argument\n"); |
return; |
} |
/* Uppercase the action for match below */ |
acpi_ut_strupr(action_arg); |
/* install - install an interface */ |
sub_string = strstr("INSTALL", action_arg); |
if (sub_string) { |
status = acpi_install_interface(interface_name_arg); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("%s, while installing \"%s\"\n", |
acpi_format_exception(status), |
interface_name_arg); |
} |
return; |
} |
/* remove - remove an interface */ |
sub_string = strstr("REMOVE", action_arg); |
if (sub_string) { |
status = acpi_remove_interface(interface_name_arg); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("%s, while removing \"%s\"\n", |
acpi_format_exception(status), |
interface_name_arg); |
} |
return; |
} |
/* Invalid action_arg */ |
acpi_os_printf("Invalid action argument: %s\n", action_arg); |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_template |
* |
* PARAMETERS: buffer_arg - Buffer name or address |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump a buffer that contains a resource template |
* |
******************************************************************************/ |
void acpi_db_display_template(char *buffer_arg) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
struct acpi_buffer return_buffer; |
/* Translate buffer_arg to an Named object */ |
node = acpi_db_convert_to_node(buffer_arg); |
if (!node || (node == acpi_gbl_root_node)) { |
acpi_os_printf("Invalid argument: %s\n", buffer_arg); |
return; |
} |
/* We must have a buffer object */ |
if (node->type != ACPI_TYPE_BUFFER) { |
acpi_os_printf |
("Not a Buffer object, cannot be a template: %s\n", |
buffer_arg); |
return; |
} |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
return_buffer.pointer = acpi_gbl_db_buffer; |
/* Attempt to convert the raw buffer to a resource list */ |
status = acpi_rs_create_resource_list(node->object, &return_buffer); |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
acpi_dbg_level |= ACPI_LV_RESOURCES; |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("Could not convert Buffer to a resource list: %s, %s\n", |
buffer_arg, acpi_format_exception(status)); |
goto dump_buffer; |
} |
/* Now we can dump the resource list */ |
acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource, |
return_buffer.pointer)); |
dump_buffer: |
acpi_os_printf("\nRaw data buffer:\n"); |
acpi_ut_debug_dump_buffer((u8 *)node->object->buffer.pointer, |
node->object->buffer.length, |
DB_BYTE_DISPLAY, ACPI_UINT32_MAX); |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_dm_compare_aml_resources |
* |
* PARAMETERS: aml1_buffer - Contains first resource list |
* aml1_buffer_length - Length of first resource list |
* aml2_buffer - Contains second resource list |
* aml2_buffer_length - Length of second resource list |
* |
* RETURN: None |
* |
* DESCRIPTION: Compare two AML resource lists, descriptor by descriptor (in |
* order to isolate a miscompare to an individual resource) |
* |
******************************************************************************/ |
static void |
acpi_dm_compare_aml_resources(u8 *aml1_buffer, |
acpi_rsdesc_size aml1_buffer_length, |
u8 *aml2_buffer, |
acpi_rsdesc_size aml2_buffer_length) |
{ |
u8 *aml1; |
u8 *aml2; |
u8 *aml1_end; |
u8 *aml2_end; |
acpi_rsdesc_size aml1_length; |
acpi_rsdesc_size aml2_length; |
acpi_rsdesc_size offset = 0; |
u8 resource_type; |
u32 count = 0; |
u32 i; |
/* Compare overall buffer sizes (may be different due to size rounding) */ |
if (aml1_buffer_length != aml2_buffer_length) { |
acpi_os_printf("**** Buffer length mismatch in converted " |
"AML: Original %X, New %X ****\n", |
aml1_buffer_length, aml2_buffer_length); |
} |
aml1 = aml1_buffer; |
aml2 = aml2_buffer; |
aml1_end = aml1_buffer + aml1_buffer_length; |
aml2_end = aml2_buffer + aml2_buffer_length; |
/* Walk the descriptor lists, comparing each descriptor */ |
while ((aml1 < aml1_end) && (aml2 < aml2_end)) { |
/* Get the lengths of each descriptor */ |
aml1_length = acpi_ut_get_descriptor_length(aml1); |
aml2_length = acpi_ut_get_descriptor_length(aml2); |
resource_type = acpi_ut_get_resource_type(aml1); |
/* Check for descriptor length match */ |
if (aml1_length != aml2_length) { |
acpi_os_printf |
("**** Length mismatch in descriptor [%.2X] type %2.2X, " |
"Offset %8.8X Len1 %X, Len2 %X ****\n", count, |
resource_type, offset, aml1_length, aml2_length); |
} |
/* Check for descriptor byte match */ |
else if (memcmp(aml1, aml2, aml1_length)) { |
acpi_os_printf |
("**** Data mismatch in descriptor [%.2X] type %2.2X, " |
"Offset %8.8X ****\n", count, resource_type, |
offset); |
for (i = 0; i < aml1_length; i++) { |
if (aml1[i] != aml2[i]) { |
acpi_os_printf |
("Mismatch at byte offset %.2X: is %2.2X, " |
"should be %2.2X\n", i, aml2[i], |
aml1[i]); |
} |
} |
} |
/* Exit on end_tag descriptor */ |
if (resource_type == ACPI_RESOURCE_NAME_END_TAG) { |
return; |
} |
/* Point to next descriptor in each buffer */ |
count++; |
offset += aml1_length; |
aml1 += aml1_length; |
aml2 += aml2_length; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_dm_test_resource_conversion |
* |
* PARAMETERS: node - Parent device node |
* name - resource method name (_CRS) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Compare the original AML with a conversion of the AML to |
* internal resource list, then back to AML. |
* |
******************************************************************************/ |
static acpi_status |
acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name) |
{ |
acpi_status status; |
struct acpi_buffer return_buffer; |
struct acpi_buffer resource_buffer; |
struct acpi_buffer new_aml; |
union acpi_object *original_aml; |
acpi_os_printf("Resource Conversion Comparison:\n"); |
new_aml.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
resource_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
/* Get the original _CRS AML resource template */ |
status = acpi_evaluate_object(node, name, NULL, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not obtain %s: %s\n", |
name, acpi_format_exception(status)); |
return (status); |
} |
/* Get the AML resource template, converted to internal resource structs */ |
status = acpi_get_current_resources(node, &resource_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiGetCurrentResources failed: %s\n", |
acpi_format_exception(status)); |
goto exit1; |
} |
/* Convert internal resource list to external AML resource template */ |
status = acpi_rs_create_aml_resources(&resource_buffer, &new_aml); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiRsCreateAmlResources failed: %s\n", |
acpi_format_exception(status)); |
goto exit2; |
} |
/* Compare original AML to the newly created AML resource list */ |
original_aml = return_buffer.pointer; |
acpi_dm_compare_aml_resources(original_aml->buffer.pointer, |
(acpi_rsdesc_size) original_aml->buffer. |
length, new_aml.pointer, |
(acpi_rsdesc_size) new_aml.length); |
/* Cleanup and exit */ |
ACPI_FREE(new_aml.pointer); |
exit2: |
ACPI_FREE(resource_buffer.pointer); |
exit1: |
ACPI_FREE(return_buffer.pointer); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_resource_callback |
* |
* PARAMETERS: acpi_walk_resource_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Simple callback to exercise acpi_walk_resources and |
* acpi_walk_resource_buffer. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_resource_callback(struct acpi_resource *resource, void *context) |
{ |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_device_resources |
* |
* PARAMETERS: acpi_walk_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Display the _PRT/_CRS/_PRS resources for a device object. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_device_resources(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value) |
{ |
struct acpi_namespace_node *node; |
struct acpi_namespace_node *prt_node = NULL; |
struct acpi_namespace_node *crs_node = NULL; |
struct acpi_namespace_node *prs_node = NULL; |
struct acpi_namespace_node *aei_node = NULL; |
char *parent_path; |
struct acpi_buffer return_buffer; |
acpi_status status; |
node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
parent_path = acpi_ns_get_external_pathname(node); |
if (!parent_path) { |
return (AE_NO_MEMORY); |
} |
/* Get handles to the resource methods for this device */ |
(void)acpi_get_handle(node, METHOD_NAME__PRT, |
ACPI_CAST_PTR(acpi_handle, &prt_node)); |
(void)acpi_get_handle(node, METHOD_NAME__CRS, |
ACPI_CAST_PTR(acpi_handle, &crs_node)); |
(void)acpi_get_handle(node, METHOD_NAME__PRS, |
ACPI_CAST_PTR(acpi_handle, &prs_node)); |
(void)acpi_get_handle(node, METHOD_NAME__AEI, |
ACPI_CAST_PTR(acpi_handle, &aei_node)); |
if (!prt_node && !crs_node && !prs_node && !aei_node) { |
goto cleanup; /* Nothing to do */ |
} |
acpi_os_printf("\nDevice: %s\n", parent_path); |
/* Prepare for a return object of arbitrary size */ |
return_buffer.pointer = acpi_gbl_db_buffer; |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
/* _PRT */ |
if (prt_node) { |
acpi_os_printf("Evaluating _PRT\n"); |
status = |
acpi_evaluate_object(prt_node, NULL, NULL, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not evaluate _PRT: %s\n", |
acpi_format_exception(status)); |
goto get_crs; |
} |
return_buffer.pointer = acpi_gbl_db_buffer; |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
status = acpi_get_irq_routing_table(node, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("GetIrqRoutingTable failed: %s\n", |
acpi_format_exception(status)); |
goto get_crs; |
} |
acpi_rs_dump_irq_list(ACPI_CAST_PTR(u8, acpi_gbl_db_buffer)); |
} |
/* _CRS */ |
get_crs: |
if (crs_node) { |
acpi_os_printf("Evaluating _CRS\n"); |
return_buffer.pointer = acpi_gbl_db_buffer; |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
status = |
acpi_evaluate_object(crs_node, NULL, NULL, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not evaluate _CRS: %s\n", |
acpi_format_exception(status)); |
goto get_prs; |
} |
/* This code exercises the acpi_walk_resources interface */ |
status = acpi_walk_resources(node, METHOD_NAME__CRS, |
acpi_db_resource_callback, NULL); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiWalkResources failed: %s\n", |
acpi_format_exception(status)); |
goto get_prs; |
} |
/* Get the _CRS resource list (test ALLOCATE buffer) */ |
return_buffer.pointer = NULL; |
return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_get_current_resources(node, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiGetCurrentResources failed: %s\n", |
acpi_format_exception(status)); |
goto get_prs; |
} |
/* This code exercises the acpi_walk_resource_buffer interface */ |
status = acpi_walk_resource_buffer(&return_buffer, |
acpi_db_resource_callback, |
NULL); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiWalkResourceBuffer failed: %s\n", |
acpi_format_exception(status)); |
goto end_crs; |
} |
/* Dump the _CRS resource list */ |
acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource, |
return_buffer. |
pointer)); |
/* |
* Perform comparison of original AML to newly created AML. This |
* tests both the AML->Resource conversion and the Resource->AML |
* conversion. |
*/ |
(void)acpi_dm_test_resource_conversion(node, METHOD_NAME__CRS); |
/* Execute _SRS with the resource list */ |
acpi_os_printf("Evaluating _SRS\n"); |
status = acpi_set_current_resources(node, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiSetCurrentResources failed: %s\n", |
acpi_format_exception(status)); |
goto end_crs; |
} |
end_crs: |
ACPI_FREE(return_buffer.pointer); |
} |
/* _PRS */ |
get_prs: |
if (prs_node) { |
acpi_os_printf("Evaluating _PRS\n"); |
return_buffer.pointer = acpi_gbl_db_buffer; |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
status = |
acpi_evaluate_object(prs_node, NULL, NULL, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not evaluate _PRS: %s\n", |
acpi_format_exception(status)); |
goto get_aei; |
} |
return_buffer.pointer = acpi_gbl_db_buffer; |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
status = acpi_get_possible_resources(node, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiGetPossibleResources failed: %s\n", |
acpi_format_exception(status)); |
goto get_aei; |
} |
acpi_rs_dump_resource_list(ACPI_CAST_PTR |
(struct acpi_resource, |
acpi_gbl_db_buffer)); |
} |
/* _AEI */ |
get_aei: |
if (aei_node) { |
acpi_os_printf("Evaluating _AEI\n"); |
return_buffer.pointer = acpi_gbl_db_buffer; |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
status = |
acpi_evaluate_object(aei_node, NULL, NULL, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not evaluate _AEI: %s\n", |
acpi_format_exception(status)); |
goto cleanup; |
} |
return_buffer.pointer = acpi_gbl_db_buffer; |
return_buffer.length = ACPI_DEBUG_BUFFER_SIZE; |
status = acpi_get_event_resources(node, &return_buffer); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiGetEventResources failed: %s\n", |
acpi_format_exception(status)); |
goto cleanup; |
} |
acpi_rs_dump_resource_list(ACPI_CAST_PTR |
(struct acpi_resource, |
acpi_gbl_db_buffer)); |
} |
cleanup: |
ACPI_FREE(parent_path); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_resources |
* |
* PARAMETERS: object_arg - String object name or object pointer. |
* NULL or "*" means "display resources for |
* all devices" |
* |
* RETURN: None |
* |
* DESCRIPTION: Display the resource objects associated with a device. |
* |
******************************************************************************/ |
void acpi_db_display_resources(char *object_arg) |
{ |
struct acpi_namespace_node *node; |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
acpi_dbg_level |= ACPI_LV_RESOURCES; |
/* Asterisk means "display resources for all devices" */ |
if (!object_arg || (!strcmp(object_arg, "*"))) { |
(void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, |
acpi_db_device_resources, NULL, NULL, |
NULL); |
} else { |
/* Convert string to object pointer */ |
node = acpi_db_convert_to_node(object_arg); |
if (node) { |
if (node->type != ACPI_TYPE_DEVICE) { |
acpi_os_printf |
("%4.4s: Name is not a device object (%s)\n", |
node->name.ascii, |
acpi_ut_get_type_name(node->type)); |
} else { |
(void)acpi_db_device_resources(node, 0, NULL, |
NULL); |
} |
} |
} |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
} |
#if (!ACPI_REDUCED_HARDWARE) |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_generate_gpe |
* |
* PARAMETERS: gpe_arg - Raw GPE number, ascii string |
* block_arg - GPE block number, ascii string |
* 0 or 1 for FADT GPE blocks |
* |
* RETURN: None |
* |
* DESCRIPTION: Simulate firing of a GPE |
* |
******************************************************************************/ |
void acpi_db_generate_gpe(char *gpe_arg, char *block_arg) |
{ |
u32 block_number = 0; |
u32 gpe_number; |
struct acpi_gpe_event_info *gpe_event_info; |
gpe_number = strtoul(gpe_arg, NULL, 0); |
/* |
* If no block arg, or block arg == 0 or 1, use the FADT-defined |
* GPE blocks. |
*/ |
if (block_arg) { |
block_number = strtoul(block_arg, NULL, 0); |
if (block_number == 1) { |
block_number = 0; |
} |
} |
gpe_event_info = |
acpi_ev_get_gpe_event_info(ACPI_TO_POINTER(block_number), |
gpe_number); |
if (!gpe_event_info) { |
acpi_os_printf("Invalid GPE\n"); |
return; |
} |
(void)acpi_ev_gpe_dispatch(NULL, gpe_event_info, gpe_number); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_generate_sci |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Simulate an SCI -- just call the SCI dispatch. |
* |
******************************************************************************/ |
void acpi_db_generate_sci(void) |
{ |
acpi_ev_sci_dispatch(); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_trace |
* |
* PARAMETERS: enable_arg - ENABLE/AML to enable tracer |
* DISABLE to disable tracer |
* method_arg - Method to trace |
* once_arg - Whether trace once |
* |
* RETURN: None |
* |
* DESCRIPTION: Control method tracing facility |
* |
******************************************************************************/ |
void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg) |
{ |
u32 debug_level = 0; |
u32 debug_layer = 0; |
u32 flags = 0; |
if (enable_arg) { |
acpi_ut_strupr(enable_arg); |
} |
if (once_arg) { |
acpi_ut_strupr(once_arg); |
} |
if (method_arg) { |
if (acpi_db_trace_method_name) { |
ACPI_FREE(acpi_db_trace_method_name); |
acpi_db_trace_method_name = NULL; |
} |
acpi_db_trace_method_name = |
ACPI_ALLOCATE(strlen(method_arg) + 1); |
if (!acpi_db_trace_method_name) { |
acpi_os_printf("Failed to allocate method name (%s)\n", |
method_arg); |
return; |
} |
strcpy(acpi_db_trace_method_name, method_arg); |
} |
if (!strcmp(enable_arg, "ENABLE") || |
!strcmp(enable_arg, "METHOD") || !strcmp(enable_arg, "OPCODE")) { |
if (!strcmp(enable_arg, "ENABLE")) { |
/* Inherit current console settings */ |
debug_level = acpi_gbl_db_console_debug_level; |
debug_layer = acpi_dbg_layer; |
} else { |
/* Restrict console output to trace points only */ |
debug_level = ACPI_LV_TRACE_POINT; |
debug_layer = ACPI_EXECUTER; |
} |
flags = ACPI_TRACE_ENABLED; |
if (!strcmp(enable_arg, "OPCODE")) { |
flags |= ACPI_TRACE_OPCODE; |
} |
if (once_arg && !strcmp(once_arg, "ONCE")) { |
flags |= ACPI_TRACE_ONESHOT; |
} |
} |
(void)acpi_debug_trace(acpi_db_trace_method_name, |
debug_level, debug_layer, flags); |
} |
/drivers/acpi/acpica/dbconvert.c |
---|
0,0 → 1,484 |
/******************************************************************************* |
* |
* Module Name: dbconvert - debugger miscellaneous conversion routines |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbconvert") |
#define DB_DEFAULT_PKG_ELEMENTS 33 |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_hex_char_to_value |
* |
* PARAMETERS: hex_char - Ascii Hex digit, 0-9|a-f|A-F |
* return_value - Where the converted value is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert a single hex character to a 4-bit number (0-16). |
* |
******************************************************************************/ |
acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value) |
{ |
u8 value; |
/* Digit must be ascii [0-9a-fA-F] */ |
if (!isxdigit(hex_char)) { |
return (AE_BAD_HEX_CONSTANT); |
} |
if (hex_char <= 0x39) { |
value = (u8)(hex_char - 0x30); |
} else { |
value = (u8)(toupper(hex_char) - 0x37); |
} |
*return_value = value; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_hex_byte_to_binary |
* |
* PARAMETERS: hex_byte - Double hex digit (0x00 - 0xFF) in format: |
* hi_byte then lo_byte. |
* return_value - Where the converted value is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255). |
* |
******************************************************************************/ |
static acpi_status acpi_db_hex_byte_to_binary(char *hex_byte, u8 *return_value) |
{ |
u8 local0; |
u8 local1; |
acpi_status status; |
/* High byte */ |
status = acpi_db_hex_char_to_value(hex_byte[0], &local0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Low byte */ |
status = acpi_db_hex_char_to_value(hex_byte[1], &local1); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
*return_value = (u8)((local0 << 4) | local1); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_convert_to_buffer |
* |
* PARAMETERS: string - Input string to be converted |
* object - Where the buffer object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert a string to a buffer object. String is treated a list |
* of buffer elements, each separated by a space or comma. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_convert_to_buffer(char *string, union acpi_object *object) |
{ |
u32 i; |
u32 j; |
u32 length; |
u8 *buffer; |
acpi_status status; |
/* Generate the final buffer length */ |
for (i = 0, length = 0; string[i];) { |
i += 2; |
length++; |
while (string[i] && ((string[i] == ',') || (string[i] == ' '))) { |
i++; |
} |
} |
buffer = ACPI_ALLOCATE(length); |
if (!buffer) { |
return (AE_NO_MEMORY); |
} |
/* Convert the command line bytes to the buffer */ |
for (i = 0, j = 0; string[i];) { |
status = acpi_db_hex_byte_to_binary(&string[i], &buffer[j]); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(buffer); |
return (status); |
} |
j++; |
i += 2; |
while (string[i] && ((string[i] == ',') || (string[i] == ' '))) { |
i++; |
} |
} |
object->type = ACPI_TYPE_BUFFER; |
object->buffer.pointer = buffer; |
object->buffer.length = length; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_convert_to_package |
* |
* PARAMETERS: string - Input string to be converted |
* object - Where the package object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert a string to a package object. Handles nested packages |
* via recursion with acpi_db_convert_to_object. |
* |
******************************************************************************/ |
acpi_status acpi_db_convert_to_package(char *string, union acpi_object * object) |
{ |
char *this; |
char *next; |
u32 i; |
acpi_object_type type; |
union acpi_object *elements; |
acpi_status status; |
elements = |
ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS * |
sizeof(union acpi_object)); |
this = string; |
for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) { |
this = acpi_db_get_next_token(this, &next, &type); |
if (!this) { |
break; |
} |
/* Recursive call to convert each package element */ |
status = acpi_db_convert_to_object(type, this, &elements[i]); |
if (ACPI_FAILURE(status)) { |
acpi_db_delete_objects(i + 1, elements); |
ACPI_FREE(elements); |
return (status); |
} |
this = next; |
} |
object->type = ACPI_TYPE_PACKAGE; |
object->package.count = i; |
object->package.elements = elements; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_convert_to_object |
* |
* PARAMETERS: type - Object type as determined by parser |
* string - Input string to be converted |
* object - Where the new object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert a typed and tokenized string to an union acpi_object. Typing: |
* 1) String objects were surrounded by quotes. |
* 2) Buffer objects were surrounded by parentheses. |
* 3) Package objects were surrounded by brackets "[]". |
* 4) All standalone tokens are treated as integers. |
* |
******************************************************************************/ |
acpi_status |
acpi_db_convert_to_object(acpi_object_type type, |
char *string, union acpi_object * object) |
{ |
acpi_status status = AE_OK; |
switch (type) { |
case ACPI_TYPE_STRING: |
object->type = ACPI_TYPE_STRING; |
object->string.pointer = string; |
object->string.length = (u32)strlen(string); |
break; |
case ACPI_TYPE_BUFFER: |
status = acpi_db_convert_to_buffer(string, object); |
break; |
case ACPI_TYPE_PACKAGE: |
status = acpi_db_convert_to_package(string, object); |
break; |
default: |
object->type = ACPI_TYPE_INTEGER; |
status = acpi_ut_strtoul64(string, 16, &object->integer.value); |
break; |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_encode_pld_buffer |
* |
* PARAMETERS: pld_info - _PLD buffer struct (Using local struct) |
* |
* RETURN: Encode _PLD buffer suitable for return value from _PLD |
* |
* DESCRIPTION: Bit-packs a _PLD buffer struct. Used to test the _PLD macros |
* |
******************************************************************************/ |
u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info) |
{ |
u32 *buffer; |
u32 dword; |
buffer = ACPI_ALLOCATE_ZEROED(ACPI_PLD_BUFFER_SIZE); |
if (!buffer) { |
return (NULL); |
} |
/* First 32 bits */ |
dword = 0; |
ACPI_PLD_SET_REVISION(&dword, pld_info->revision); |
ACPI_PLD_SET_IGNORE_COLOR(&dword, pld_info->ignore_color); |
ACPI_PLD_SET_RED(&dword, pld_info->red); |
ACPI_PLD_SET_GREEN(&dword, pld_info->green); |
ACPI_PLD_SET_BLUE(&dword, pld_info->blue); |
ACPI_MOVE_32_TO_32(&buffer[0], &dword); |
/* Second 32 bits */ |
dword = 0; |
ACPI_PLD_SET_WIDTH(&dword, pld_info->width); |
ACPI_PLD_SET_HEIGHT(&dword, pld_info->height); |
ACPI_MOVE_32_TO_32(&buffer[1], &dword); |
/* Third 32 bits */ |
dword = 0; |
ACPI_PLD_SET_USER_VISIBLE(&dword, pld_info->user_visible); |
ACPI_PLD_SET_DOCK(&dword, pld_info->dock); |
ACPI_PLD_SET_LID(&dword, pld_info->lid); |
ACPI_PLD_SET_PANEL(&dword, pld_info->panel); |
ACPI_PLD_SET_VERTICAL(&dword, pld_info->vertical_position); |
ACPI_PLD_SET_HORIZONTAL(&dword, pld_info->horizontal_position); |
ACPI_PLD_SET_SHAPE(&dword, pld_info->shape); |
ACPI_PLD_SET_ORIENTATION(&dword, pld_info->group_orientation); |
ACPI_PLD_SET_TOKEN(&dword, pld_info->group_token); |
ACPI_PLD_SET_POSITION(&dword, pld_info->group_position); |
ACPI_PLD_SET_BAY(&dword, pld_info->bay); |
ACPI_MOVE_32_TO_32(&buffer[2], &dword); |
/* Fourth 32 bits */ |
dword = 0; |
ACPI_PLD_SET_EJECTABLE(&dword, pld_info->ejectable); |
ACPI_PLD_SET_OSPM_EJECT(&dword, pld_info->ospm_eject_required); |
ACPI_PLD_SET_CABINET(&dword, pld_info->cabinet_number); |
ACPI_PLD_SET_CARD_CAGE(&dword, pld_info->card_cage_number); |
ACPI_PLD_SET_REFERENCE(&dword, pld_info->reference); |
ACPI_PLD_SET_ROTATION(&dword, pld_info->rotation); |
ACPI_PLD_SET_ORDER(&dword, pld_info->order); |
ACPI_MOVE_32_TO_32(&buffer[3], &dword); |
if (pld_info->revision >= 2) { |
/* Fifth 32 bits */ |
dword = 0; |
ACPI_PLD_SET_VERT_OFFSET(&dword, pld_info->vertical_offset); |
ACPI_PLD_SET_HORIZ_OFFSET(&dword, pld_info->horizontal_offset); |
ACPI_MOVE_32_TO_32(&buffer[4], &dword); |
} |
return (ACPI_CAST_PTR(u8, buffer)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_pld_buffer |
* |
* PARAMETERS: obj_desc - Object returned from _PLD method |
* |
* RETURN: None. |
* |
* DESCRIPTION: Dumps formatted contents of a _PLD return buffer. |
* |
******************************************************************************/ |
#define ACPI_PLD_OUTPUT "%20s : %-6X\n" |
void acpi_db_dump_pld_buffer(union acpi_object *obj_desc) |
{ |
union acpi_object *buffer_desc; |
struct acpi_pld_info *pld_info; |
u8 *new_buffer; |
acpi_status status; |
/* Object must be of type Package with at least one Buffer element */ |
if (obj_desc->type != ACPI_TYPE_PACKAGE) { |
return; |
} |
buffer_desc = &obj_desc->package.elements[0]; |
if (buffer_desc->type != ACPI_TYPE_BUFFER) { |
return; |
} |
/* Convert _PLD buffer to local _PLD struct */ |
status = acpi_decode_pld_buffer(buffer_desc->buffer.pointer, |
buffer_desc->buffer.length, &pld_info); |
if (ACPI_FAILURE(status)) { |
return; |
} |
/* Encode local _PLD struct back to a _PLD buffer */ |
new_buffer = acpi_db_encode_pld_buffer(pld_info); |
if (!new_buffer) { |
return; |
} |
/* The two bit-packed buffers should match */ |
if (memcmp(new_buffer, buffer_desc->buffer.pointer, |
buffer_desc->buffer.length)) { |
acpi_os_printf |
("Converted _PLD buffer does not compare. New:\n"); |
acpi_ut_dump_buffer(new_buffer, |
buffer_desc->buffer.length, DB_BYTE_DISPLAY, |
0); |
} |
/* First 32-bit dword */ |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Revision", pld_info->revision); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_IgnoreColor", |
pld_info->ignore_color); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Red", pld_info->red); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Green", pld_info->green); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Blue", pld_info->blue); |
/* Second 32-bit dword */ |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Width", pld_info->width); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Height", pld_info->height); |
/* Third 32-bit dword */ |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_UserVisible", |
pld_info->user_visible); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Dock", pld_info->dock); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Lid", pld_info->lid); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Panel", pld_info->panel); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalPosition", |
pld_info->vertical_position); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalPosition", |
pld_info->horizontal_position); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Shape", pld_info->shape); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupOrientation", |
pld_info->group_orientation); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupToken", |
pld_info->group_token); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupPosition", |
pld_info->group_position); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Bay", pld_info->bay); |
/* Fourth 32-bit dword */ |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Ejectable", pld_info->ejectable); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_EjectRequired", |
pld_info->ospm_eject_required); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CabinetNumber", |
pld_info->cabinet_number); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CardCageNumber", |
pld_info->card_cage_number); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Reference", pld_info->reference); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Rotation", pld_info->rotation); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Order", pld_info->order); |
/* Fifth 32-bit dword */ |
if (buffer_desc->buffer.length > 16) { |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalOffset", |
pld_info->vertical_offset); |
acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalOffset", |
pld_info->horizontal_offset); |
} |
ACPI_FREE(pld_info); |
ACPI_FREE(new_buffer); |
} |
/drivers/acpi/acpica/dbdisply.c |
---|
0,0 → 1,1108 |
/******************************************************************************* |
* |
* Module Name: dbdisply - debug display commands |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#include "acparser.h" |
#include "acinterp.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbdisply") |
/* Local prototypes */ |
static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op); |
static void *acpi_db_get_pointer(void *target); |
static acpi_status |
acpi_db_display_non_root_handlers(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
/* |
* System handler information. |
* Used for Handlers command, in acpi_db_display_handlers. |
*/ |
#define ACPI_PREDEFINED_PREFIX "%25s (%.2X) : " |
#define ACPI_HANDLER_NAME_STRING "%30s : " |
#define ACPI_HANDLER_PRESENT_STRING "%-9s (%p)\n" |
#define ACPI_HANDLER_PRESENT_STRING2 "%-9s (%p)" |
#define ACPI_HANDLER_NOT_PRESENT_STRING "%-9s\n" |
/* All predefined Address Space IDs */ |
static acpi_adr_space_type acpi_gbl_space_id_list[] = { |
ACPI_ADR_SPACE_SYSTEM_MEMORY, |
ACPI_ADR_SPACE_SYSTEM_IO, |
ACPI_ADR_SPACE_PCI_CONFIG, |
ACPI_ADR_SPACE_EC, |
ACPI_ADR_SPACE_SMBUS, |
ACPI_ADR_SPACE_CMOS, |
ACPI_ADR_SPACE_PCI_BAR_TARGET, |
ACPI_ADR_SPACE_IPMI, |
ACPI_ADR_SPACE_GPIO, |
ACPI_ADR_SPACE_GSBUS, |
ACPI_ADR_SPACE_DATA_TABLE, |
ACPI_ADR_SPACE_FIXED_HARDWARE |
}; |
/* Global handler information */ |
typedef struct acpi_handler_info { |
void *handler; |
char *name; |
} acpi_handler_info; |
static struct acpi_handler_info acpi_gbl_handler_list[] = { |
{&acpi_gbl_global_notify[0].handler, "System Notifications"}, |
{&acpi_gbl_global_notify[1].handler, "Device Notifications"}, |
{&acpi_gbl_table_handler, "ACPI Table Events"}, |
{&acpi_gbl_exception_handler, "Control Method Exceptions"}, |
{&acpi_gbl_interface_handler, "OSI Invocations"} |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_pointer |
* |
* PARAMETERS: target - Pointer to string to be converted |
* |
* RETURN: Converted pointer |
* |
* DESCRIPTION: Convert an ascii pointer value to a real value |
* |
******************************************************************************/ |
static void *acpi_db_get_pointer(void *target) |
{ |
void *obj_ptr; |
acpi_size address; |
address = strtoul(target, NULL, 16); |
obj_ptr = ACPI_TO_POINTER(address); |
return (obj_ptr); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_parser_descriptor |
* |
* PARAMETERS: op - A parser Op descriptor |
* |
* RETURN: None |
* |
* DESCRIPTION: Display a formatted parser object |
* |
******************************************************************************/ |
static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op) |
{ |
const struct acpi_opcode_info *info; |
info = acpi_ps_get_opcode_info(op->common.aml_opcode); |
acpi_os_printf("Parser Op Descriptor:\n"); |
acpi_os_printf("%20.20s : %4.4X\n", "Opcode", op->common.aml_opcode); |
ACPI_DEBUG_ONLY_MEMBERS(acpi_os_printf("%20.20s : %s\n", "Opcode Name", |
info->name)); |
acpi_os_printf("%20.20s : %p\n", "Value/ArgList", op->common.value.arg); |
acpi_os_printf("%20.20s : %p\n", "Parent", op->common.parent); |
acpi_os_printf("%20.20s : %p\n", "NextOp", op->common.next); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_decode_and_display_object |
* |
* PARAMETERS: target - String with object to be displayed. Names |
* and hex pointers are supported. |
* output_type - Byte, Word, Dword, or Qword (B|W|D|Q) |
* |
* RETURN: None |
* |
* DESCRIPTION: Display a formatted ACPI object |
* |
******************************************************************************/ |
void acpi_db_decode_and_display_object(char *target, char *output_type) |
{ |
void *obj_ptr; |
struct acpi_namespace_node *node; |
union acpi_operand_object *obj_desc; |
u32 display = DB_BYTE_DISPLAY; |
char buffer[80]; |
struct acpi_buffer ret_buf; |
acpi_status status; |
u32 size; |
if (!target) { |
return; |
} |
/* Decode the output type */ |
if (output_type) { |
acpi_ut_strupr(output_type); |
if (output_type[0] == 'W') { |
display = DB_WORD_DISPLAY; |
} else if (output_type[0] == 'D') { |
display = DB_DWORD_DISPLAY; |
} else if (output_type[0] == 'Q') { |
display = DB_QWORD_DISPLAY; |
} |
} |
ret_buf.length = sizeof(buffer); |
ret_buf.pointer = buffer; |
/* Differentiate between a number and a name */ |
if ((target[0] >= 0x30) && (target[0] <= 0x39)) { |
obj_ptr = acpi_db_get_pointer(target); |
if (!acpi_os_readable(obj_ptr, 16)) { |
acpi_os_printf |
("Address %p is invalid in this address space\n", |
obj_ptr); |
return; |
} |
/* Decode the object type */ |
switch (ACPI_GET_DESCRIPTOR_TYPE(obj_ptr)) { |
case ACPI_DESC_TYPE_NAMED: |
/* This is a namespace Node */ |
if (!acpi_os_readable |
(obj_ptr, sizeof(struct acpi_namespace_node))) { |
acpi_os_printf |
("Cannot read entire Named object at address %p\n", |
obj_ptr); |
return; |
} |
node = obj_ptr; |
goto dump_node; |
case ACPI_DESC_TYPE_OPERAND: |
/* This is a ACPI OPERAND OBJECT */ |
if (!acpi_os_readable |
(obj_ptr, sizeof(union acpi_operand_object))) { |
acpi_os_printf |
("Cannot read entire ACPI object at address %p\n", |
obj_ptr); |
return; |
} |
acpi_ut_debug_dump_buffer(obj_ptr, |
sizeof(union |
acpi_operand_object), |
display, ACPI_UINT32_MAX); |
acpi_ex_dump_object_descriptor(obj_ptr, 1); |
break; |
case ACPI_DESC_TYPE_PARSER: |
/* This is a Parser Op object */ |
if (!acpi_os_readable |
(obj_ptr, sizeof(union acpi_parse_object))) { |
acpi_os_printf |
("Cannot read entire Parser object at address %p\n", |
obj_ptr); |
return; |
} |
acpi_ut_debug_dump_buffer(obj_ptr, |
sizeof(union |
acpi_parse_object), |
display, ACPI_UINT32_MAX); |
acpi_db_dump_parser_descriptor((union acpi_parse_object |
*)obj_ptr); |
break; |
default: |
/* Is not a recognizeable object */ |
acpi_os_printf |
("Not a known ACPI internal object, descriptor type %2.2X\n", |
ACPI_GET_DESCRIPTOR_TYPE(obj_ptr)); |
size = 16; |
if (acpi_os_readable(obj_ptr, 64)) { |
size = 64; |
} |
/* Just dump some memory */ |
acpi_ut_debug_dump_buffer(obj_ptr, size, display, |
ACPI_UINT32_MAX); |
break; |
} |
return; |
} |
/* The parameter is a name string that must be resolved to a Named obj */ |
node = acpi_db_local_ns_lookup(target); |
if (!node) { |
return; |
} |
dump_node: |
/* Now dump the NS node */ |
status = acpi_get_name(node, ACPI_FULL_PATHNAME_NO_TRAILING, &ret_buf); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not convert name to pathname\n"); |
} |
else { |
acpi_os_printf("Object (%p) Pathname: %s\n", |
node, (char *)ret_buf.pointer); |
} |
if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) { |
acpi_os_printf("Invalid Named object at address %p\n", node); |
return; |
} |
acpi_ut_debug_dump_buffer((void *)node, |
sizeof(struct acpi_namespace_node), display, |
ACPI_UINT32_MAX); |
acpi_ex_dump_namespace_node(node, 1); |
obj_desc = acpi_ns_get_attached_object(node); |
if (obj_desc) { |
acpi_os_printf("\nAttached Object (%p):\n", obj_desc); |
if (!acpi_os_readable |
(obj_desc, sizeof(union acpi_operand_object))) { |
acpi_os_printf |
("Invalid internal ACPI Object at address %p\n", |
obj_desc); |
return; |
} |
acpi_ut_debug_dump_buffer((void *)obj_desc, |
sizeof(union acpi_operand_object), |
display, ACPI_UINT32_MAX); |
acpi_ex_dump_object_descriptor(obj_desc, 1); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_method_info |
* |
* PARAMETERS: start_op - Root of the control method parse tree |
* |
* RETURN: None |
* |
* DESCRIPTION: Display information about the current method |
* |
******************************************************************************/ |
void acpi_db_display_method_info(union acpi_parse_object *start_op) |
{ |
struct acpi_walk_state *walk_state; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
union acpi_parse_object *root_op; |
union acpi_parse_object *op; |
const struct acpi_opcode_info *op_info; |
u32 num_ops = 0; |
u32 num_operands = 0; |
u32 num_operators = 0; |
u32 num_remaining_ops = 0; |
u32 num_remaining_operands = 0; |
u32 num_remaining_operators = 0; |
u8 count_remaining = FALSE; |
walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list); |
if (!walk_state) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
obj_desc = walk_state->method_desc; |
node = walk_state->method_node; |
acpi_os_printf("Currently executing control method is [%4.4s]\n", |
acpi_ut_get_node_name(node)); |
acpi_os_printf("%X Arguments, SyncLevel = %X\n", |
(u32)obj_desc->method.param_count, |
(u32)obj_desc->method.sync_level); |
root_op = start_op; |
while (root_op->common.parent) { |
root_op = root_op->common.parent; |
} |
op = root_op; |
while (op) { |
if (op == start_op) { |
count_remaining = TRUE; |
} |
num_ops++; |
if (count_remaining) { |
num_remaining_ops++; |
} |
/* Decode the opcode */ |
op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); |
switch (op_info->class) { |
case AML_CLASS_ARGUMENT: |
if (count_remaining) { |
num_remaining_operands++; |
} |
num_operands++; |
break; |
case AML_CLASS_UNKNOWN: |
/* Bad opcode or ASCII character */ |
continue; |
default: |
if (count_remaining) { |
num_remaining_operators++; |
} |
num_operators++; |
break; |
} |
op = acpi_ps_get_depth_next(start_op, op); |
} |
acpi_os_printf |
("Method contains: %X AML Opcodes - %X Operators, %X Operands\n", |
num_ops, num_operators, num_operands); |
acpi_os_printf |
("Remaining to execute: %X AML Opcodes - %X Operators, %X Operands\n", |
num_remaining_ops, num_remaining_operators, |
num_remaining_operands); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_locals |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display all locals for the currently running control method |
* |
******************************************************************************/ |
void acpi_db_display_locals(void) |
{ |
struct acpi_walk_state *walk_state; |
walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list); |
if (!walk_state) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
acpi_db_decode_locals(walk_state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_arguments |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display all arguments for the currently running control method |
* |
******************************************************************************/ |
void acpi_db_display_arguments(void) |
{ |
struct acpi_walk_state *walk_state; |
walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list); |
if (!walk_state) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
acpi_db_decode_arguments(walk_state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_results |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display current contents of a method result stack |
* |
******************************************************************************/ |
void acpi_db_display_results(void) |
{ |
u32 i; |
struct acpi_walk_state *walk_state; |
union acpi_operand_object *obj_desc; |
u32 result_count = 0; |
struct acpi_namespace_node *node; |
union acpi_generic_state *frame; |
u32 index; /* Index onto current frame */ |
walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list); |
if (!walk_state) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
obj_desc = walk_state->method_desc; |
node = walk_state->method_node; |
if (walk_state->results) { |
result_count = walk_state->result_count; |
} |
acpi_os_printf("Method [%4.4s] has %X stacked result objects\n", |
acpi_ut_get_node_name(node), result_count); |
/* From the top element of result stack */ |
frame = walk_state->results; |
index = (result_count - 1) % ACPI_RESULTS_FRAME_OBJ_NUM; |
for (i = 0; i < result_count; i++) { |
obj_desc = frame->results.obj_desc[index]; |
acpi_os_printf("Result%u: ", i); |
acpi_db_display_internal_object(obj_desc, walk_state); |
if (index == 0) { |
frame = frame->results.next; |
index = ACPI_RESULTS_FRAME_OBJ_NUM; |
} |
index--; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_calling_tree |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display current calling tree of nested control methods |
* |
******************************************************************************/ |
void acpi_db_display_calling_tree(void) |
{ |
struct acpi_walk_state *walk_state; |
struct acpi_namespace_node *node; |
walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list); |
if (!walk_state) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
node = walk_state->method_node; |
acpi_os_printf("Current Control Method Call Tree\n"); |
while (walk_state) { |
node = walk_state->method_node; |
acpi_os_printf(" [%4.4s]\n", acpi_ut_get_node_name(node)); |
walk_state = walk_state->next; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_object_type |
* |
* PARAMETERS: name - User entered NS node handle or name |
* |
* RETURN: None |
* |
* DESCRIPTION: Display type of an arbitrary NS node |
* |
******************************************************************************/ |
void acpi_db_display_object_type(char *name) |
{ |
struct acpi_namespace_node *node; |
struct acpi_device_info *info; |
acpi_status status; |
u32 i; |
node = acpi_db_convert_to_node(name); |
if (!node) { |
return; |
} |
status = acpi_get_object_info(ACPI_CAST_PTR(acpi_handle, node), &info); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not get object info, %s\n", |
acpi_format_exception(status)); |
return; |
} |
if (info->valid & ACPI_VALID_ADR) { |
acpi_os_printf("ADR: %8.8X%8.8X, STA: %8.8X, Flags: %X\n", |
ACPI_FORMAT_UINT64(info->address), |
info->current_status, info->flags); |
} |
if (info->valid & ACPI_VALID_SXDS) { |
acpi_os_printf("S1D-%2.2X S2D-%2.2X S3D-%2.2X S4D-%2.2X\n", |
info->highest_dstates[0], |
info->highest_dstates[1], |
info->highest_dstates[2], |
info->highest_dstates[3]); |
} |
if (info->valid & ACPI_VALID_SXWS) { |
acpi_os_printf |
("S0W-%2.2X S1W-%2.2X S2W-%2.2X S3W-%2.2X S4W-%2.2X\n", |
info->lowest_dstates[0], info->lowest_dstates[1], |
info->lowest_dstates[2], info->lowest_dstates[3], |
info->lowest_dstates[4]); |
} |
if (info->valid & ACPI_VALID_HID) { |
acpi_os_printf("HID: %s\n", info->hardware_id.string); |
} |
if (info->valid & ACPI_VALID_UID) { |
acpi_os_printf("UID: %s\n", info->unique_id.string); |
} |
if (info->valid & ACPI_VALID_SUB) { |
acpi_os_printf("SUB: %s\n", info->subsystem_id.string); |
} |
if (info->valid & ACPI_VALID_CID) { |
for (i = 0; i < info->compatible_id_list.count; i++) { |
acpi_os_printf("CID %u: %s\n", i, |
info->compatible_id_list.ids[i].string); |
} |
} |
ACPI_FREE(info); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_result_object |
* |
* PARAMETERS: obj_desc - Object to be displayed |
* walk_state - Current walk state |
* |
* RETURN: None |
* |
* DESCRIPTION: Display the result of an AML opcode |
* |
* Note: Curently only displays the result object if we are single stepping. |
* However, this output may be useful in other contexts and could be enabled |
* to do so if needed. |
* |
******************************************************************************/ |
void |
acpi_db_display_result_object(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
/* Only display if single stepping */ |
if (!acpi_gbl_cm_single_step) { |
return; |
} |
acpi_os_printf("ResultObj: "); |
acpi_db_display_internal_object(obj_desc, walk_state); |
acpi_os_printf("\n"); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_argument_object |
* |
* PARAMETERS: obj_desc - Object to be displayed |
* walk_state - Current walk state |
* |
* RETURN: None |
* |
* DESCRIPTION: Display the result of an AML opcode |
* |
******************************************************************************/ |
void |
acpi_db_display_argument_object(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
if (!acpi_gbl_cm_single_step) { |
return; |
} |
acpi_os_printf("ArgObj: "); |
acpi_db_display_internal_object(obj_desc, walk_state); |
} |
#if (!ACPI_REDUCED_HARDWARE) |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display the current GPE structures |
* |
******************************************************************************/ |
void acpi_db_display_gpes(void) |
{ |
struct acpi_gpe_block_info *gpe_block; |
struct acpi_gpe_xrupt_info *gpe_xrupt_info; |
struct acpi_gpe_event_info *gpe_event_info; |
struct acpi_gpe_register_info *gpe_register_info; |
char *gpe_type; |
struct acpi_gpe_notify_info *notify; |
u32 gpe_index; |
u32 block = 0; |
u32 i; |
u32 j; |
u32 count; |
char buffer[80]; |
struct acpi_buffer ret_buf; |
acpi_status status; |
ret_buf.length = sizeof(buffer); |
ret_buf.pointer = buffer; |
block = 0; |
/* Walk the GPE lists */ |
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; |
while (gpe_xrupt_info) { |
gpe_block = gpe_xrupt_info->gpe_block_list_head; |
while (gpe_block) { |
status = acpi_get_name(gpe_block->node, |
ACPI_FULL_PATHNAME_NO_TRAILING, |
&ret_buf); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("Could not convert name to pathname\n"); |
} |
if (gpe_block->node == acpi_gbl_fadt_gpe_device) { |
gpe_type = "FADT-defined GPE block"; |
} else { |
gpe_type = "GPE Block Device"; |
} |
acpi_os_printf |
("\nBlock %u - Info %p DeviceNode %p [%s] - %s\n", |
block, gpe_block, gpe_block->node, buffer, |
gpe_type); |
acpi_os_printf(" Registers: %u (%u GPEs)\n", |
gpe_block->register_count, |
gpe_block->gpe_count); |
acpi_os_printf |
(" GPE range: 0x%X to 0x%X on interrupt %u\n", |
gpe_block->block_base_number, |
gpe_block->block_base_number + |
(gpe_block->gpe_count - 1), |
gpe_xrupt_info->interrupt_number); |
acpi_os_printf |
(" RegisterInfo: %p Status %8.8X%8.8X Enable %8.8X%8.8X\n", |
gpe_block->register_info, |
ACPI_FORMAT_UINT64(gpe_block->register_info-> |
status_address.address), |
ACPI_FORMAT_UINT64(gpe_block->register_info-> |
enable_address.address)); |
acpi_os_printf(" EventInfo: %p\n", |
gpe_block->event_info); |
/* Examine each GPE Register within the block */ |
for (i = 0; i < gpe_block->register_count; i++) { |
gpe_register_info = |
&gpe_block->register_info[i]; |
acpi_os_printf(" Reg %u: (GPE %.2X-%.2X) " |
"RunEnable %2.2X WakeEnable %2.2X" |
" Status %8.8X%8.8X Enable %8.8X%8.8X\n", |
i, |
gpe_register_info-> |
base_gpe_number, |
gpe_register_info-> |
base_gpe_number + |
(ACPI_GPE_REGISTER_WIDTH - 1), |
gpe_register_info-> |
enable_for_run, |
gpe_register_info-> |
enable_for_wake, |
ACPI_FORMAT_UINT64 |
(gpe_register_info-> |
status_address.address), |
ACPI_FORMAT_UINT64 |
(gpe_register_info-> |
enable_address.address)); |
/* Now look at the individual GPEs in this byte register */ |
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { |
gpe_index = |
(i * ACPI_GPE_REGISTER_WIDTH) + j; |
gpe_event_info = |
&gpe_block->event_info[gpe_index]; |
if (ACPI_GPE_DISPATCH_TYPE |
(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_NONE) { |
/* This GPE is not used (no method or handler), ignore it */ |
continue; |
} |
acpi_os_printf |
(" GPE %.2X: %p RunRefs %2.2X Flags %2.2X (", |
gpe_block->block_base_number + |
gpe_index, gpe_event_info, |
gpe_event_info->runtime_count, |
gpe_event_info->flags); |
/* Decode the flags byte */ |
if (gpe_event_info-> |
flags & ACPI_GPE_LEVEL_TRIGGERED) { |
acpi_os_printf("Level, "); |
} else { |
acpi_os_printf("Edge, "); |
} |
if (gpe_event_info-> |
flags & ACPI_GPE_CAN_WAKE) { |
acpi_os_printf("CanWake, "); |
} else { |
acpi_os_printf("RunOnly, "); |
} |
switch (ACPI_GPE_DISPATCH_TYPE |
(gpe_event_info->flags)) { |
case ACPI_GPE_DISPATCH_NONE: |
acpi_os_printf("NotUsed"); |
break; |
case ACPI_GPE_DISPATCH_METHOD: |
acpi_os_printf("Method"); |
break; |
case ACPI_GPE_DISPATCH_HANDLER: |
acpi_os_printf("Handler"); |
break; |
case ACPI_GPE_DISPATCH_NOTIFY: |
count = 0; |
notify = |
gpe_event_info->dispatch. |
notify_list; |
while (notify) { |
count++; |
notify = notify->next; |
} |
acpi_os_printf |
("Implicit Notify on %u devices", |
count); |
break; |
case ACPI_GPE_DISPATCH_RAW_HANDLER: |
acpi_os_printf("RawHandler"); |
break; |
default: |
acpi_os_printf("UNKNOWN: %X", |
ACPI_GPE_DISPATCH_TYPE |
(gpe_event_info-> |
flags)); |
break; |
} |
acpi_os_printf(")\n"); |
} |
} |
block++; |
gpe_block = gpe_block->next; |
} |
gpe_xrupt_info = gpe_xrupt_info->next; |
} |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_handlers |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display the currently installed global handlers |
* |
******************************************************************************/ |
void acpi_db_display_handlers(void) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_obj; |
acpi_adr_space_type space_id; |
u32 i; |
/* Operation region handlers */ |
acpi_os_printf("\nOperation Region Handlers at the namespace root:\n"); |
obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node); |
if (obj_desc) { |
for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_space_id_list); i++) { |
space_id = acpi_gbl_space_id_list[i]; |
handler_obj = obj_desc->device.handler; |
acpi_os_printf(ACPI_PREDEFINED_PREFIX, |
acpi_ut_get_region_name((u8)space_id), |
space_id); |
while (handler_obj) { |
if (acpi_gbl_space_id_list[i] == |
handler_obj->address_space.space_id) { |
acpi_os_printf |
(ACPI_HANDLER_PRESENT_STRING, |
(handler_obj->address_space. |
handler_flags & |
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) |
? "Default" : "User", |
handler_obj->address_space. |
handler); |
goto found_handler; |
} |
handler_obj = handler_obj->address_space.next; |
} |
/* There is no handler for this space_id */ |
acpi_os_printf("None\n"); |
found_handler: ; |
} |
/* Find all handlers for user-defined space_IDs */ |
handler_obj = obj_desc->device.handler; |
while (handler_obj) { |
if (handler_obj->address_space.space_id >= |
ACPI_USER_REGION_BEGIN) { |
acpi_os_printf(ACPI_PREDEFINED_PREFIX, |
"User-defined ID", |
handler_obj->address_space. |
space_id); |
acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, |
(handler_obj->address_space. |
handler_flags & |
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) |
? "Default" : "User", |
handler_obj->address_space. |
handler); |
} |
handler_obj = handler_obj->address_space.next; |
} |
} |
#if (!ACPI_REDUCED_HARDWARE) |
/* Fixed event handlers */ |
acpi_os_printf("\nFixed Event Handlers:\n"); |
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
acpi_os_printf(ACPI_PREDEFINED_PREFIX, |
acpi_ut_get_event_name(i), i); |
if (acpi_gbl_fixed_event_handlers[i].handler) { |
acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User", |
acpi_gbl_fixed_event_handlers[i]. |
handler); |
} else { |
acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None"); |
} |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/* Miscellaneous global handlers */ |
acpi_os_printf("\nMiscellaneous Global Handlers:\n"); |
for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_handler_list); i++) { |
acpi_os_printf(ACPI_HANDLER_NAME_STRING, |
acpi_gbl_handler_list[i].name); |
if (acpi_gbl_handler_list[i].handler) { |
acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User", |
acpi_gbl_handler_list[i].handler); |
} else { |
acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None"); |
} |
} |
/* Other handlers that are installed throughout the namespace */ |
acpi_os_printf("\nOperation Region Handlers for specific devices:\n"); |
(void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, |
acpi_db_display_non_root_handlers, NULL, NULL, |
NULL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_non_root_handlers |
* |
* PARAMETERS: acpi_walk_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Display information about all handlers installed for a |
* device object. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_display_non_root_handlers(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
struct acpi_namespace_node *node = |
ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_obj; |
char *pathname; |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
return (AE_OK); |
} |
pathname = acpi_ns_get_external_pathname(node); |
if (!pathname) { |
return (AE_OK); |
} |
/* Display all handlers associated with this device */ |
handler_obj = obj_desc->device.handler; |
while (handler_obj) { |
acpi_os_printf(ACPI_PREDEFINED_PREFIX, |
acpi_ut_get_region_name((u8)handler_obj-> |
address_space.space_id), |
handler_obj->address_space.space_id); |
acpi_os_printf(ACPI_HANDLER_PRESENT_STRING2, |
(handler_obj->address_space.handler_flags & |
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default" |
: "User", handler_obj->address_space.handler); |
acpi_os_printf(" Device Name: %s (%p)\n", pathname, node); |
handler_obj = handler_obj->address_space.next; |
} |
ACPI_FREE(pathname); |
return (AE_OK); |
} |
/drivers/acpi/acpica/dbexec.c |
---|
0,0 → 1,764 |
/******************************************************************************* |
* |
* Module Name: dbexec - debugger control method execution |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbexec") |
static struct acpi_db_method_info acpi_gbl_db_method_info; |
/* Local prototypes */ |
static acpi_status |
acpi_db_execute_method(struct acpi_db_method_info *info, |
struct acpi_buffer *return_obj); |
static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info); |
static u32 acpi_db_get_outstanding_allocations(void); |
static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context); |
static acpi_status |
acpi_db_execution_walk(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value); |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_delete_objects |
* |
* PARAMETERS: count - Count of objects in the list |
* objects - Array of ACPI_OBJECTs to be deleted |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested |
* packages via recursion. |
* |
******************************************************************************/ |
void acpi_db_delete_objects(u32 count, union acpi_object *objects) |
{ |
u32 i; |
for (i = 0; i < count; i++) { |
switch (objects[i].type) { |
case ACPI_TYPE_BUFFER: |
ACPI_FREE(objects[i].buffer.pointer); |
break; |
case ACPI_TYPE_PACKAGE: |
/* Recursive call to delete package elements */ |
acpi_db_delete_objects(objects[i].package.count, |
objects[i].package.elements); |
/* Free the elements array */ |
ACPI_FREE(objects[i].package.elements); |
break; |
default: |
break; |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_execute_method |
* |
* PARAMETERS: info - Valid info segment |
* return_obj - Where to put return object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute a control method. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_execute_method(struct acpi_db_method_info *info, |
struct acpi_buffer *return_obj) |
{ |
acpi_status status; |
struct acpi_object_list param_objects; |
union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1]; |
u32 i; |
ACPI_FUNCTION_TRACE(db_execute_method); |
if (acpi_gbl_db_output_to_file && !acpi_dbg_level) { |
acpi_os_printf("Warning: debug output is not enabled!\n"); |
} |
param_objects.count = 0; |
param_objects.pointer = NULL; |
/* Pass through any command-line arguments */ |
if (info->args && info->args[0]) { |
/* Get arguments passed on the command line */ |
for (i = 0; (info->args[i] && *(info->args[i])); i++) { |
/* Convert input string (token) to an actual union acpi_object */ |
status = acpi_db_convert_to_object(info->types[i], |
info->args[i], |
¶ms[i]); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"While parsing method arguments")); |
goto cleanup; |
} |
} |
param_objects.count = i; |
param_objects.pointer = params; |
} |
/* Prepare for a return object of arbitrary size */ |
return_obj->pointer = acpi_gbl_db_buffer; |
return_obj->length = ACPI_DEBUG_BUFFER_SIZE; |
/* Do the actual method execution */ |
acpi_gbl_method_executing = TRUE; |
status = acpi_evaluate_object(NULL, info->pathname, |
¶m_objects, return_obj); |
acpi_gbl_cm_single_step = FALSE; |
acpi_gbl_method_executing = FALSE; |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"while executing %s from debugger", |
info->pathname)); |
if (status == AE_BUFFER_OVERFLOW) { |
ACPI_ERROR((AE_INFO, |
"Possible overflow of internal debugger " |
"buffer (size 0x%X needed 0x%X)", |
ACPI_DEBUG_BUFFER_SIZE, |
(u32)return_obj->length)); |
} |
} |
cleanup: |
acpi_db_delete_objects(param_objects.count, params); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_execute_setup |
* |
* PARAMETERS: info - Valid method info |
* |
* RETURN: None |
* |
* DESCRIPTION: Setup info segment prior to method execution |
* |
******************************************************************************/ |
static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info) |
{ |
acpi_status status; |
ACPI_FUNCTION_NAME(db_execute_setup); |
/* Catenate the current scope to the supplied name */ |
info->pathname[0] = 0; |
if ((info->name[0] != '\\') && (info->name[0] != '/')) { |
if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname), |
acpi_gbl_db_scope_buf)) { |
status = AE_BUFFER_OVERFLOW; |
goto error_exit; |
} |
} |
if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname), |
info->name)) { |
status = AE_BUFFER_OVERFLOW; |
goto error_exit; |
} |
acpi_db_prep_namestring(info->pathname); |
acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
acpi_os_printf("Evaluating %s\n", info->pathname); |
if (info->flags & EX_SINGLE_STEP) { |
acpi_gbl_cm_single_step = TRUE; |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
} |
else { |
/* No single step, allow redirection to a file */ |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
} |
return (AE_OK); |
error_exit: |
ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution")); |
return (status); |
} |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
u32 acpi_db_get_cache_info(struct acpi_memory_list *cache) |
{ |
return (cache->total_allocated - cache->total_freed - |
cache->current_depth); |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_outstanding_allocations |
* |
* PARAMETERS: None |
* |
* RETURN: Current global allocation count minus cache entries |
* |
* DESCRIPTION: Determine the current number of "outstanding" allocations -- |
* those allocations that have not been freed and also are not |
* in one of the various object caches. |
* |
******************************************************************************/ |
static u32 acpi_db_get_outstanding_allocations(void) |
{ |
u32 outstanding = 0; |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache); |
outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache); |
outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache); |
outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache); |
#endif |
return (outstanding); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_execution_walk |
* |
* PARAMETERS: WALK_CALLBACK |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute a control method. Name is relative to the current |
* scope. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_execution_walk(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value) |
{ |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
struct acpi_buffer return_obj; |
acpi_status status; |
obj_desc = acpi_ns_get_attached_object(node); |
if (obj_desc->method.param_count) { |
return (AE_OK); |
} |
return_obj.pointer = NULL; |
return_obj.length = ACPI_ALLOCATE_BUFFER; |
acpi_ns_print_node_pathname(node, "Evaluating"); |
/* Do the actual method execution */ |
acpi_os_printf("\n"); |
acpi_gbl_method_executing = TRUE; |
status = acpi_evaluate_object(node, NULL, NULL, &return_obj); |
acpi_os_printf("Evaluation of [%4.4s] returned %s\n", |
acpi_ut_get_node_name(node), |
acpi_format_exception(status)); |
acpi_gbl_method_executing = FALSE; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_execute |
* |
* PARAMETERS: name - Name of method to execute |
* args - Parameters to the method |
* Types - |
* flags - single step/no single step |
* |
* RETURN: None |
* |
* DESCRIPTION: Execute a control method. Name is relative to the current |
* scope. |
* |
******************************************************************************/ |
void |
acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags) |
{ |
acpi_status status; |
struct acpi_buffer return_obj; |
char *name_string; |
#ifdef ACPI_DEBUG_OUTPUT |
u32 previous_allocations; |
u32 allocations; |
#endif |
/* |
* Allow one execution to be performed by debugger or single step |
* execution will be dead locked by the interpreter mutexes. |
*/ |
if (acpi_gbl_method_executing) { |
acpi_os_printf("Only one debugger execution is allowed.\n"); |
return; |
} |
#ifdef ACPI_DEBUG_OUTPUT |
/* Memory allocation tracking */ |
previous_allocations = acpi_db_get_outstanding_allocations(); |
#endif |
if (*name == '*') { |
(void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, |
acpi_db_execution_walk, NULL, NULL, |
NULL); |
return; |
} else { |
name_string = ACPI_ALLOCATE(strlen(name) + 1); |
if (!name_string) { |
return; |
} |
memset(&acpi_gbl_db_method_info, 0, |
sizeof(struct acpi_db_method_info)); |
strcpy(name_string, name); |
acpi_ut_strupr(name_string); |
acpi_gbl_db_method_info.name = name_string; |
acpi_gbl_db_method_info.args = args; |
acpi_gbl_db_method_info.types = types; |
acpi_gbl_db_method_info.flags = flags; |
return_obj.pointer = NULL; |
return_obj.length = ACPI_ALLOCATE_BUFFER; |
status = acpi_db_execute_setup(&acpi_gbl_db_method_info); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(name_string); |
return; |
} |
/* Get the NS node, determines existence also */ |
status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, |
&acpi_gbl_db_method_info.method); |
if (ACPI_SUCCESS(status)) { |
status = |
acpi_db_execute_method(&acpi_gbl_db_method_info, |
&return_obj); |
} |
ACPI_FREE(name_string); |
} |
/* |
* Allow any handlers in separate threads to complete. |
* (Such as Notify handlers invoked from AML executed above). |
*/ |
acpi_os_sleep((u64)10); |
#ifdef ACPI_DEBUG_OUTPUT |
/* Memory allocation tracking */ |
allocations = |
acpi_db_get_outstanding_allocations() - previous_allocations; |
acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
if (allocations > 0) { |
acpi_os_printf |
("0x%X Outstanding allocations after evaluation of %s\n", |
allocations, acpi_gbl_db_method_info.pathname); |
} |
#endif |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Evaluation of %s failed with status %s\n", |
acpi_gbl_db_method_info.pathname, |
acpi_format_exception(status)); |
} else { |
/* Display a return object, if any */ |
if (return_obj.length) { |
acpi_os_printf("Evaluation of %s returned object %p, " |
"external buffer length %X\n", |
acpi_gbl_db_method_info.pathname, |
return_obj.pointer, |
(u32)return_obj.length); |
acpi_db_dump_external_object(return_obj.pointer, 1); |
/* Dump a _PLD buffer if present */ |
if (ACPI_COMPARE_NAME |
((ACPI_CAST_PTR |
(struct acpi_namespace_node, |
acpi_gbl_db_method_info.method)->name.ascii), |
METHOD_NAME__PLD)) { |
acpi_db_dump_pld_buffer(return_obj.pointer); |
} |
} else { |
acpi_os_printf |
("No object was returned from evaluation of %s\n", |
acpi_gbl_db_method_info.pathname); |
} |
} |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_method_thread |
* |
* PARAMETERS: context - Execution info segment |
* |
* RETURN: None |
* |
* DESCRIPTION: Debugger execute thread. Waits for a command line, then |
* simply dispatches it. |
* |
******************************************************************************/ |
static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context) |
{ |
acpi_status status; |
struct acpi_db_method_info *info = context; |
struct acpi_db_method_info local_info; |
u32 i; |
u8 allow; |
struct acpi_buffer return_obj; |
/* |
* acpi_gbl_db_method_info.Arguments will be passed as method arguments. |
* Prevent acpi_gbl_db_method_info from being modified by multiple threads |
* concurrently. |
* |
* Note: The arguments we are passing are used by the ASL test suite |
* (aslts). Do not change them without updating the tests. |
*/ |
(void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER); |
if (info->init_args) { |
acpi_db_uint32_to_hex_string(info->num_created, |
info->index_of_thread_str); |
acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(), |
info->id_of_thread_str); |
} |
if (info->threads && (info->num_created < info->num_threads)) { |
info->threads[info->num_created++] = acpi_os_get_thread_id(); |
} |
local_info = *info; |
local_info.args = local_info.arguments; |
local_info.arguments[0] = local_info.num_threads_str; |
local_info.arguments[1] = local_info.id_of_thread_str; |
local_info.arguments[2] = local_info.index_of_thread_str; |
local_info.arguments[3] = NULL; |
local_info.types = local_info.arg_types; |
(void)acpi_os_signal_semaphore(info->info_gate, 1); |
for (i = 0; i < info->num_loops; i++) { |
status = acpi_db_execute_method(&local_info, &return_obj); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("%s During evaluation of %s at iteration %X\n", |
acpi_format_exception(status), info->pathname, i); |
if (status == AE_ABORT_METHOD) { |
break; |
} |
} |
#if 0 |
if ((i % 100) == 0) { |
acpi_os_printf("%u loops, Thread 0x%x\n", |
i, acpi_os_get_thread_id()); |
} |
if (return_obj.length) { |
acpi_os_printf |
("Evaluation of %s returned object %p Buflen %X\n", |
info->pathname, return_obj.pointer, |
(u32)return_obj.length); |
acpi_db_dump_external_object(return_obj.pointer, 1); |
} |
#endif |
} |
/* Signal our completion */ |
allow = 0; |
(void)acpi_os_wait_semaphore(info->thread_complete_gate, |
1, ACPI_WAIT_FOREVER); |
info->num_completed++; |
if (info->num_completed == info->num_threads) { |
/* Do signal for main thread once only */ |
allow = 1; |
} |
(void)acpi_os_signal_semaphore(info->thread_complete_gate, 1); |
if (allow) { |
status = acpi_os_signal_semaphore(info->main_thread_gate, 1); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("Could not signal debugger thread sync semaphore, %s\n", |
acpi_format_exception(status)); |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_create_execution_threads |
* |
* PARAMETERS: num_threads_arg - Number of threads to create |
* num_loops_arg - Loop count for the thread(s) |
* method_name_arg - Control method to execute |
* |
* RETURN: None |
* |
* DESCRIPTION: Create threads to execute method(s) |
* |
******************************************************************************/ |
void |
acpi_db_create_execution_threads(char *num_threads_arg, |
char *num_loops_arg, char *method_name_arg) |
{ |
acpi_status status; |
u32 num_threads; |
u32 num_loops; |
u32 i; |
u32 size; |
acpi_mutex main_thread_gate; |
acpi_mutex thread_complete_gate; |
acpi_mutex info_gate; |
/* Get the arguments */ |
num_threads = strtoul(num_threads_arg, NULL, 0); |
num_loops = strtoul(num_loops_arg, NULL, 0); |
if (!num_threads || !num_loops) { |
acpi_os_printf("Bad argument: Threads %X, Loops %X\n", |
num_threads, num_loops); |
return; |
} |
/* |
* Create the semaphore for synchronization of |
* the created threads with the main thread. |
*/ |
status = acpi_os_create_semaphore(1, 0, &main_thread_gate); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not create semaphore for " |
"synchronization with the main thread, %s\n", |
acpi_format_exception(status)); |
return; |
} |
/* |
* Create the semaphore for synchronization |
* between the created threads. |
*/ |
status = acpi_os_create_semaphore(1, 1, &thread_complete_gate); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not create semaphore for " |
"synchronization between the created threads, %s\n", |
acpi_format_exception(status)); |
(void)acpi_os_delete_semaphore(main_thread_gate); |
return; |
} |
status = acpi_os_create_semaphore(1, 1, &info_gate); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not create semaphore for " |
"synchronization of AcpiGbl_DbMethodInfo, %s\n", |
acpi_format_exception(status)); |
(void)acpi_os_delete_semaphore(thread_complete_gate); |
(void)acpi_os_delete_semaphore(main_thread_gate); |
return; |
} |
memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info)); |
/* Array to store IDs of threads */ |
acpi_gbl_db_method_info.num_threads = num_threads; |
size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads; |
acpi_gbl_db_method_info.threads = acpi_os_allocate(size); |
if (acpi_gbl_db_method_info.threads == NULL) { |
acpi_os_printf("No memory for thread IDs array\n"); |
(void)acpi_os_delete_semaphore(main_thread_gate); |
(void)acpi_os_delete_semaphore(thread_complete_gate); |
(void)acpi_os_delete_semaphore(info_gate); |
return; |
} |
memset(acpi_gbl_db_method_info.threads, 0, size); |
/* Setup the context to be passed to each thread */ |
acpi_gbl_db_method_info.name = method_name_arg; |
acpi_gbl_db_method_info.flags = 0; |
acpi_gbl_db_method_info.num_loops = num_loops; |
acpi_gbl_db_method_info.main_thread_gate = main_thread_gate; |
acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate; |
acpi_gbl_db_method_info.info_gate = info_gate; |
/* Init arguments to be passed to method */ |
acpi_gbl_db_method_info.init_args = 1; |
acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments; |
acpi_gbl_db_method_info.arguments[0] = |
acpi_gbl_db_method_info.num_threads_str; |
acpi_gbl_db_method_info.arguments[1] = |
acpi_gbl_db_method_info.id_of_thread_str; |
acpi_gbl_db_method_info.arguments[2] = |
acpi_gbl_db_method_info.index_of_thread_str; |
acpi_gbl_db_method_info.arguments[3] = NULL; |
acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types; |
acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER; |
acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER; |
acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER; |
acpi_db_uint32_to_hex_string(num_threads, |
acpi_gbl_db_method_info.num_threads_str); |
status = acpi_db_execute_setup(&acpi_gbl_db_method_info); |
if (ACPI_FAILURE(status)) { |
goto cleanup_and_exit; |
} |
/* Get the NS node, determines existence also */ |
status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, |
&acpi_gbl_db_method_info.method); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("%s Could not get handle for %s\n", |
acpi_format_exception(status), |
acpi_gbl_db_method_info.pathname); |
goto cleanup_and_exit; |
} |
/* Create the threads */ |
acpi_os_printf("Creating %X threads to execute %X times each\n", |
num_threads, num_loops); |
for (i = 0; i < (num_threads); i++) { |
status = |
acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD, |
acpi_db_method_thread, |
&acpi_gbl_db_method_info); |
if (ACPI_FAILURE(status)) { |
break; |
} |
} |
/* Wait for all threads to complete */ |
(void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER); |
acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
acpi_os_printf("All threads (%X) have completed\n", num_threads); |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
cleanup_and_exit: |
/* Cleanup and exit */ |
(void)acpi_os_delete_semaphore(main_thread_gate); |
(void)acpi_os_delete_semaphore(thread_complete_gate); |
(void)acpi_os_delete_semaphore(info_gate); |
acpi_os_free(acpi_gbl_db_method_info.threads); |
acpi_gbl_db_method_info.threads = NULL; |
} |
/drivers/acpi/acpica/dbfileio.c |
---|
0,0 → 1,256 |
/******************************************************************************* |
* |
* Module Name: dbfileio - Debugger file I/O commands. These can't usually |
* be used when running the debugger in Ring 0 (Kernel mode) |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#include "actables.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbfileio") |
#ifdef ACPI_DEBUGGER |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_close_debug_file |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: If open, close the current debug output file |
* |
******************************************************************************/ |
void acpi_db_close_debug_file(void) |
{ |
#ifdef ACPI_APPLICATION |
if (acpi_gbl_debug_file) { |
fclose(acpi_gbl_debug_file); |
acpi_gbl_debug_file = NULL; |
acpi_gbl_db_output_to_file = FALSE; |
acpi_os_printf("Debug output file %s closed\n", |
acpi_gbl_db_debug_filename); |
} |
#endif |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_open_debug_file |
* |
* PARAMETERS: name - Filename to open |
* |
* RETURN: None |
* |
* DESCRIPTION: Open a file where debug output will be directed. |
* |
******************************************************************************/ |
void acpi_db_open_debug_file(char *name) |
{ |
#ifdef ACPI_APPLICATION |
acpi_db_close_debug_file(); |
acpi_gbl_debug_file = fopen(name, "w+"); |
if (!acpi_gbl_debug_file) { |
acpi_os_printf("Could not open debug file %s\n", name); |
return; |
} |
acpi_os_printf("Debug output file %s opened\n", name); |
strncpy(acpi_gbl_db_debug_filename, name, |
sizeof(acpi_gbl_db_debug_filename)); |
acpi_gbl_db_output_to_file = TRUE; |
#endif |
} |
#endif |
#ifdef ACPI_APPLICATION |
#include "acapps.h" |
/******************************************************************************* |
* |
* FUNCTION: ae_local_load_table |
* |
* PARAMETERS: table - pointer to a buffer containing the entire |
* table to be loaded |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to load a table from the caller's |
* buffer. The buffer must contain an entire ACPI Table including |
* a valid header. The header fields will be verified, and if it |
* is determined that the table is invalid, the call will fail. |
* |
******************************************************************************/ |
static acpi_status ae_local_load_table(struct acpi_table_header *table) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ae_local_load_table); |
#if 0 |
/* struct acpi_table_desc table_info; */ |
if (!table) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
table_info.pointer = table; |
status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Install the new table into the local data structures */ |
status = acpi_tb_init_table_descriptor(&table_info); |
if (ACPI_FAILURE(status)) { |
if (status == AE_ALREADY_EXISTS) { |
/* Table already exists, no error */ |
status = AE_OK; |
} |
/* Free table allocated by acpi_tb_get_table */ |
acpi_tb_delete_single_table(&table_info); |
return_ACPI_STATUS(status); |
} |
#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) |
status = |
acpi_ns_load_table(table_info.installed_desc, acpi_gbl_root_node); |
if (ACPI_FAILURE(status)) { |
/* Uninstall table and free the buffer */ |
acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_DSDT); |
return_ACPI_STATUS(status); |
} |
#endif |
#endif |
return_ACPI_STATUS(status); |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_table_from_file |
* |
* PARAMETERS: filename - File where table is located |
* return_table - Where a pointer to the table is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load an ACPI table from a file |
* |
******************************************************************************/ |
acpi_status |
acpi_db_get_table_from_file(char *filename, |
struct acpi_table_header **return_table, |
u8 must_be_aml_file) |
{ |
#ifdef ACPI_APPLICATION |
acpi_status status; |
struct acpi_table_header *table; |
u8 is_aml_table = TRUE; |
status = acpi_ut_read_table_from_file(filename, &table); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (must_be_aml_file) { |
is_aml_table = acpi_ut_is_aml_table(table); |
if (!is_aml_table) { |
ACPI_EXCEPTION((AE_INFO, AE_OK, |
"Input for -e is not an AML table: " |
"\"%4.4s\" (must be DSDT/SSDT)", |
table->signature)); |
return (AE_TYPE); |
} |
} |
if (is_aml_table) { |
/* Attempt to recognize and install the table */ |
status = ae_local_load_table(table); |
if (ACPI_FAILURE(status)) { |
if (status == AE_ALREADY_EXISTS) { |
acpi_os_printf |
("Table %4.4s is already installed\n", |
table->signature); |
} else { |
acpi_os_printf("Could not install table, %s\n", |
acpi_format_exception(status)); |
} |
return (status); |
} |
acpi_tb_print_table_header(0, table); |
fprintf(stderr, |
"Acpi table [%4.4s] successfully installed and loaded\n", |
table->signature); |
} |
acpi_gbl_acpi_hardware_present = FALSE; |
if (return_table) { |
*return_table = table; |
} |
#endif /* ACPI_APPLICATION */ |
return (AE_OK); |
} |
/drivers/acpi/acpica/dbhistry.c |
---|
0,0 → 1,239 |
/****************************************************************************** |
* |
* Module Name: dbhistry - debugger HISTORY command |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbhistry") |
#define HI_NO_HISTORY 0 |
#define HI_RECORD_HISTORY 1 |
#define HISTORY_SIZE 40 |
typedef struct history_info { |
char *command; |
u32 cmd_num; |
} HISTORY_INFO; |
static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE]; |
static u16 acpi_gbl_lo_history = 0; |
static u16 acpi_gbl_num_history = 0; |
static u16 acpi_gbl_next_history_index = 0; |
u32 acpi_gbl_next_cmd_num = 1; |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_add_to_history |
* |
* PARAMETERS: command_line - Command to add |
* |
* RETURN: None |
* |
* DESCRIPTION: Add a command line to the history buffer. |
* |
******************************************************************************/ |
void acpi_db_add_to_history(char *command_line) |
{ |
u16 cmd_len; |
u16 buffer_len; |
/* Put command into the next available slot */ |
cmd_len = (u16)strlen(command_line); |
if (!cmd_len) { |
return; |
} |
if (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command != |
NULL) { |
buffer_len = |
(u16) |
strlen(acpi_gbl_history_buffer[acpi_gbl_next_history_index]. |
command); |
if (cmd_len > buffer_len) { |
acpi_os_free(acpi_gbl_history_buffer |
[acpi_gbl_next_history_index].command); |
acpi_gbl_history_buffer[acpi_gbl_next_history_index]. |
command = acpi_os_allocate(cmd_len + 1); |
} |
} else { |
acpi_gbl_history_buffer[acpi_gbl_next_history_index].command = |
acpi_os_allocate(cmd_len + 1); |
} |
strcpy(acpi_gbl_history_buffer[acpi_gbl_next_history_index].command, |
command_line); |
acpi_gbl_history_buffer[acpi_gbl_next_history_index].cmd_num = |
acpi_gbl_next_cmd_num; |
/* Adjust indexes */ |
if ((acpi_gbl_num_history == HISTORY_SIZE) && |
(acpi_gbl_next_history_index == acpi_gbl_lo_history)) { |
acpi_gbl_lo_history++; |
if (acpi_gbl_lo_history >= HISTORY_SIZE) { |
acpi_gbl_lo_history = 0; |
} |
} |
acpi_gbl_next_history_index++; |
if (acpi_gbl_next_history_index >= HISTORY_SIZE) { |
acpi_gbl_next_history_index = 0; |
} |
acpi_gbl_next_cmd_num++; |
if (acpi_gbl_num_history < HISTORY_SIZE) { |
acpi_gbl_num_history++; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_history |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display the contents of the history buffer |
* |
******************************************************************************/ |
void acpi_db_display_history(void) |
{ |
u32 i; |
u16 history_index; |
history_index = acpi_gbl_lo_history; |
/* Dump entire history buffer */ |
for (i = 0; i < acpi_gbl_num_history; i++) { |
if (acpi_gbl_history_buffer[history_index].command) { |
acpi_os_printf("%3ld %s\n", |
acpi_gbl_history_buffer[history_index]. |
cmd_num, |
acpi_gbl_history_buffer[history_index]. |
command); |
} |
history_index++; |
if (history_index >= HISTORY_SIZE) { |
history_index = 0; |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_from_history |
* |
* PARAMETERS: command_num_arg - String containing the number of the |
* command to be retrieved |
* |
* RETURN: Pointer to the retrieved command. Null on error. |
* |
* DESCRIPTION: Get a command from the history buffer |
* |
******************************************************************************/ |
char *acpi_db_get_from_history(char *command_num_arg) |
{ |
u32 cmd_num; |
if (command_num_arg == NULL) { |
cmd_num = acpi_gbl_next_cmd_num - 1; |
} |
else { |
cmd_num = strtoul(command_num_arg, NULL, 0); |
} |
return (acpi_db_get_history_by_index(cmd_num)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_history_by_index |
* |
* PARAMETERS: cmd_num - Index of the desired history entry. |
* Values are 0...(acpi_gbl_next_cmd_num - 1) |
* |
* RETURN: Pointer to the retrieved command. Null on error. |
* |
* DESCRIPTION: Get a command from the history buffer |
* |
******************************************************************************/ |
char *acpi_db_get_history_by_index(u32 cmd_num) |
{ |
u32 i; |
u16 history_index; |
/* Search history buffer */ |
history_index = acpi_gbl_lo_history; |
for (i = 0; i < acpi_gbl_num_history; i++) { |
if (acpi_gbl_history_buffer[history_index].cmd_num == cmd_num) { |
/* Found the command, return it */ |
return (acpi_gbl_history_buffer[history_index].command); |
} |
/* History buffer is circular */ |
history_index++; |
if (history_index >= HISTORY_SIZE) { |
history_index = 0; |
} |
} |
acpi_os_printf("Invalid history number: %u\n", history_index); |
return (NULL); |
} |
/drivers/acpi/acpica/dbinput.c |
---|
0,0 → 1,1267 |
/******************************************************************************* |
* |
* Module Name: dbinput - user front-end to the AML debugger |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbinput") |
/* Local prototypes */ |
static u32 acpi_db_get_line(char *input_buffer); |
static u32 acpi_db_match_command(char *user_command); |
static void acpi_db_single_thread(void); |
static void acpi_db_display_command_info(char *command, u8 display_all); |
static void acpi_db_display_help(char *command); |
static u8 |
acpi_db_match_command_help(char *command, |
const struct acpi_db_command_help *help); |
/* |
* Top-level debugger commands. |
* |
* This list of commands must match the string table below it |
*/ |
enum acpi_ex_debugger_commands { |
CMD_NOT_FOUND = 0, |
CMD_NULL, |
CMD_ALLOCATIONS, |
CMD_ARGS, |
CMD_ARGUMENTS, |
CMD_BREAKPOINT, |
CMD_BUSINFO, |
CMD_CALL, |
CMD_DEBUG, |
CMD_DISASSEMBLE, |
CMD_DISASM, |
CMD_DUMP, |
CMD_EVALUATE, |
CMD_EXECUTE, |
CMD_EXIT, |
CMD_FIND, |
CMD_GO, |
CMD_HANDLERS, |
CMD_HELP, |
CMD_HELP2, |
CMD_HISTORY, |
CMD_HISTORY_EXE, |
CMD_HISTORY_LAST, |
CMD_INFORMATION, |
CMD_INTEGRITY, |
CMD_INTO, |
CMD_LEVEL, |
CMD_LIST, |
CMD_LOCALS, |
CMD_LOCKS, |
CMD_METHODS, |
CMD_NAMESPACE, |
CMD_NOTIFY, |
CMD_OBJECTS, |
CMD_OSI, |
CMD_OWNER, |
CMD_PATHS, |
CMD_PREDEFINED, |
CMD_PREFIX, |
CMD_QUIT, |
CMD_REFERENCES, |
CMD_RESOURCES, |
CMD_RESULTS, |
CMD_SET, |
CMD_STATS, |
CMD_STOP, |
CMD_TABLES, |
CMD_TEMPLATE, |
CMD_TRACE, |
CMD_TREE, |
CMD_TYPE, |
#ifdef ACPI_APPLICATION |
CMD_ENABLEACPI, |
CMD_EVENT, |
CMD_GPE, |
CMD_GPES, |
CMD_SCI, |
CMD_SLEEP, |
CMD_CLOSE, |
CMD_LOAD, |
CMD_OPEN, |
CMD_UNLOAD, |
CMD_TERMINATE, |
CMD_THREADS, |
CMD_TEST, |
#endif |
}; |
#define CMD_FIRST_VALID 2 |
/* Second parameter is the required argument count */ |
static const struct acpi_db_command_info acpi_gbl_db_commands[] = { |
{"<NOT FOUND>", 0}, |
{"<NULL>", 0}, |
{"ALLOCATIONS", 0}, |
{"ARGS", 0}, |
{"ARGUMENTS", 0}, |
{"BREAKPOINT", 1}, |
{"BUSINFO", 0}, |
{"CALL", 0}, |
{"DEBUG", 1}, |
{"DISASSEMBLE", 1}, |
{"DISASM", 1}, |
{"DUMP", 1}, |
{"EVALUATE", 1}, |
{"EXECUTE", 1}, |
{"EXIT", 0}, |
{"FIND", 1}, |
{"GO", 0}, |
{"HANDLERS", 0}, |
{"HELP", 0}, |
{"?", 0}, |
{"HISTORY", 0}, |
{"!", 1}, |
{"!!", 0}, |
{"INFORMATION", 0}, |
{"INTEGRITY", 0}, |
{"INTO", 0}, |
{"LEVEL", 0}, |
{"LIST", 0}, |
{"LOCALS", 0}, |
{"LOCKS", 0}, |
{"METHODS", 0}, |
{"NAMESPACE", 0}, |
{"NOTIFY", 2}, |
{"OBJECTS", 0}, |
{"OSI", 0}, |
{"OWNER", 1}, |
{"PATHS", 0}, |
{"PREDEFINED", 0}, |
{"PREFIX", 0}, |
{"QUIT", 0}, |
{"REFERENCES", 1}, |
{"RESOURCES", 0}, |
{"RESULTS", 0}, |
{"SET", 3}, |
{"STATS", 1}, |
{"STOP", 0}, |
{"TABLES", 0}, |
{"TEMPLATE", 1}, |
{"TRACE", 1}, |
{"TREE", 0}, |
{"TYPE", 1}, |
#ifdef ACPI_APPLICATION |
{"ENABLEACPI", 0}, |
{"EVENT", 1}, |
{"GPE", 1}, |
{"GPES", 0}, |
{"SCI", 0}, |
{"SLEEP", 0}, |
{"CLOSE", 0}, |
{"LOAD", 1}, |
{"OPEN", 1}, |
{"UNLOAD", 1}, |
{"TERMINATE", 0}, |
{"THREADS", 3}, |
{"TEST", 1}, |
#endif |
{NULL, 0} |
}; |
/* |
* Help for all debugger commands. First argument is the number of lines |
* of help to output for the command. |
*/ |
static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { |
{0, "\nGeneral-Purpose Commands:", "\n"}, |
{1, " Allocations", "Display list of current memory allocations\n"}, |
{2, " Dump <Address>|<Namepath>", "\n"}, |
{0, " [Byte|Word|Dword|Qword]", |
"Display ACPI objects or memory\n"}, |
{1, " Handlers", "Info about global handlers\n"}, |
{1, " Help [Command]", "This help screen or individual command\n"}, |
{1, " History", "Display command history buffer\n"}, |
{1, " Level <DebugLevel>] [console]", |
"Get/Set debug level for file or console\n"}, |
{1, " Locks", "Current status of internal mutexes\n"}, |
{1, " Osi [Install|Remove <name>]", |
"Display or modify global _OSI list\n"}, |
{1, " Quit or Exit", "Exit this command\n"}, |
{8, " Stats <SubCommand>", |
"Display namespace and memory statistics\n"}, |
{1, " Allocations", "Display list of current memory allocations\n"}, |
{1, " Memory", "Dump internal memory lists\n"}, |
{1, " Misc", "Namespace search and mutex stats\n"}, |
{1, " Objects", "Summary of namespace objects\n"}, |
{1, " Sizes", "Sizes for each of the internal objects\n"}, |
{1, " Stack", "Display CPU stack usage\n"}, |
{1, " Tables", "Info about current ACPI table(s)\n"}, |
{1, " Tables", "Display info about loaded ACPI tables\n"}, |
{1, " ! <CommandNumber>", "Execute command from history buffer\n"}, |
{1, " !!", "Execute last command again\n"}, |
{0, "\nNamespace Access Commands:", "\n"}, |
{1, " Businfo", "Display system bus info\n"}, |
{1, " Disassemble <Method>", "Disassemble a control method\n"}, |
{1, " Find <AcpiName> (? is wildcard)", |
"Find ACPI name(s) with wildcards\n"}, |
{1, " Integrity", "Validate namespace integrity\n"}, |
{1, " Methods", "Display list of loaded control methods\n"}, |
{1, " Namespace [Object] [Depth]", |
"Display loaded namespace tree/subtree\n"}, |
{1, " Notify <Object> <Value>", "Send a notification on Object\n"}, |
{1, " Objects [ObjectType]", |
"Display summary of all objects or just given type\n"}, |
{1, " Owner <OwnerId> [Depth]", |
"Display loaded namespace by object owner\n"}, |
{1, " Paths", "Display full pathnames of namespace objects\n"}, |
{1, " Predefined", "Check all predefined names\n"}, |
{1, " Prefix [<Namepath>]", "Set or Get current execution prefix\n"}, |
{1, " References <Addr>", "Find all references to object at addr\n"}, |
{1, " Resources [DeviceName]", |
"Display Device resources (no arg = all devices)\n"}, |
{1, " Set N <NamedObject> <Value>", "Set value for named integer\n"}, |
{1, " Template <Object>", "Format/dump a Buffer/ResourceTemplate\n"}, |
{1, " Type <Object>", "Display object type\n"}, |
{0, "\nControl Method Execution Commands:", "\n"}, |
{1, " Arguments (or Args)", "Display method arguments\n"}, |
{1, " Breakpoint <AmlOffset>", "Set an AML execution breakpoint\n"}, |
{1, " Call", "Run to next control method invocation\n"}, |
{1, " Debug <Namepath> [Arguments]", "Single Step a control method\n"}, |
{6, " Evaluate", "Synonym for Execute\n"}, |
{5, " Execute <Namepath> [Arguments]", "Execute control method\n"}, |
{1, " Hex Integer", "Integer method argument\n"}, |
{1, " \"Ascii String\"", "String method argument\n"}, |
{1, " (Hex Byte List)", "Buffer method argument\n"}, |
{1, " [Package Element List]", "Package method argument\n"}, |
{1, " Go", "Allow method to run to completion\n"}, |
{1, " Information", "Display info about the current method\n"}, |
{1, " Into", "Step into (not over) a method call\n"}, |
{1, " List [# of Aml Opcodes]", "Display method ASL statements\n"}, |
{1, " Locals", "Display method local variables\n"}, |
{1, " Results", "Display method result stack\n"}, |
{1, " Set <A|L> <#> <Value>", "Set method data (Arguments/Locals)\n"}, |
{1, " Stop", "Terminate control method\n"}, |
{5, " Trace <State> [<Namepath>] [Once]", |
"Trace control method execution\n"}, |
{1, " Enable", "Enable all messages\n"}, |
{1, " Disable", "Disable tracing\n"}, |
{1, " Method", "Enable method execution messages\n"}, |
{1, " Opcode", "Enable opcode execution messages\n"}, |
{1, " Tree", "Display control method calling tree\n"}, |
{1, " <Enter>", "Single step next AML opcode (over calls)\n"}, |
#ifdef ACPI_APPLICATION |
{0, "\nHardware Simulation Commands:", "\n"}, |
{1, " EnableAcpi", "Enable ACPI (hardware) mode\n"}, |
{1, " Event <F|G> <Value>", "Generate AcpiEvent (Fixed/GPE)\n"}, |
{1, " Gpe <GpeNum> [GpeBlockDevice]", "Simulate a GPE\n"}, |
{1, " Gpes", "Display info on all GPE devices\n"}, |
{1, " Sci", "Generate an SCI\n"}, |
{1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"}, |
{0, "\nFile I/O Commands:", "\n"}, |
{1, " Close", "Close debug output file\n"}, |
{1, " Load <Input Filename>", "Load ACPI table from a file\n"}, |
{1, " Open <Output Filename>", "Open a file for debug output\n"}, |
{1, " Unload <Namepath>", |
"Unload an ACPI table via namespace object\n"}, |
{0, "\nUser Space Commands:", "\n"}, |
{1, " Terminate", "Delete namespace and all internal objects\n"}, |
{1, " Thread <Threads><Loops><NamePath>", |
"Spawn threads to execute method(s)\n"}, |
{0, "\nDebug Test Commands:", "\n"}, |
{3, " Test <TestName>", "Invoke a debug test\n"}, |
{1, " Objects", "Read/write/compare all namespace data objects\n"}, |
{1, " Predefined", |
"Execute all ACPI predefined names (_STA, etc.)\n"}, |
#endif |
{0, NULL, NULL} |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_match_command_help |
* |
* PARAMETERS: command - Command string to match |
* help - Help table entry to attempt match |
* |
* RETURN: TRUE if command matched, FALSE otherwise |
* |
* DESCRIPTION: Attempt to match a command in the help table in order to |
* print help information for a single command. |
* |
******************************************************************************/ |
static u8 |
acpi_db_match_command_help(char *command, |
const struct acpi_db_command_help *help) |
{ |
char *invocation = help->invocation; |
u32 line_count; |
/* Valid commands in the help table begin with a couple of spaces */ |
if (*invocation != ' ') { |
return (FALSE); |
} |
while (*invocation == ' ') { |
invocation++; |
} |
/* Match command name (full command or substring) */ |
while ((*command) && (*invocation) && (*invocation != ' ')) { |
if (tolower((int)*command) != tolower((int)*invocation)) { |
return (FALSE); |
} |
invocation++; |
command++; |
} |
/* Print the appropriate number of help lines */ |
line_count = help->line_count; |
while (line_count) { |
acpi_os_printf("%-38s : %s", help->invocation, |
help->description); |
help++; |
line_count--; |
} |
return (TRUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_command_info |
* |
* PARAMETERS: command - Command string to match |
* display_all - Display all matching commands, or just |
* the first one (substring match) |
* |
* RETURN: None |
* |
* DESCRIPTION: Display help information for a Debugger command. |
* |
******************************************************************************/ |
static void acpi_db_display_command_info(char *command, u8 display_all) |
{ |
const struct acpi_db_command_help *next; |
u8 matched; |
next = acpi_gbl_db_command_help; |
while (next->invocation) { |
matched = acpi_db_match_command_help(command, next); |
if (!display_all && matched) { |
return; |
} |
next++; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_help |
* |
* PARAMETERS: command - Optional command string to display help. |
* if not specified, all debugger command |
* help strings are displayed |
* |
* RETURN: None |
* |
* DESCRIPTION: Display help for a single debugger command, or all of them. |
* |
******************************************************************************/ |
static void acpi_db_display_help(char *command) |
{ |
const struct acpi_db_command_help *next = acpi_gbl_db_command_help; |
if (!command) { |
/* No argument to help, display help for all commands */ |
while (next->invocation) { |
acpi_os_printf("%-38s%s", next->invocation, |
next->description); |
next++; |
} |
} else { |
/* Display help for all commands that match the subtring */ |
acpi_db_display_command_info(command, TRUE); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_next_token |
* |
* PARAMETERS: string - Command buffer |
* next - Return value, end of next token |
* |
* RETURN: Pointer to the start of the next token. |
* |
* DESCRIPTION: Command line parsing. Get the next token on the command line |
* |
******************************************************************************/ |
char *acpi_db_get_next_token(char *string, |
char **next, acpi_object_type * return_type) |
{ |
char *start; |
u32 depth; |
acpi_object_type type = ACPI_TYPE_INTEGER; |
/* At end of buffer? */ |
if (!string || !(*string)) { |
return (NULL); |
} |
/* Remove any spaces at the beginning */ |
if (*string == ' ') { |
while (*string && (*string == ' ')) { |
string++; |
} |
if (!(*string)) { |
return (NULL); |
} |
} |
switch (*string) { |
case '"': |
/* This is a quoted string, scan until closing quote */ |
string++; |
start = string; |
type = ACPI_TYPE_STRING; |
/* Find end of string */ |
while (*string && (*string != '"')) { |
string++; |
} |
break; |
case '(': |
/* This is the start of a buffer, scan until closing paren */ |
string++; |
start = string; |
type = ACPI_TYPE_BUFFER; |
/* Find end of buffer */ |
while (*string && (*string != ')')) { |
string++; |
} |
break; |
case '[': |
/* This is the start of a package, scan until closing bracket */ |
string++; |
depth = 1; |
start = string; |
type = ACPI_TYPE_PACKAGE; |
/* Find end of package (closing bracket) */ |
while (*string) { |
/* Handle String package elements */ |
if (*string == '"') { |
/* Find end of string */ |
string++; |
while (*string && (*string != '"')) { |
string++; |
} |
if (!(*string)) { |
break; |
} |
} else if (*string == '[') { |
depth++; /* A nested package declaration */ |
} else if (*string == ']') { |
depth--; |
if (depth == 0) { /* Found final package closing bracket */ |
break; |
} |
} |
string++; |
} |
break; |
default: |
start = string; |
/* Find end of token */ |
while (*string && (*string != ' ')) { |
string++; |
} |
break; |
} |
if (!(*string)) { |
*next = NULL; |
} else { |
*string = 0; |
*next = string + 1; |
} |
*return_type = type; |
return (start); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_line |
* |
* PARAMETERS: input_buffer - Command line buffer |
* |
* RETURN: Count of arguments to the command |
* |
* DESCRIPTION: Get the next command line from the user. Gets entire line |
* up to the next newline |
* |
******************************************************************************/ |
static u32 acpi_db_get_line(char *input_buffer) |
{ |
u32 i; |
u32 count; |
char *next; |
char *this; |
if (acpi_ut_safe_strcpy |
(acpi_gbl_db_parsed_buf, sizeof(acpi_gbl_db_parsed_buf), |
input_buffer)) { |
acpi_os_printf |
("Buffer overflow while parsing input line (max %u characters)\n", |
sizeof(acpi_gbl_db_parsed_buf)); |
return (0); |
} |
this = acpi_gbl_db_parsed_buf; |
for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++) { |
acpi_gbl_db_args[i] = acpi_db_get_next_token(this, &next, |
&acpi_gbl_db_arg_types |
[i]); |
if (!acpi_gbl_db_args[i]) { |
break; |
} |
this = next; |
} |
/* Uppercase the actual command */ |
if (acpi_gbl_db_args[0]) { |
acpi_ut_strupr(acpi_gbl_db_args[0]); |
} |
count = i; |
if (count) { |
count--; /* Number of args only */ |
} |
return (count); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_match_command |
* |
* PARAMETERS: user_command - User command line |
* |
* RETURN: Index into command array, -1 if not found |
* |
* DESCRIPTION: Search command array for a command match |
* |
******************************************************************************/ |
static u32 acpi_db_match_command(char *user_command) |
{ |
u32 i; |
if (!user_command || user_command[0] == 0) { |
return (CMD_NULL); |
} |
for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++) { |
if (strstr(acpi_gbl_db_commands[i].name, user_command) == |
acpi_gbl_db_commands[i].name) { |
return (i); |
} |
} |
/* Command not recognized */ |
return (CMD_NOT_FOUND); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_command_dispatch |
* |
* PARAMETERS: input_buffer - Command line buffer |
* walk_state - Current walk |
* op - Current (executing) parse op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Command dispatcher. |
* |
******************************************************************************/ |
acpi_status |
acpi_db_command_dispatch(char *input_buffer, |
struct acpi_walk_state * walk_state, |
union acpi_parse_object * op) |
{ |
u32 temp; |
u32 command_index; |
u32 param_count; |
char *command_line; |
acpi_status status = AE_CTRL_TRUE; |
/* If acpi_terminate has been called, terminate this thread */ |
if (acpi_gbl_db_terminate_loop) { |
return (AE_CTRL_TERMINATE); |
} |
/* Find command and add to the history buffer */ |
param_count = acpi_db_get_line(input_buffer); |
command_index = acpi_db_match_command(acpi_gbl_db_args[0]); |
temp = 0; |
/* |
* We don't want to add the !! command to the history buffer. It |
* would cause an infinite loop because it would always be the |
* previous command. |
*/ |
if (command_index != CMD_HISTORY_LAST) { |
acpi_db_add_to_history(input_buffer); |
} |
/* Verify that we have the minimum number of params */ |
if (param_count < acpi_gbl_db_commands[command_index].min_args) { |
acpi_os_printf |
("%u parameters entered, [%s] requires %u parameters\n", |
param_count, acpi_gbl_db_commands[command_index].name, |
acpi_gbl_db_commands[command_index].min_args); |
acpi_db_display_command_info(acpi_gbl_db_commands |
[command_index].name, FALSE); |
return (AE_CTRL_TRUE); |
} |
/* Decode and dispatch the command */ |
switch (command_index) { |
case CMD_NULL: |
if (op) { |
return (AE_OK); |
} |
break; |
case CMD_ALLOCATIONS: |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
acpi_ut_dump_allocations((u32)-1, NULL); |
#endif |
break; |
case CMD_ARGS: |
case CMD_ARGUMENTS: |
acpi_db_display_arguments(); |
break; |
case CMD_BREAKPOINT: |
acpi_db_set_method_breakpoint(acpi_gbl_db_args[1], walk_state, |
op); |
break; |
case CMD_BUSINFO: |
acpi_db_get_bus_info(); |
break; |
case CMD_CALL: |
acpi_db_set_method_call_breakpoint(op); |
status = AE_OK; |
break; |
case CMD_DEBUG: |
acpi_db_execute(acpi_gbl_db_args[1], |
&acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2], |
EX_SINGLE_STEP); |
break; |
case CMD_DISASSEMBLE: |
case CMD_DISASM: |
(void)acpi_db_disassemble_method(acpi_gbl_db_args[1]); |
break; |
case CMD_DUMP: |
acpi_db_decode_and_display_object(acpi_gbl_db_args[1], |
acpi_gbl_db_args[2]); |
break; |
case CMD_EVALUATE: |
case CMD_EXECUTE: |
acpi_db_execute(acpi_gbl_db_args[1], |
&acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2], |
EX_NO_SINGLE_STEP); |
break; |
case CMD_FIND: |
status = acpi_db_find_name_in_namespace(acpi_gbl_db_args[1]); |
break; |
case CMD_GO: |
acpi_gbl_cm_single_step = FALSE; |
return (AE_OK); |
case CMD_HANDLERS: |
acpi_db_display_handlers(); |
break; |
case CMD_HELP: |
case CMD_HELP2: |
acpi_db_display_help(acpi_gbl_db_args[1]); |
break; |
case CMD_HISTORY: |
acpi_db_display_history(); |
break; |
case CMD_HISTORY_EXE: /* ! command */ |
command_line = acpi_db_get_from_history(acpi_gbl_db_args[1]); |
if (!command_line) { |
return (AE_CTRL_TRUE); |
} |
status = acpi_db_command_dispatch(command_line, walk_state, op); |
return (status); |
case CMD_HISTORY_LAST: /* !! command */ |
command_line = acpi_db_get_from_history(NULL); |
if (!command_line) { |
return (AE_CTRL_TRUE); |
} |
status = acpi_db_command_dispatch(command_line, walk_state, op); |
return (status); |
case CMD_INFORMATION: |
acpi_db_display_method_info(op); |
break; |
case CMD_INTEGRITY: |
acpi_db_check_integrity(); |
break; |
case CMD_INTO: |
if (op) { |
acpi_gbl_cm_single_step = TRUE; |
return (AE_OK); |
} |
break; |
case CMD_LEVEL: |
if (param_count == 0) { |
acpi_os_printf |
("Current debug level for file output is: %8.8lX\n", |
acpi_gbl_db_debug_level); |
acpi_os_printf |
("Current debug level for console output is: %8.8lX\n", |
acpi_gbl_db_console_debug_level); |
} else if (param_count == 2) { |
temp = acpi_gbl_db_console_debug_level; |
acpi_gbl_db_console_debug_level = |
strtoul(acpi_gbl_db_args[1], NULL, 16); |
acpi_os_printf |
("Debug Level for console output was %8.8lX, now %8.8lX\n", |
temp, acpi_gbl_db_console_debug_level); |
} else { |
temp = acpi_gbl_db_debug_level; |
acpi_gbl_db_debug_level = |
strtoul(acpi_gbl_db_args[1], NULL, 16); |
acpi_os_printf |
("Debug Level for file output was %8.8lX, now %8.8lX\n", |
temp, acpi_gbl_db_debug_level); |
} |
break; |
case CMD_LIST: |
acpi_db_disassemble_aml(acpi_gbl_db_args[1], op); |
break; |
case CMD_LOCKS: |
acpi_db_display_locks(); |
break; |
case CMD_LOCALS: |
acpi_db_display_locals(); |
break; |
case CMD_METHODS: |
status = acpi_db_display_objects("METHOD", acpi_gbl_db_args[1]); |
break; |
case CMD_NAMESPACE: |
acpi_db_dump_namespace(acpi_gbl_db_args[1], |
acpi_gbl_db_args[2]); |
break; |
case CMD_NOTIFY: |
temp = strtoul(acpi_gbl_db_args[2], NULL, 0); |
acpi_db_send_notify(acpi_gbl_db_args[1], temp); |
break; |
case CMD_OBJECTS: |
acpi_ut_strupr(acpi_gbl_db_args[1]); |
status = |
acpi_db_display_objects(acpi_gbl_db_args[1], |
acpi_gbl_db_args[2]); |
break; |
case CMD_OSI: |
acpi_db_display_interfaces(acpi_gbl_db_args[1], |
acpi_gbl_db_args[2]); |
break; |
case CMD_OWNER: |
acpi_db_dump_namespace_by_owner(acpi_gbl_db_args[1], |
acpi_gbl_db_args[2]); |
break; |
case CMD_PATHS: |
acpi_db_dump_namespace_paths(); |
break; |
case CMD_PREFIX: |
acpi_db_set_scope(acpi_gbl_db_args[1]); |
break; |
case CMD_REFERENCES: |
acpi_db_find_references(acpi_gbl_db_args[1]); |
break; |
case CMD_RESOURCES: |
acpi_db_display_resources(acpi_gbl_db_args[1]); |
break; |
case CMD_RESULTS: |
acpi_db_display_results(); |
break; |
case CMD_SET: |
acpi_db_set_method_data(acpi_gbl_db_args[1], |
acpi_gbl_db_args[2], |
acpi_gbl_db_args[3]); |
break; |
case CMD_STATS: |
status = acpi_db_display_statistics(acpi_gbl_db_args[1]); |
break; |
case CMD_STOP: |
return (AE_NOT_IMPLEMENTED); |
case CMD_TABLES: |
acpi_db_display_table_info(acpi_gbl_db_args[1]); |
break; |
case CMD_TEMPLATE: |
acpi_db_display_template(acpi_gbl_db_args[1]); |
break; |
case CMD_TRACE: |
acpi_db_trace(acpi_gbl_db_args[1], acpi_gbl_db_args[2], |
acpi_gbl_db_args[3]); |
break; |
case CMD_TREE: |
acpi_db_display_calling_tree(); |
break; |
case CMD_TYPE: |
acpi_db_display_object_type(acpi_gbl_db_args[1]); |
break; |
#ifdef ACPI_APPLICATION |
/* Hardware simulation commands. */ |
case CMD_ENABLEACPI: |
#if (!ACPI_REDUCED_HARDWARE) |
status = acpi_enable(); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("AcpiEnable failed (Status=%X)\n", |
status); |
return (status); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
break; |
case CMD_EVENT: |
acpi_os_printf("Event command not implemented\n"); |
break; |
case CMD_GPE: |
acpi_db_generate_gpe(acpi_gbl_db_args[1], acpi_gbl_db_args[2]); |
break; |
case CMD_GPES: |
acpi_db_display_gpes(); |
break; |
case CMD_SCI: |
acpi_db_generate_sci(); |
break; |
case CMD_SLEEP: |
status = acpi_db_sleep(acpi_gbl_db_args[1]); |
break; |
/* File I/O commands. */ |
case CMD_CLOSE: |
acpi_db_close_debug_file(); |
break; |
case CMD_LOAD: |
status = |
acpi_db_get_table_from_file(acpi_gbl_db_args[1], NULL, |
FALSE); |
break; |
case CMD_OPEN: |
acpi_db_open_debug_file(acpi_gbl_db_args[1]); |
break; |
/* User space commands. */ |
case CMD_TERMINATE: |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
acpi_ut_subsystem_shutdown(); |
/* |
* TBD: [Restructure] Need some way to re-initialize without |
* re-creating the semaphores! |
*/ |
acpi_gbl_db_terminate_loop = TRUE; |
/* acpi_initialize (NULL); */ |
break; |
case CMD_THREADS: |
acpi_db_create_execution_threads(acpi_gbl_db_args[1], |
acpi_gbl_db_args[2], |
acpi_gbl_db_args[3]); |
break; |
/* Debug test commands. */ |
case CMD_PREDEFINED: |
acpi_db_check_predefined_names(); |
break; |
case CMD_TEST: |
acpi_db_execute_test(acpi_gbl_db_args[1]); |
break; |
case CMD_UNLOAD: |
acpi_db_unload_acpi_table(acpi_gbl_db_args[1]); |
break; |
#endif |
case CMD_EXIT: |
case CMD_QUIT: |
if (op) { |
acpi_os_printf("Method execution terminated\n"); |
return (AE_CTRL_TERMINATE); |
} |
if (!acpi_gbl_db_output_to_file) { |
acpi_dbg_level = ACPI_DEBUG_DEFAULT; |
} |
#ifdef ACPI_APPLICATION |
acpi_db_close_debug_file(); |
#endif |
acpi_gbl_db_terminate_loop = TRUE; |
return (AE_CTRL_TERMINATE); |
case CMD_NOT_FOUND: |
default: |
acpi_os_printf("%s: unknown command\n", acpi_gbl_db_args[0]); |
return (AE_CTRL_TRUE); |
} |
if (ACPI_SUCCESS(status)) { |
status = AE_CTRL_TRUE; |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_execute_thread |
* |
* PARAMETERS: context - Not used |
* |
* RETURN: None |
* |
* DESCRIPTION: Debugger execute thread. Waits for a command line, then |
* simply dispatches it. |
* |
******************************************************************************/ |
void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context) |
{ |
acpi_status status = AE_OK; |
acpi_status Mstatus; |
while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) { |
acpi_gbl_method_executing = FALSE; |
acpi_gbl_step_to_next_call = FALSE; |
Mstatus = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, |
ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(Mstatus)) { |
return; |
} |
status = |
acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL); |
acpi_os_release_mutex(acpi_gbl_db_command_complete); |
} |
acpi_gbl_db_threads_terminated = TRUE; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_single_thread |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Debugger execute thread. Waits for a command line, then |
* simply dispatches it. |
* |
******************************************************************************/ |
static void acpi_db_single_thread(void) |
{ |
acpi_gbl_method_executing = FALSE; |
acpi_gbl_step_to_next_call = FALSE; |
(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_user_commands |
* |
* PARAMETERS: prompt - User prompt (depends on mode) |
* op - Current executing parse op |
* |
* RETURN: None |
* |
* DESCRIPTION: Command line execution for the AML debugger. Commands are |
* matched and dispatched here. |
* |
******************************************************************************/ |
acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) |
{ |
acpi_status status = AE_OK; |
acpi_os_printf("\n"); |
/* TBD: [Restructure] Need a separate command line buffer for step mode */ |
while (!acpi_gbl_db_terminate_loop) { |
/* Force output to console until a command is entered */ |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
/* Different prompt if method is executing */ |
if (!acpi_gbl_method_executing) { |
acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); |
} else { |
acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); |
} |
/* Get the user input line */ |
status = acpi_os_get_line(acpi_gbl_db_line_buf, |
ACPI_DB_LINE_BUFFER_SIZE, NULL); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"While parsing command line")); |
return (status); |
} |
/* Check for single or multithreaded debug */ |
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { |
/* |
* Signal the debug thread that we have a command to execute, |
* and wait for the command to complete. |
*/ |
acpi_os_release_mutex(acpi_gbl_db_command_ready); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = |
acpi_os_acquire_mutex(acpi_gbl_db_command_complete, |
ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} else { |
/* Just call to the command line interpreter */ |
acpi_db_single_thread(); |
} |
} |
return (status); |
} |
/drivers/acpi/acpica/dbmethod.c |
---|
0,0 → 1,369 |
/******************************************************************************* |
* |
* Module Name: dbmethod - Debug commands for control methods |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#include "acdebug.h" |
#include "acparser.h" |
#include "acpredef.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbmethod") |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_set_method_breakpoint |
* |
* PARAMETERS: location - AML offset of breakpoint |
* walk_state - Current walk info |
* op - Current Op (from parse walk) |
* |
* RETURN: None |
* |
* DESCRIPTION: Set a breakpoint in a control method at the specified |
* AML offset |
* |
******************************************************************************/ |
void |
acpi_db_set_method_breakpoint(char *location, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
u32 address; |
u32 aml_offset; |
if (!op) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
/* Get and verify the breakpoint address */ |
address = strtoul(location, NULL, 16); |
aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml, |
walk_state->parser_state.aml_start); |
if (address <= aml_offset) { |
acpi_os_printf("Breakpoint %X is beyond current address %X\n", |
address, aml_offset); |
} |
/* Save breakpoint in current walk */ |
walk_state->user_breakpoint = address; |
acpi_os_printf("Breakpoint set at AML offset %X\n", address); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_set_method_call_breakpoint |
* |
* PARAMETERS: op - Current Op (from parse walk) |
* |
* RETURN: None |
* |
* DESCRIPTION: Set a breakpoint in a control method at the specified |
* AML offset |
* |
******************************************************************************/ |
void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op) |
{ |
if (!op) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
acpi_gbl_step_to_next_call = TRUE; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_set_method_data |
* |
* PARAMETERS: type_arg - L for local, A for argument |
* index_arg - which one |
* value_arg - Value to set. |
* |
* RETURN: None |
* |
* DESCRIPTION: Set a local or argument for the running control method. |
* NOTE: only object supported is Number. |
* |
******************************************************************************/ |
void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg) |
{ |
char type; |
u32 index; |
u32 value; |
struct acpi_walk_state *walk_state; |
union acpi_operand_object *obj_desc; |
acpi_status status; |
struct acpi_namespace_node *node; |
/* Validate type_arg */ |
acpi_ut_strupr(type_arg); |
type = type_arg[0]; |
if ((type != 'L') && (type != 'A') && (type != 'N')) { |
acpi_os_printf("Invalid SET operand: %s\n", type_arg); |
return; |
} |
value = strtoul(value_arg, NULL, 16); |
if (type == 'N') { |
node = acpi_db_convert_to_node(index_arg); |
if (!node) { |
return; |
} |
if (node->type != ACPI_TYPE_INTEGER) { |
acpi_os_printf("Can only set Integer nodes\n"); |
return; |
} |
obj_desc = node->object; |
obj_desc->integer.value = value; |
return; |
} |
/* Get the index and value */ |
index = strtoul(index_arg, NULL, 16); |
walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list); |
if (!walk_state) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
/* Create and initialize the new object */ |
obj_desc = acpi_ut_create_integer_object((u64)value); |
if (!obj_desc) { |
acpi_os_printf("Could not create an internal object\n"); |
return; |
} |
/* Store the new object into the target */ |
switch (type) { |
case 'A': |
/* Set a method argument */ |
if (index > ACPI_METHOD_MAX_ARG) { |
acpi_os_printf("Arg%u - Invalid argument name\n", |
index); |
goto cleanup; |
} |
status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG, |
index, obj_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
obj_desc = walk_state->arguments[index].object; |
acpi_os_printf("Arg%u: ", index); |
acpi_db_display_internal_object(obj_desc, walk_state); |
break; |
case 'L': |
/* Set a method local */ |
if (index > ACPI_METHOD_MAX_LOCAL) { |
acpi_os_printf |
("Local%u - Invalid local variable name\n", index); |
goto cleanup; |
} |
status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL, |
index, obj_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
obj_desc = walk_state->local_variables[index].object; |
acpi_os_printf("Local%u: ", index); |
acpi_db_display_internal_object(obj_desc, walk_state); |
break; |
default: |
break; |
} |
cleanup: |
acpi_ut_remove_reference(obj_desc); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_disassemble_aml |
* |
* PARAMETERS: statements - Number of statements to disassemble |
* op - Current Op (from parse walk) |
* |
* RETURN: None |
* |
* DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number |
* of statements specified. |
* |
******************************************************************************/ |
void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op) |
{ |
u32 num_statements = 8; |
if (!op) { |
acpi_os_printf("There is no method currently executing\n"); |
return; |
} |
if (statements) { |
num_statements = strtoul(statements, NULL, 0); |
} |
#ifdef ACPI_DISASSEMBLER |
acpi_dm_disassemble(NULL, op, num_statements); |
#endif |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_disassemble_method |
* |
* PARAMETERS: name - Name of control method |
* |
* RETURN: None |
* |
* DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number |
* of statements specified. |
* |
******************************************************************************/ |
acpi_status acpi_db_disassemble_method(char *name) |
{ |
acpi_status status; |
union acpi_parse_object *op; |
struct acpi_walk_state *walk_state; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *method; |
method = acpi_db_convert_to_node(name); |
if (!method) { |
return (AE_BAD_PARAMETER); |
} |
if (method->type != ACPI_TYPE_METHOD) { |
ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method", |
name, acpi_ut_get_type_name(method->type))); |
return (AE_BAD_PARAMETER); |
} |
obj_desc = method->object; |
op = acpi_ps_create_scope_op(obj_desc->method.aml_start); |
if (!op) { |
return (AE_NO_MEMORY); |
} |
/* Create and initialize a new walk state */ |
walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL); |
if (!walk_state) { |
return (AE_NO_MEMORY); |
} |
status = acpi_ds_init_aml_walk(walk_state, op, NULL, |
obj_desc->method.aml_start, |
obj_desc->method.aml_length, NULL, |
ACPI_IMODE_LOAD_PASS1); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); |
walk_state->owner_id = obj_desc->method.owner_id; |
/* Push start scope on scope stack and make it current */ |
status = acpi_ds_scope_stack_push(method, method->type, walk_state); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Parse the entire method AML including deferred operators */ |
walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE; |
walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE; |
status = acpi_ps_parse_aml(walk_state); |
#ifdef ACPI_DISASSEMBLER |
(void)acpi_dm_parse_deferred_ops(op); |
/* Now we can disassemble the method */ |
acpi_gbl_dm_opt_verbose = FALSE; |
acpi_dm_disassemble(NULL, op, 0); |
acpi_gbl_dm_opt_verbose = TRUE; |
#endif |
acpi_ps_delete_parse_tree(op); |
/* Method cleanup */ |
acpi_ns_delete_namespace_subtree(method); |
acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id); |
acpi_ut_release_owner_id(&obj_desc->method.owner_id); |
return (AE_OK); |
} |
/drivers/acpi/acpica/dbnames.c |
---|
0,0 → 1,947 |
/******************************************************************************* |
* |
* Module Name: dbnames - Debugger commands for the acpi namespace |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acdebug.h" |
#include "acpredef.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbnames") |
/* Local prototypes */ |
static acpi_status |
acpi_db_walk_and_match_name(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
static acpi_status |
acpi_db_walk_for_predefined_names(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
static acpi_status |
acpi_db_walk_for_specific_objects(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
static acpi_status |
acpi_db_walk_for_object_counts(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
static acpi_status |
acpi_db_integrity_walk(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value); |
static acpi_status |
acpi_db_walk_for_references(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
static acpi_status |
acpi_db_bus_walk(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value); |
/* |
* Arguments for the Objects command |
* These object types map directly to the ACPI_TYPES |
*/ |
static struct acpi_db_argument_info acpi_db_object_types[] = { |
{"ANY"}, |
{"INTEGERS"}, |
{"STRINGS"}, |
{"BUFFERS"}, |
{"PACKAGES"}, |
{"FIELDS"}, |
{"DEVICES"}, |
{"EVENTS"}, |
{"METHODS"}, |
{"MUTEXES"}, |
{"REGIONS"}, |
{"POWERRESOURCES"}, |
{"PROCESSORS"}, |
{"THERMALZONES"}, |
{"BUFFERFIELDS"}, |
{"DDBHANDLES"}, |
{"DEBUG"}, |
{"REGIONFIELDS"}, |
{"BANKFIELDS"}, |
{"INDEXFIELDS"}, |
{"REFERENCES"}, |
{"ALIASES"}, |
{"METHODALIASES"}, |
{"NOTIFY"}, |
{"ADDRESSHANDLER"}, |
{"RESOURCE"}, |
{"RESOURCEFIELD"}, |
{"SCOPES"}, |
{NULL} /* Must be null terminated */ |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_set_scope |
* |
* PARAMETERS: name - New scope path |
* |
* RETURN: Status |
* |
* DESCRIPTION: Set the "current scope" as maintained by this utility. |
* The scope is used as a prefix to ACPI paths. |
* |
******************************************************************************/ |
void acpi_db_set_scope(char *name) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
if (!name || name[0] == 0) { |
acpi_os_printf("Current scope: %s\n", acpi_gbl_db_scope_buf); |
return; |
} |
acpi_db_prep_namestring(name); |
if (ACPI_IS_ROOT_PREFIX(name[0])) { |
/* Validate new scope from the root */ |
status = acpi_ns_get_node(acpi_gbl_root_node, name, |
ACPI_NS_NO_UPSEARCH, &node); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
acpi_gbl_db_scope_buf[0] = 0; |
} else { |
/* Validate new scope relative to old scope */ |
status = acpi_ns_get_node(acpi_gbl_db_scope_node, name, |
ACPI_NS_NO_UPSEARCH, &node); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
} |
/* Build the final pathname */ |
if (acpi_ut_safe_strcat |
(acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), name)) { |
status = AE_BUFFER_OVERFLOW; |
goto error_exit; |
} |
if (acpi_ut_safe_strcat |
(acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), "\\")) { |
status = AE_BUFFER_OVERFLOW; |
goto error_exit; |
} |
acpi_gbl_db_scope_node = node; |
acpi_os_printf("New scope: %s\n", acpi_gbl_db_scope_buf); |
return; |
error_exit: |
acpi_os_printf("Could not attach scope: %s, %s\n", |
name, acpi_format_exception(status)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_namespace |
* |
* PARAMETERS: start_arg - Node to begin namespace dump |
* depth_arg - Maximum tree depth to be dumped |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed |
* with type and other information. |
* |
******************************************************************************/ |
void acpi_db_dump_namespace(char *start_arg, char *depth_arg) |
{ |
acpi_handle subtree_entry = acpi_gbl_root_node; |
u32 max_depth = ACPI_UINT32_MAX; |
/* No argument given, just start at the root and dump entire namespace */ |
if (start_arg) { |
subtree_entry = acpi_db_convert_to_node(start_arg); |
if (!subtree_entry) { |
return; |
} |
/* Now we can check for the depth argument */ |
if (depth_arg) { |
max_depth = strtoul(depth_arg, NULL, 0); |
} |
} |
acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n", |
((struct acpi_namespace_node *)subtree_entry)->name. |
ascii, subtree_entry); |
/* Display the subtree */ |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, |
ACPI_OWNER_ID_MAX, subtree_entry); |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_namespace_paths |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump entire namespace with full object pathnames and object |
* type information. Alternative to "namespace" command. |
* |
******************************************************************************/ |
void acpi_db_dump_namespace_paths(void) |
{ |
acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
acpi_os_printf("ACPI Namespace (from root):\n"); |
/* Display the entire namespace */ |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
acpi_ns_dump_object_paths(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, |
ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX, |
acpi_gbl_root_node); |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_namespace_by_owner |
* |
* PARAMETERS: owner_arg - Owner ID whose nodes will be displayed |
* depth_arg - Maximum tree depth to be dumped |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump elements of the namespace that are owned by the owner_id. |
* |
******************************************************************************/ |
void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg) |
{ |
acpi_handle subtree_entry = acpi_gbl_root_node; |
u32 max_depth = ACPI_UINT32_MAX; |
acpi_owner_id owner_id; |
owner_id = (acpi_owner_id) strtoul(owner_arg, NULL, 0); |
/* Now we can check for the depth argument */ |
if (depth_arg) { |
max_depth = strtoul(depth_arg, NULL, 0); |
} |
acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
acpi_os_printf("ACPI Namespace by owner %X:\n", owner_id); |
/* Display the subtree */ |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, |
owner_id, subtree_entry); |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_walk_and_match_name |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Find a particular name/names within the namespace. Wildcards |
* are supported -- '?' matches any character. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_walk_and_match_name(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
acpi_status status; |
char *requested_name = (char *)context; |
u32 i; |
struct acpi_buffer buffer; |
struct acpi_walk_info info; |
/* Check for a name match */ |
for (i = 0; i < 4; i++) { |
/* Wildcard support */ |
if ((requested_name[i] != '?') && |
(requested_name[i] != ((struct acpi_namespace_node *) |
obj_handle)->name.ascii[i])) { |
/* No match, just exit */ |
return (AE_OK); |
} |
} |
/* Get the full pathname to this object */ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could Not get pathname for object %p\n", |
obj_handle); |
} else { |
info.owner_id = ACPI_OWNER_ID_MAX; |
info.debug_level = ACPI_UINT32_MAX; |
info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
acpi_os_printf("%32s", (char *)buffer.pointer); |
(void)acpi_ns_dump_one_object(obj_handle, nesting_level, &info, |
NULL); |
ACPI_FREE(buffer.pointer); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_find_name_in_namespace |
* |
* PARAMETERS: name_arg - The 4-character ACPI name to find. |
* wildcards are supported. |
* |
* RETURN: None |
* |
* DESCRIPTION: Search the namespace for a given name (with wildcards) |
* |
******************************************************************************/ |
acpi_status acpi_db_find_name_in_namespace(char *name_arg) |
{ |
char acpi_name[5] = "____"; |
char *acpi_name_ptr = acpi_name; |
if (strlen(name_arg) > ACPI_NAME_SIZE) { |
acpi_os_printf("Name must be no longer than 4 characters\n"); |
return (AE_OK); |
} |
/* Pad out name with underscores as necessary to create a 4-char name */ |
acpi_ut_strupr(name_arg); |
while (*name_arg) { |
*acpi_name_ptr = *name_arg; |
acpi_name_ptr++; |
name_arg++; |
} |
/* Walk the namespace from the root */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, acpi_db_walk_and_match_name, |
NULL, acpi_name, NULL); |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_walk_for_predefined_names |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Detect and display predefined ACPI names (names that start with |
* an underscore) |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_walk_for_predefined_names(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
u32 *count = (u32 *)context; |
const union acpi_predefined_info *predefined; |
const union acpi_predefined_info *package = NULL; |
char *pathname; |
char string_buffer[48]; |
predefined = acpi_ut_match_predefined_method(node->name.ascii); |
if (!predefined) { |
return (AE_OK); |
} |
pathname = acpi_ns_get_external_pathname(node); |
if (!pathname) { |
return (AE_OK); |
} |
/* If method returns a package, the info is in the next table entry */ |
if (predefined->info.expected_btypes & ACPI_RTYPE_PACKAGE) { |
package = predefined + 1; |
} |
acpi_ut_get_expected_return_types(string_buffer, |
predefined->info.expected_btypes); |
acpi_os_printf("%-32s Arguments %X, Return Types: %s", pathname, |
METHOD_GET_ARG_COUNT(predefined->info.argument_list), |
string_buffer); |
if (package) { |
acpi_os_printf(" (PkgType %2.2X, ObjType %2.2X, Count %2.2X)", |
package->ret_info.type, |
package->ret_info.object_type1, |
package->ret_info.count1); |
} |
acpi_os_printf("\n"); |
/* Check that the declared argument count matches the ACPI spec */ |
acpi_ns_check_acpi_compliance(pathname, node, predefined); |
ACPI_FREE(pathname); |
(*count)++; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_check_predefined_names |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Validate all predefined names in the namespace |
* |
******************************************************************************/ |
void acpi_db_check_predefined_names(void) |
{ |
u32 count = 0; |
/* Search all nodes in namespace */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, |
acpi_db_walk_for_predefined_names, NULL, |
(void *)&count, NULL); |
acpi_os_printf("Found %u predefined names in the namespace\n", count); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_walk_for_object_counts |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Display short info about objects in the namespace |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_walk_for_object_counts(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
struct acpi_object_info *info = (struct acpi_object_info *)context; |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
if (node->type > ACPI_TYPE_NS_NODE_MAX) { |
acpi_os_printf("[%4.4s]: Unknown object type %X\n", |
node->name.ascii, node->type); |
} else { |
info->types[node->type]++; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_walk_for_specific_objects |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Display short info about objects in the namespace |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_walk_for_specific_objects(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
struct acpi_walk_info *info = (struct acpi_walk_info *)context; |
struct acpi_buffer buffer; |
acpi_status status; |
info->count++; |
/* Get and display the full pathname to this object */ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could Not get pathname for object %p\n", |
obj_handle); |
return (AE_OK); |
} |
acpi_os_printf("%32s", (char *)buffer.pointer); |
ACPI_FREE(buffer.pointer); |
/* Dump short info about the object */ |
(void)acpi_ns_dump_one_object(obj_handle, nesting_level, info, NULL); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_objects |
* |
* PARAMETERS: obj_type_arg - Type of object to display |
* display_count_arg - Max depth to display |
* |
* RETURN: None |
* |
* DESCRIPTION: Display objects in the namespace of the requested type |
* |
******************************************************************************/ |
acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg) |
{ |
struct acpi_walk_info info; |
acpi_object_type type; |
struct acpi_object_info *object_info; |
u32 i; |
u32 total_objects = 0; |
/* No argument means display summary/count of all object types */ |
if (!obj_type_arg) { |
object_info = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info)); |
/* Walk the namespace from the root */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, |
acpi_db_walk_for_object_counts, NULL, |
(void *)object_info, NULL); |
acpi_os_printf("\nSummary of namespace objects:\n\n"); |
for (i = 0; i < ACPI_TOTAL_TYPES; i++) { |
acpi_os_printf("%8u %s\n", object_info->types[i], |
acpi_ut_get_type_name(i)); |
total_objects += object_info->types[i]; |
} |
acpi_os_printf("\n%8u Total namespace objects\n\n", |
total_objects); |
ACPI_FREE(object_info); |
return (AE_OK); |
} |
/* Get the object type */ |
type = acpi_db_match_argument(obj_type_arg, acpi_db_object_types); |
if (type == ACPI_TYPE_NOT_FOUND) { |
acpi_os_printf("Invalid or unsupported argument\n"); |
return (AE_OK); |
} |
acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
acpi_os_printf |
("Objects of type [%s] defined in the current ACPI Namespace:\n", |
acpi_ut_get_type_name(type)); |
acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
info.count = 0; |
info.owner_id = ACPI_OWNER_ID_MAX; |
info.debug_level = ACPI_UINT32_MAX; |
info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
/* Walk the namespace from the root */ |
(void)acpi_walk_namespace(type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, |
acpi_db_walk_for_specific_objects, NULL, |
(void *)&info, NULL); |
acpi_os_printf |
("\nFound %u objects of type [%s] in the current ACPI Namespace\n", |
info.count, acpi_ut_get_type_name(type)); |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_integrity_walk |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Examine one NS node for valid values. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_integrity_walk(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value) |
{ |
struct acpi_integrity_info *info = |
(struct acpi_integrity_info *)context; |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
union acpi_operand_object *object; |
u8 alias = TRUE; |
info->nodes++; |
/* Verify the NS node, and dereference aliases */ |
while (alias) { |
if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { |
acpi_os_printf |
("Invalid Descriptor Type for Node %p [%s] - " |
"is %2.2X should be %2.2X\n", node, |
acpi_ut_get_descriptor_name(node), |
ACPI_GET_DESCRIPTOR_TYPE(node), |
ACPI_DESC_TYPE_NAMED); |
return (AE_OK); |
} |
if ((node->type == ACPI_TYPE_LOCAL_ALIAS) || |
(node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
node = (struct acpi_namespace_node *)node->object; |
} else { |
alias = FALSE; |
} |
} |
if (node->type > ACPI_TYPE_LOCAL_MAX) { |
acpi_os_printf("Invalid Object Type for Node %p, Type = %X\n", |
node, node->type); |
return (AE_OK); |
} |
if (!acpi_ut_valid_acpi_name(node->name.ascii)) { |
acpi_os_printf("Invalid AcpiName for Node %p\n", node); |
return (AE_OK); |
} |
object = acpi_ns_get_attached_object(node); |
if (object) { |
info->objects++; |
if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) { |
acpi_os_printf |
("Invalid Descriptor Type for Object %p [%s]\n", |
object, acpi_ut_get_descriptor_name(object)); |
} |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_check_integrity |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Check entire namespace for data structure integrity |
* |
******************************************************************************/ |
void acpi_db_check_integrity(void) |
{ |
struct acpi_integrity_info info = { 0, 0 }; |
/* Search all nodes in namespace */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, acpi_db_integrity_walk, NULL, |
(void *)&info, NULL); |
acpi_os_printf("Verified %u namespace nodes with %u Objects\n", |
info.nodes, info.objects); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_walk_for_references |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check if this namespace object refers to the target object |
* that is passed in as the context value. |
* |
* Note: Currently doesn't check subobjects within the Node's object |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_walk_for_references(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
union acpi_operand_object *obj_desc = |
(union acpi_operand_object *)context; |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
/* Check for match against the namespace node itself */ |
if (node == (void *)obj_desc) { |
acpi_os_printf("Object is a Node [%4.4s]\n", |
acpi_ut_get_node_name(node)); |
} |
/* Check for match against the object attached to the node */ |
if (acpi_ns_get_attached_object(node) == obj_desc) { |
acpi_os_printf("Reference at Node->Object %p [%4.4s]\n", |
node, acpi_ut_get_node_name(node)); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_find_references |
* |
* PARAMETERS: object_arg - String with hex value of the object |
* |
* RETURN: None |
* |
* DESCRIPTION: Search namespace for all references to the input object |
* |
******************************************************************************/ |
void acpi_db_find_references(char *object_arg) |
{ |
union acpi_operand_object *obj_desc; |
acpi_size address; |
/* Convert string to object pointer */ |
address = strtoul(object_arg, NULL, 16); |
obj_desc = ACPI_TO_POINTER(address); |
/* Search all nodes in namespace */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, acpi_db_walk_for_references, |
NULL, (void *)obj_desc, NULL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_bus_walk |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Display info about device objects that have a corresponding |
* _PRT method. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_bus_walk(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value) |
{ |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
acpi_status status; |
struct acpi_buffer buffer; |
struct acpi_namespace_node *temp_node; |
struct acpi_device_info *info; |
u32 i; |
if ((node->type != ACPI_TYPE_DEVICE) && |
(node->type != ACPI_TYPE_PROCESSOR)) { |
return (AE_OK); |
} |
/* Exit if there is no _PRT under this device */ |
status = acpi_get_handle(node, METHOD_NAME__PRT, |
ACPI_CAST_PTR(acpi_handle, &temp_node)); |
if (ACPI_FAILURE(status)) { |
return (AE_OK); |
} |
/* Get the full path to this device object */ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could Not get pathname for object %p\n", |
obj_handle); |
return (AE_OK); |
} |
status = acpi_get_object_info(obj_handle, &info); |
if (ACPI_FAILURE(status)) { |
return (AE_OK); |
} |
/* Display the full path */ |
acpi_os_printf("%-32s Type %X", (char *)buffer.pointer, node->type); |
ACPI_FREE(buffer.pointer); |
if (info->flags & ACPI_PCI_ROOT_BRIDGE) { |
acpi_os_printf(" - Is PCI Root Bridge"); |
} |
acpi_os_printf("\n"); |
/* _PRT info */ |
acpi_os_printf("_PRT: %p\n", temp_node); |
/* Dump _ADR, _HID, _UID, _CID */ |
if (info->valid & ACPI_VALID_ADR) { |
acpi_os_printf("_ADR: %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(info->address)); |
} else { |
acpi_os_printf("_ADR: <Not Present>\n"); |
} |
if (info->valid & ACPI_VALID_HID) { |
acpi_os_printf("_HID: %s\n", info->hardware_id.string); |
} else { |
acpi_os_printf("_HID: <Not Present>\n"); |
} |
if (info->valid & ACPI_VALID_UID) { |
acpi_os_printf("_UID: %s\n", info->unique_id.string); |
} else { |
acpi_os_printf("_UID: <Not Present>\n"); |
} |
if (info->valid & ACPI_VALID_CID) { |
for (i = 0; i < info->compatible_id_list.count; i++) { |
acpi_os_printf("_CID: %s\n", |
info->compatible_id_list.ids[i].string); |
} |
} else { |
acpi_os_printf("_CID: <Not Present>\n"); |
} |
ACPI_FREE(info); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_get_bus_info |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Display info about system busses. |
* |
******************************************************************************/ |
void acpi_db_get_bus_info(void) |
{ |
/* Search all nodes in namespace */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, acpi_db_bus_walk, NULL, NULL, |
NULL); |
} |
/drivers/acpi/acpica/dbobject.c |
---|
0,0 → 1,533 |
/******************************************************************************* |
* |
* Module Name: dbobject - ACPI object decode and display |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbobject") |
/* Local prototypes */ |
static void acpi_db_decode_node(struct acpi_namespace_node *node); |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_method_info |
* |
* PARAMETERS: status - Method execution status |
* walk_state - Current state of the parse tree walk |
* |
* RETURN: None |
* |
* DESCRIPTION: Called when a method has been aborted because of an error. |
* Dumps the method execution stack, and the method locals/args, |
* and disassembles the AML opcode that failed. |
* |
******************************************************************************/ |
void |
acpi_db_dump_method_info(acpi_status status, struct acpi_walk_state *walk_state) |
{ |
struct acpi_thread_state *thread; |
/* Ignore control codes, they are not errors */ |
if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) { |
return; |
} |
/* We may be executing a deferred opcode */ |
if (walk_state->deferred_node) { |
acpi_os_printf("Executing subtree for Buffer/Package/Region\n"); |
return; |
} |
/* |
* If there is no Thread, we are not actually executing a method. |
* This can happen when the iASL compiler calls the interpreter |
* to perform constant folding. |
*/ |
thread = walk_state->thread; |
if (!thread) { |
return; |
} |
/* Display the method locals and arguments */ |
acpi_os_printf("\n"); |
acpi_db_decode_locals(walk_state); |
acpi_os_printf("\n"); |
acpi_db_decode_arguments(walk_state); |
acpi_os_printf("\n"); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_decode_internal_object |
* |
* PARAMETERS: obj_desc - Object to be displayed |
* |
* RETURN: None |
* |
* DESCRIPTION: Short display of an internal object. Numbers/Strings/Buffers. |
* |
******************************************************************************/ |
void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc) |
{ |
u32 i; |
if (!obj_desc) { |
acpi_os_printf(" Uninitialized"); |
return; |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { |
acpi_os_printf(" %p [%s]", obj_desc, |
acpi_ut_get_descriptor_name(obj_desc)); |
return; |
} |
acpi_os_printf(" %s", acpi_ut_get_object_type_name(obj_desc)); |
switch (obj_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
acpi_os_printf(" %8.8X%8.8X", |
ACPI_FORMAT_UINT64(obj_desc->integer.value)); |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf("(%u) \"%.24s", |
obj_desc->string.length, |
obj_desc->string.pointer); |
if (obj_desc->string.length > 24) { |
acpi_os_printf("..."); |
} else { |
acpi_os_printf("\""); |
} |
break; |
case ACPI_TYPE_BUFFER: |
acpi_os_printf("(%u)", obj_desc->buffer.length); |
for (i = 0; (i < 8) && (i < obj_desc->buffer.length); i++) { |
acpi_os_printf(" %2.2X", obj_desc->buffer.pointer[i]); |
} |
break; |
default: |
acpi_os_printf(" %p", obj_desc); |
break; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_decode_node |
* |
* PARAMETERS: node - Object to be displayed |
* |
* RETURN: None |
* |
* DESCRIPTION: Short display of a namespace node |
* |
******************************************************************************/ |
static void acpi_db_decode_node(struct acpi_namespace_node *node) |
{ |
acpi_os_printf("<Node> Name %4.4s", |
acpi_ut_get_node_name(node)); |
if (node->flags & ANOBJ_METHOD_ARG) { |
acpi_os_printf(" [Method Arg]"); |
} |
if (node->flags & ANOBJ_METHOD_LOCAL) { |
acpi_os_printf(" [Method Local]"); |
} |
switch (node->type) { |
/* These types have no attached object */ |
case ACPI_TYPE_DEVICE: |
acpi_os_printf(" Device"); |
break; |
case ACPI_TYPE_THERMAL: |
acpi_os_printf(" Thermal Zone"); |
break; |
default: |
acpi_db_decode_internal_object(acpi_ns_get_attached_object |
(node)); |
break; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_internal_object |
* |
* PARAMETERS: obj_desc - Object to be displayed |
* walk_state - Current walk state |
* |
* RETURN: None |
* |
* DESCRIPTION: Short display of an internal object |
* |
******************************************************************************/ |
void |
acpi_db_display_internal_object(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
u8 type; |
acpi_os_printf("%p ", obj_desc); |
if (!obj_desc) { |
acpi_os_printf("<Null Object>\n"); |
return; |
} |
/* Decode the object type */ |
switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
case ACPI_DESC_TYPE_PARSER: |
acpi_os_printf("<Parser> "); |
break; |
case ACPI_DESC_TYPE_NAMED: |
acpi_db_decode_node((struct acpi_namespace_node *)obj_desc); |
break; |
case ACPI_DESC_TYPE_OPERAND: |
type = obj_desc->common.type; |
if (type > ACPI_TYPE_LOCAL_MAX) { |
acpi_os_printf(" Type %X [Invalid Type]", (u32)type); |
return; |
} |
/* Decode the ACPI object type */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_LOCAL_REFERENCE: |
acpi_os_printf("[%s] ", |
acpi_ut_get_reference_name(obj_desc)); |
/* Decode the refererence */ |
switch (obj_desc->reference.class) { |
case ACPI_REFCLASS_LOCAL: |
acpi_os_printf("%X ", |
obj_desc->reference.value); |
if (walk_state) { |
obj_desc = walk_state->local_variables |
[obj_desc->reference.value].object; |
acpi_os_printf("%p", obj_desc); |
acpi_db_decode_internal_object |
(obj_desc); |
} |
break; |
case ACPI_REFCLASS_ARG: |
acpi_os_printf("%X ", |
obj_desc->reference.value); |
if (walk_state) { |
obj_desc = walk_state->arguments |
[obj_desc->reference.value].object; |
acpi_os_printf("%p", obj_desc); |
acpi_db_decode_internal_object |
(obj_desc); |
} |
break; |
case ACPI_REFCLASS_INDEX: |
switch (obj_desc->reference.target_type) { |
case ACPI_TYPE_BUFFER_FIELD: |
acpi_os_printf("%p", |
obj_desc->reference. |
object); |
acpi_db_decode_internal_object |
(obj_desc->reference.object); |
break; |
case ACPI_TYPE_PACKAGE: |
acpi_os_printf("%p", |
obj_desc->reference. |
where); |
if (!obj_desc->reference.where) { |
acpi_os_printf |
(" Uninitialized WHERE pointer"); |
} else { |
acpi_db_decode_internal_object(* |
(obj_desc-> |
reference. |
where)); |
} |
break; |
default: |
acpi_os_printf |
("Unknown index target type"); |
break; |
} |
break; |
case ACPI_REFCLASS_REFOF: |
if (!obj_desc->reference.object) { |
acpi_os_printf |
("Uninitialized reference subobject pointer"); |
break; |
} |
/* Reference can be to a Node or an Operand object */ |
switch (ACPI_GET_DESCRIPTOR_TYPE |
(obj_desc->reference.object)) { |
case ACPI_DESC_TYPE_NAMED: |
acpi_db_decode_node(obj_desc->reference. |
object); |
break; |
case ACPI_DESC_TYPE_OPERAND: |
acpi_db_decode_internal_object |
(obj_desc->reference.object); |
break; |
default: |
break; |
} |
break; |
case ACPI_REFCLASS_NAME: |
acpi_db_decode_node(obj_desc->reference.node); |
break; |
case ACPI_REFCLASS_DEBUG: |
case ACPI_REFCLASS_TABLE: |
acpi_os_printf("\n"); |
break; |
default: /* Unknown reference class */ |
acpi_os_printf("%2.2X\n", |
obj_desc->reference.class); |
break; |
} |
break; |
default: |
acpi_os_printf("<Obj> "); |
acpi_db_decode_internal_object(obj_desc); |
break; |
} |
break; |
default: |
acpi_os_printf("<Not a valid ACPI Object Descriptor> [%s]", |
acpi_ut_get_descriptor_name(obj_desc)); |
break; |
} |
acpi_os_printf("\n"); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_decode_locals |
* |
* PARAMETERS: walk_state - State for current method |
* |
* RETURN: None |
* |
* DESCRIPTION: Display all locals for the currently running control method |
* |
******************************************************************************/ |
void acpi_db_decode_locals(struct acpi_walk_state *walk_state) |
{ |
u32 i; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
u8 display_locals = FALSE; |
obj_desc = walk_state->method_desc; |
node = walk_state->method_node; |
if (!node) { |
acpi_os_printf |
("No method node (Executing subtree for buffer or opregion)\n"); |
return; |
} |
if (node->type != ACPI_TYPE_METHOD) { |
acpi_os_printf("Executing subtree for Buffer/Package/Region\n"); |
return; |
} |
/* Are any locals actually set? */ |
for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { |
obj_desc = walk_state->local_variables[i].object; |
if (obj_desc) { |
display_locals = TRUE; |
break; |
} |
} |
/* If any are set, only display the ones that are set */ |
if (display_locals) { |
acpi_os_printf |
("\nInitialized Local Variables for method [%4.4s]:\n", |
acpi_ut_get_node_name(node)); |
for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { |
obj_desc = walk_state->local_variables[i].object; |
if (obj_desc) { |
acpi_os_printf(" Local%X: ", i); |
acpi_db_display_internal_object(obj_desc, |
walk_state); |
} |
} |
} else { |
acpi_os_printf |
("No Local Variables are initialized for method [%4.4s]\n", |
acpi_ut_get_node_name(node)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_decode_arguments |
* |
* PARAMETERS: walk_state - State for current method |
* |
* RETURN: None |
* |
* DESCRIPTION: Display all arguments for the currently running control method |
* |
******************************************************************************/ |
void acpi_db_decode_arguments(struct acpi_walk_state *walk_state) |
{ |
u32 i; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
u8 display_args = FALSE; |
node = walk_state->method_node; |
obj_desc = walk_state->method_desc; |
if (!node) { |
acpi_os_printf |
("No method node (Executing subtree for buffer or opregion)\n"); |
return; |
} |
if (node->type != ACPI_TYPE_METHOD) { |
acpi_os_printf("Executing subtree for Buffer/Package/Region\n"); |
return; |
} |
/* Are any arguments actually set? */ |
for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { |
obj_desc = walk_state->arguments[i].object; |
if (obj_desc) { |
display_args = TRUE; |
break; |
} |
} |
/* If any are set, only display the ones that are set */ |
if (display_args) { |
acpi_os_printf("Initialized Arguments for Method [%4.4s]: " |
"(%X arguments defined for method invocation)\n", |
acpi_ut_get_node_name(node), |
obj_desc->method.param_count); |
for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { |
obj_desc = walk_state->arguments[i].object; |
if (obj_desc) { |
acpi_os_printf(" Arg%u: ", i); |
acpi_db_display_internal_object(obj_desc, |
walk_state); |
} |
} |
} else { |
acpi_os_printf |
("No Arguments are initialized for method [%4.4s]\n", |
acpi_ut_get_node_name(node)); |
} |
} |
/drivers/acpi/acpica/dbstats.c |
---|
0,0 → 1,546 |
/******************************************************************************* |
* |
* Module Name: dbstats - Generation and display of ACPI table statistics |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbstats") |
/* Local prototypes */ |
static void acpi_db_count_namespace_objects(void); |
static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc); |
static acpi_status |
acpi_db_classify_one_object(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE |
static void acpi_db_list_info(struct acpi_memory_list *list); |
#endif |
/* |
* Statistics subcommands |
*/ |
static struct acpi_db_argument_info acpi_db_stat_types[] = { |
{"ALLOCATIONS"}, |
{"OBJECTS"}, |
{"MEMORY"}, |
{"MISC"}, |
{"TABLES"}, |
{"SIZES"}, |
{"STACK"}, |
{NULL} /* Must be null terminated */ |
}; |
#define CMD_STAT_ALLOCATIONS 0 |
#define CMD_STAT_OBJECTS 1 |
#define CMD_STAT_MEMORY 2 |
#define CMD_STAT_MISC 3 |
#define CMD_STAT_TABLES 4 |
#define CMD_STAT_SIZES 5 |
#define CMD_STAT_STACK 6 |
#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_list_info |
* |
* PARAMETERS: list - Memory list/cache to be displayed |
* |
* RETURN: None |
* |
* DESCRIPTION: Display information about the input memory list or cache. |
* |
******************************************************************************/ |
static void acpi_db_list_info(struct acpi_memory_list *list) |
{ |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
u32 outstanding; |
#endif |
acpi_os_printf("\n%s\n", list->list_name); |
/* max_depth > 0 indicates a cache object */ |
if (list->max_depth > 0) { |
acpi_os_printf |
(" Cache: [Depth MaxD Avail Size] " |
"%8.2X %8.2X %8.2X %8.2X\n", list->current_depth, |
list->max_depth, list->max_depth - list->current_depth, |
(list->current_depth * list->object_size)); |
} |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
if (list->max_depth > 0) { |
acpi_os_printf |
(" Cache: [Requests Hits Misses ObjSize] " |
"%8.2X %8.2X %8.2X %8.2X\n", list->requests, list->hits, |
list->requests - list->hits, list->object_size); |
} |
outstanding = acpi_db_get_cache_info(list); |
if (list->object_size) { |
acpi_os_printf |
(" Mem: [Alloc Free Max CurSize Outstanding] " |
"%8.2X %8.2X %8.2X %8.2X %8.2X\n", list->total_allocated, |
list->total_freed, list->max_occupied, |
outstanding * list->object_size, outstanding); |
} else { |
acpi_os_printf |
(" Mem: [Alloc Free Max CurSize Outstanding Total] " |
"%8.2X %8.2X %8.2X %8.2X %8.2X %8.2X\n", |
list->total_allocated, list->total_freed, |
list->max_occupied, list->current_total_size, outstanding, |
list->total_size); |
} |
#endif |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_enumerate_object |
* |
* PARAMETERS: obj_desc - Object to be counted |
* |
* RETURN: None |
* |
* DESCRIPTION: Add this object to the global counts, by object type. |
* Limited recursion handles subobjects and packages, and this |
* is probably acceptable within the AML debugger only. |
* |
******************************************************************************/ |
static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc) |
{ |
u32 i; |
if (!obj_desc) { |
return; |
} |
/* Enumerate this object first */ |
acpi_gbl_num_objects++; |
if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) { |
acpi_gbl_obj_type_count_misc++; |
} else { |
acpi_gbl_obj_type_count[obj_desc->common.type]++; |
} |
/* Count the sub-objects */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_PACKAGE: |
for (i = 0; i < obj_desc->package.count; i++) { |
acpi_db_enumerate_object(obj_desc->package.elements[i]); |
} |
break; |
case ACPI_TYPE_DEVICE: |
acpi_db_enumerate_object(obj_desc->device.notify_list[0]); |
acpi_db_enumerate_object(obj_desc->device.notify_list[1]); |
acpi_db_enumerate_object(obj_desc->device.handler); |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
if (acpi_ns_get_secondary_object(obj_desc)) { |
acpi_gbl_obj_type_count[ACPI_TYPE_BUFFER_FIELD]++; |
} |
break; |
case ACPI_TYPE_REGION: |
acpi_gbl_obj_type_count[ACPI_TYPE_LOCAL_REGION_FIELD]++; |
acpi_db_enumerate_object(obj_desc->region.handler); |
break; |
case ACPI_TYPE_POWER: |
acpi_db_enumerate_object(obj_desc->power_resource. |
notify_list[0]); |
acpi_db_enumerate_object(obj_desc->power_resource. |
notify_list[1]); |
break; |
case ACPI_TYPE_PROCESSOR: |
acpi_db_enumerate_object(obj_desc->processor.notify_list[0]); |
acpi_db_enumerate_object(obj_desc->processor.notify_list[1]); |
acpi_db_enumerate_object(obj_desc->processor.handler); |
break; |
case ACPI_TYPE_THERMAL: |
acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[0]); |
acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[1]); |
acpi_db_enumerate_object(obj_desc->thermal_zone.handler); |
break; |
default: |
break; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_classify_one_object |
* |
* PARAMETERS: Callback for walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enumerate both the object descriptor (including subobjects) and |
* the parent namespace node. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_classify_one_object(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
struct acpi_namespace_node *node; |
union acpi_operand_object *obj_desc; |
u32 type; |
acpi_gbl_num_nodes++; |
node = (struct acpi_namespace_node *)obj_handle; |
obj_desc = acpi_ns_get_attached_object(node); |
acpi_db_enumerate_object(obj_desc); |
type = node->type; |
if (type > ACPI_TYPE_NS_NODE_MAX) { |
acpi_gbl_node_type_count_misc++; |
} else { |
acpi_gbl_node_type_count[type]++; |
} |
return (AE_OK); |
#ifdef ACPI_FUTURE_IMPLEMENTATION |
/* TBD: These need to be counted during the initial parsing phase */ |
if (acpi_ps_is_named_op(op->opcode)) { |
num_nodes++; |
} |
if (is_method) { |
num_method_elements++; |
} |
num_grammar_elements++; |
op = acpi_ps_get_depth_next(root, op); |
size_of_parse_tree = (num_grammar_elements - num_method_elements) * |
(u32)sizeof(union acpi_parse_object); |
size_of_method_trees = |
num_method_elements * (u32)sizeof(union acpi_parse_object); |
size_of_node_entries = |
num_nodes * (u32)sizeof(struct acpi_namespace_node); |
size_of_acpi_objects = |
num_nodes * (u32)sizeof(union acpi_operand_object); |
#endif |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_count_namespace_objects |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Count and classify the entire namespace, including all |
* namespace nodes and attached objects. |
* |
******************************************************************************/ |
static void acpi_db_count_namespace_objects(void) |
{ |
u32 i; |
acpi_gbl_num_nodes = 0; |
acpi_gbl_num_objects = 0; |
acpi_gbl_obj_type_count_misc = 0; |
for (i = 0; i < (ACPI_TYPE_NS_NODE_MAX - 1); i++) { |
acpi_gbl_obj_type_count[i] = 0; |
acpi_gbl_node_type_count[i] = 0; |
} |
(void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, FALSE, |
acpi_db_classify_one_object, NULL, NULL, |
NULL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_display_statistics |
* |
* PARAMETERS: type_arg - Subcommand |
* |
* RETURN: Status |
* |
* DESCRIPTION: Display various statistics |
* |
******************************************************************************/ |
acpi_status acpi_db_display_statistics(char *type_arg) |
{ |
u32 i; |
u32 temp; |
acpi_ut_strupr(type_arg); |
temp = acpi_db_match_argument(type_arg, acpi_db_stat_types); |
if (temp == ACPI_TYPE_NOT_FOUND) { |
acpi_os_printf("Invalid or unsupported argument\n"); |
return (AE_OK); |
} |
switch (temp) { |
case CMD_STAT_ALLOCATIONS: |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
acpi_ut_dump_allocation_info(); |
#endif |
break; |
case CMD_STAT_TABLES: |
acpi_os_printf("ACPI Table Information (not implemented):\n\n"); |
break; |
case CMD_STAT_OBJECTS: |
acpi_db_count_namespace_objects(); |
acpi_os_printf |
("\nObjects defined in the current namespace:\n\n"); |
acpi_os_printf("%16.16s %10.10s %10.10s\n", |
"ACPI_TYPE", "NODES", "OBJECTS"); |
for (i = 0; i < ACPI_TYPE_NS_NODE_MAX; i++) { |
acpi_os_printf("%16.16s % 10ld% 10ld\n", |
acpi_ut_get_type_name(i), |
acpi_gbl_node_type_count[i], |
acpi_gbl_obj_type_count[i]); |
} |
acpi_os_printf("%16.16s % 10ld% 10ld\n", "Misc/Unknown", |
acpi_gbl_node_type_count_misc, |
acpi_gbl_obj_type_count_misc); |
acpi_os_printf("%16.16s % 10ld% 10ld\n", "TOTALS:", |
acpi_gbl_num_nodes, acpi_gbl_num_objects); |
break; |
case CMD_STAT_MEMORY: |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
acpi_os_printf |
("\n----Object Statistics (all in hex)---------\n"); |
acpi_db_list_info(acpi_gbl_global_list); |
acpi_db_list_info(acpi_gbl_ns_node_list); |
#endif |
#ifdef ACPI_USE_LOCAL_CACHE |
acpi_os_printf |
("\n----Cache Statistics (all in hex)---------\n"); |
acpi_db_list_info(acpi_gbl_operand_cache); |
acpi_db_list_info(acpi_gbl_ps_node_cache); |
acpi_db_list_info(acpi_gbl_ps_node_ext_cache); |
acpi_db_list_info(acpi_gbl_state_cache); |
#endif |
break; |
case CMD_STAT_MISC: |
acpi_os_printf("\nMiscellaneous Statistics:\n\n"); |
acpi_os_printf("Calls to AcpiPsFind:.. ........% 7ld\n", |
acpi_gbl_ps_find_count); |
acpi_os_printf("Calls to AcpiNsLookup:..........% 7ld\n", |
acpi_gbl_ns_lookup_count); |
acpi_os_printf("\n"); |
acpi_os_printf("Mutex usage:\n\n"); |
for (i = 0; i < ACPI_NUM_MUTEX; i++) { |
acpi_os_printf("%-28s: % 7ld\n", |
acpi_ut_get_mutex_name(i), |
acpi_gbl_mutex_info[i].use_count); |
} |
break; |
case CMD_STAT_SIZES: |
acpi_os_printf("\nInternal object sizes:\n\n"); |
acpi_os_printf("Common %3d\n", |
sizeof(struct acpi_object_common)); |
acpi_os_printf("Number %3d\n", |
sizeof(struct acpi_object_integer)); |
acpi_os_printf("String %3d\n", |
sizeof(struct acpi_object_string)); |
acpi_os_printf("Buffer %3d\n", |
sizeof(struct acpi_object_buffer)); |
acpi_os_printf("Package %3d\n", |
sizeof(struct acpi_object_package)); |
acpi_os_printf("BufferField %3d\n", |
sizeof(struct acpi_object_buffer_field)); |
acpi_os_printf("Device %3d\n", |
sizeof(struct acpi_object_device)); |
acpi_os_printf("Event %3d\n", |
sizeof(struct acpi_object_event)); |
acpi_os_printf("Method %3d\n", |
sizeof(struct acpi_object_method)); |
acpi_os_printf("Mutex %3d\n", |
sizeof(struct acpi_object_mutex)); |
acpi_os_printf("Region %3d\n", |
sizeof(struct acpi_object_region)); |
acpi_os_printf("PowerResource %3d\n", |
sizeof(struct acpi_object_power_resource)); |
acpi_os_printf("Processor %3d\n", |
sizeof(struct acpi_object_processor)); |
acpi_os_printf("ThermalZone %3d\n", |
sizeof(struct acpi_object_thermal_zone)); |
acpi_os_printf("RegionField %3d\n", |
sizeof(struct acpi_object_region_field)); |
acpi_os_printf("BankField %3d\n", |
sizeof(struct acpi_object_bank_field)); |
acpi_os_printf("IndexField %3d\n", |
sizeof(struct acpi_object_index_field)); |
acpi_os_printf("Reference %3d\n", |
sizeof(struct acpi_object_reference)); |
acpi_os_printf("Notify %3d\n", |
sizeof(struct acpi_object_notify_handler)); |
acpi_os_printf("AddressSpace %3d\n", |
sizeof(struct acpi_object_addr_handler)); |
acpi_os_printf("Extra %3d\n", |
sizeof(struct acpi_object_extra)); |
acpi_os_printf("Data %3d\n", |
sizeof(struct acpi_object_data)); |
acpi_os_printf("\n"); |
acpi_os_printf("ParseObject %3d\n", |
sizeof(struct acpi_parse_obj_common)); |
acpi_os_printf("ParseObjectNamed %3d\n", |
sizeof(struct acpi_parse_obj_named)); |
acpi_os_printf("ParseObjectAsl %3d\n", |
sizeof(struct acpi_parse_obj_asl)); |
acpi_os_printf("OperandObject %3d\n", |
sizeof(union acpi_operand_object)); |
acpi_os_printf("NamespaceNode %3d\n", |
sizeof(struct acpi_namespace_node)); |
acpi_os_printf("AcpiObject %3d\n", |
sizeof(union acpi_object)); |
acpi_os_printf("\n"); |
acpi_os_printf("Generic State %3d\n", |
sizeof(union acpi_generic_state)); |
acpi_os_printf("Common State %3d\n", |
sizeof(struct acpi_common_state)); |
acpi_os_printf("Control State %3d\n", |
sizeof(struct acpi_control_state)); |
acpi_os_printf("Update State %3d\n", |
sizeof(struct acpi_update_state)); |
acpi_os_printf("Scope State %3d\n", |
sizeof(struct acpi_scope_state)); |
acpi_os_printf("Parse Scope %3d\n", |
sizeof(struct acpi_pscope_state)); |
acpi_os_printf("Package State %3d\n", |
sizeof(struct acpi_pkg_state)); |
acpi_os_printf("Thread State %3d\n", |
sizeof(struct acpi_thread_state)); |
acpi_os_printf("Result Values %3d\n", |
sizeof(struct acpi_result_values)); |
acpi_os_printf("Notify Info %3d\n", |
sizeof(struct acpi_notify_info)); |
break; |
case CMD_STAT_STACK: |
#if defined(ACPI_DEBUG_OUTPUT) |
temp = |
(u32)ACPI_PTR_DIFF(acpi_gbl_entry_stack_pointer, |
acpi_gbl_lowest_stack_pointer); |
acpi_os_printf("\nSubsystem Stack Usage:\n\n"); |
acpi_os_printf("Entry Stack Pointer %p\n", |
acpi_gbl_entry_stack_pointer); |
acpi_os_printf("Lowest Stack Pointer %p\n", |
acpi_gbl_lowest_stack_pointer); |
acpi_os_printf("Stack Use %X (%u)\n", temp, |
temp); |
acpi_os_printf("Deepest Procedure Nesting %u\n", |
acpi_gbl_deepest_nesting); |
#endif |
break; |
default: |
break; |
} |
acpi_os_printf("\n"); |
return (AE_OK); |
} |
/drivers/acpi/acpica/dbtest.c |
---|
0,0 → 1,1057 |
/******************************************************************************* |
* |
* Module Name: dbtest - Various debug-related tests |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#include "acnamesp.h" |
#include "acpredef.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbtest") |
/* Local prototypes */ |
static void acpi_db_test_all_objects(void); |
static acpi_status |
acpi_db_test_one_object(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value); |
static acpi_status |
acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length); |
static acpi_status |
acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length); |
static acpi_status |
acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length); |
static acpi_status |
acpi_db_read_from_object(struct acpi_namespace_node *node, |
acpi_object_type expected_type, |
union acpi_object **value); |
static acpi_status |
acpi_db_write_to_object(struct acpi_namespace_node *node, |
union acpi_object *value); |
static void acpi_db_evaluate_all_predefined_names(char *count_arg); |
static acpi_status |
acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value); |
/* |
* Test subcommands |
*/ |
static struct acpi_db_argument_info acpi_db_test_types[] = { |
{"OBJECTS"}, |
{"PREDEFINED"}, |
{NULL} /* Must be null terminated */ |
}; |
#define CMD_TEST_OBJECTS 0 |
#define CMD_TEST_PREDEFINED 1 |
#define BUFFER_FILL_VALUE 0xFF |
/* |
* Support for the special debugger read/write control methods. |
* These methods are installed into the current namespace and are |
* used to read and write the various namespace objects. The point |
* is to force the AML interpreter do all of the work. |
*/ |
#define ACPI_DB_READ_METHOD "\\_T98" |
#define ACPI_DB_WRITE_METHOD "\\_T99" |
static acpi_handle read_handle = NULL; |
static acpi_handle write_handle = NULL; |
/* ASL Definitions of the debugger read/write control methods */ |
#if 0 |
definition_block("ssdt.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001) |
{ |
method(_T98, 1, not_serialized) { /* Read */ |
return (de_ref_of(arg0)) |
} |
} |
definition_block("ssdt2.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001) |
{ |
method(_T99, 2, not_serialized) { /* Write */ |
store(arg1, arg0) |
} |
} |
#endif |
static unsigned char read_method_code[] = { |
0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00, /* 00000000 "SSDT...." */ |
0x02, 0xC9, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00, /* 00000008 "..Intel." */ |
0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00, /* 00000010 "DEBUG..." */ |
0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C, /* 00000018 "....INTL" */ |
0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54, /* 00000020 "... .._T" */ |
0x39, 0x38, 0x01, 0xA4, 0x83, 0x68 /* 00000028 "98...h" */ |
}; |
static unsigned char write_method_code[] = { |
0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00, /* 00000000 "SSDT...." */ |
0x02, 0x15, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00, /* 00000008 "..Intel." */ |
0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00, /* 00000010 "DEBUG..." */ |
0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C, /* 00000018 "....INTL" */ |
0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54, /* 00000020 "... .._T" */ |
0x39, 0x39, 0x02, 0x70, 0x69, 0x68 /* 00000028 "99.pih" */ |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_execute_test |
* |
* PARAMETERS: type_arg - Subcommand |
* |
* RETURN: None |
* |
* DESCRIPTION: Execute various debug tests. |
* |
* Note: Code is prepared for future expansion of the TEST command. |
* |
******************************************************************************/ |
void acpi_db_execute_test(char *type_arg) |
{ |
u32 temp; |
acpi_ut_strupr(type_arg); |
temp = acpi_db_match_argument(type_arg, acpi_db_test_types); |
if (temp == ACPI_TYPE_NOT_FOUND) { |
acpi_os_printf("Invalid or unsupported argument\n"); |
return; |
} |
switch (temp) { |
case CMD_TEST_OBJECTS: |
acpi_db_test_all_objects(); |
break; |
case CMD_TEST_PREDEFINED: |
acpi_db_evaluate_all_predefined_names(NULL); |
break; |
default: |
break; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_test_all_objects |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: This test implements the OBJECTS subcommand. It exercises the |
* namespace by reading/writing/comparing all data objects such |
* as integers, strings, buffers, fields, buffer fields, etc. |
* |
******************************************************************************/ |
static void acpi_db_test_all_objects(void) |
{ |
acpi_status status; |
/* Install the debugger read-object control method if necessary */ |
if (!read_handle) { |
status = acpi_install_method(read_method_code); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("%s, Could not install debugger read method\n", |
acpi_format_exception(status)); |
return; |
} |
status = |
acpi_get_handle(NULL, ACPI_DB_READ_METHOD, &read_handle); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("Could not obtain handle for debug method %s\n", |
ACPI_DB_READ_METHOD); |
return; |
} |
} |
/* Install the debugger write-object control method if necessary */ |
if (!write_handle) { |
status = acpi_install_method(write_method_code); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("%s, Could not install debugger write method\n", |
acpi_format_exception(status)); |
return; |
} |
status = |
acpi_get_handle(NULL, ACPI_DB_WRITE_METHOD, &write_handle); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf |
("Could not obtain handle for debug method %s\n", |
ACPI_DB_WRITE_METHOD); |
return; |
} |
} |
/* Walk the entire namespace, testing each supported named data object */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, acpi_db_test_one_object, |
NULL, NULL, NULL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_test_one_object |
* |
* PARAMETERS: acpi_walk_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Test one namespace object. Supported types are Integer, |
* String, Buffer, buffer_field, and field_unit. All other object |
* types are simply ignored. |
* |
* Note: Support for Packages is not implemented. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_test_one_object(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value) |
{ |
struct acpi_namespace_node *node; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *region_obj; |
acpi_object_type local_type; |
u32 bit_length = 0; |
u32 byte_length = 0; |
acpi_status status = AE_OK; |
node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
obj_desc = node->object; |
/* |
* For the supported types, get the actual bit length or |
* byte length. Map the type to one of Integer/String/Buffer. |
*/ |
switch (node->type) { |
case ACPI_TYPE_INTEGER: |
/* Integer width is either 32 or 64 */ |
local_type = ACPI_TYPE_INTEGER; |
bit_length = acpi_gbl_integer_bit_width; |
break; |
case ACPI_TYPE_STRING: |
local_type = ACPI_TYPE_STRING; |
byte_length = obj_desc->string.length; |
break; |
case ACPI_TYPE_BUFFER: |
local_type = ACPI_TYPE_BUFFER; |
byte_length = obj_desc->buffer.length; |
bit_length = byte_length * 8; |
break; |
case ACPI_TYPE_FIELD_UNIT: |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
local_type = ACPI_TYPE_INTEGER; |
if (obj_desc) { |
/* |
* Returned object will be a Buffer if the field length |
* is larger than the size of an Integer (32 or 64 bits |
* depending on the DSDT version). |
*/ |
bit_length = obj_desc->common_field.bit_length; |
byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length); |
if (bit_length > acpi_gbl_integer_bit_width) { |
local_type = ACPI_TYPE_BUFFER; |
} |
} |
break; |
default: |
/* Ignore all other types */ |
return (AE_OK); |
} |
/* Emit the common prefix: Type:Name */ |
acpi_os_printf("%14s: %4.4s", |
acpi_ut_get_type_name(node->type), node->name.ascii); |
if (!obj_desc) { |
acpi_os_printf(" Ignoring, no attached object\n"); |
return (AE_OK); |
} |
/* |
* Check for unsupported region types. Note: acpi_exec simulates |
* access to system_memory, system_IO, PCI_Config, and EC. |
*/ |
switch (node->type) { |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
region_obj = obj_desc->field.region_obj; |
switch (region_obj->region.space_id) { |
case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
case ACPI_ADR_SPACE_SYSTEM_IO: |
case ACPI_ADR_SPACE_PCI_CONFIG: |
case ACPI_ADR_SPACE_EC: |
break; |
default: |
acpi_os_printf |
(" %s space is not supported [%4.4s]\n", |
acpi_ut_get_region_name(region_obj->region. |
space_id), |
region_obj->region.node->name.ascii); |
return (AE_OK); |
} |
break; |
default: |
break; |
} |
/* At this point, we have resolved the object to one of the major types */ |
switch (local_type) { |
case ACPI_TYPE_INTEGER: |
status = acpi_db_test_integer_type(node, bit_length); |
break; |
case ACPI_TYPE_STRING: |
status = acpi_db_test_string_type(node, byte_length); |
break; |
case ACPI_TYPE_BUFFER: |
status = acpi_db_test_buffer_type(node, bit_length); |
break; |
default: |
acpi_os_printf(" Ignoring, type not implemented (%2.2X)", |
local_type); |
break; |
} |
switch (node->type) { |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
region_obj = obj_desc->field.region_obj; |
acpi_os_printf(" (%s)", |
acpi_ut_get_region_name(region_obj->region. |
space_id)); |
break; |
default: |
break; |
} |
acpi_os_printf("\n"); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_test_integer_type |
* |
* PARAMETERS: node - Parent NS node for the object |
* bit_length - Actual length of the object. Used for |
* support of arbitrary length field_unit |
* and buffer_field objects. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Test read/write for an Integer-valued object. Performs a |
* write/read/compare of an arbitrary new value, then performs |
* a write/read/compare of the original value. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length) |
{ |
union acpi_object *temp1 = NULL; |
union acpi_object *temp2 = NULL; |
union acpi_object *temp3 = NULL; |
union acpi_object write_value; |
u64 value_to_write; |
acpi_status status; |
if (bit_length > 64) { |
acpi_os_printf(" Invalid length for an Integer: %u", |
bit_length); |
return (AE_OK); |
} |
/* Read the original value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp1); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
acpi_os_printf(" (%4.4X/%3.3X) %8.8X%8.8X", |
bit_length, ACPI_ROUND_BITS_UP_TO_BYTES(bit_length), |
ACPI_FORMAT_UINT64(temp1->integer.value)); |
value_to_write = ACPI_UINT64_MAX >> (64 - bit_length); |
if (temp1->integer.value == value_to_write) { |
value_to_write = 0; |
} |
/* Write a new value */ |
write_value.type = ACPI_TYPE_INTEGER; |
write_value.integer.value = value_to_write; |
status = acpi_db_write_to_object(node, &write_value); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Ensure that we can read back the new value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp2); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (temp2->integer.value != value_to_write) { |
acpi_os_printf(" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X", |
ACPI_FORMAT_UINT64(temp2->integer.value), |
ACPI_FORMAT_UINT64(value_to_write)); |
} |
/* Write back the original value */ |
write_value.integer.value = temp1->integer.value; |
status = acpi_db_write_to_object(node, &write_value); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Ensure that we can read back the original value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp3); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (temp3->integer.value != temp1->integer.value) { |
acpi_os_printf(" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X", |
ACPI_FORMAT_UINT64(temp3->integer.value), |
ACPI_FORMAT_UINT64(temp1->integer.value)); |
} |
exit: |
if (temp1) { |
acpi_os_free(temp1); |
} |
if (temp2) { |
acpi_os_free(temp2); |
} |
if (temp3) { |
acpi_os_free(temp3); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_test_buffer_type |
* |
* PARAMETERS: node - Parent NS node for the object |
* bit_length - Actual length of the object. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Test read/write for an Buffer-valued object. Performs a |
* write/read/compare of an arbitrary new value, then performs |
* a write/read/compare of the original value. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length) |
{ |
union acpi_object *temp1 = NULL; |
union acpi_object *temp2 = NULL; |
union acpi_object *temp3 = NULL; |
u8 *buffer; |
union acpi_object write_value; |
acpi_status status; |
u32 byte_length; |
u32 i; |
u8 extra_bits; |
byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length); |
if (byte_length == 0) { |
acpi_os_printf(" Ignoring zero length buffer"); |
return (AE_OK); |
} |
/* Allocate a local buffer */ |
buffer = ACPI_ALLOCATE_ZEROED(byte_length); |
if (!buffer) { |
return (AE_NO_MEMORY); |
} |
/* Read the original value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp1); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Emit a few bytes of the buffer */ |
acpi_os_printf(" (%4.4X/%3.3X)", bit_length, temp1->buffer.length); |
for (i = 0; ((i < 4) && (i < byte_length)); i++) { |
acpi_os_printf(" %2.2X", temp1->buffer.pointer[i]); |
} |
acpi_os_printf("... "); |
/* |
* Write a new value. |
* |
* Handle possible extra bits at the end of the buffer. Can |
* happen for field_units larger than an integer, but the bit |
* count is not an integral number of bytes. Zero out the |
* unused bits. |
*/ |
memset(buffer, BUFFER_FILL_VALUE, byte_length); |
extra_bits = bit_length % 8; |
if (extra_bits) { |
buffer[byte_length - 1] = ACPI_MASK_BITS_ABOVE(extra_bits); |
} |
write_value.type = ACPI_TYPE_BUFFER; |
write_value.buffer.length = byte_length; |
write_value.buffer.pointer = buffer; |
status = acpi_db_write_to_object(node, &write_value); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Ensure that we can read back the new value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp2); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (memcmp(temp2->buffer.pointer, buffer, byte_length)) { |
acpi_os_printf(" MISMATCH 2: New buffer value"); |
} |
/* Write back the original value */ |
write_value.buffer.length = byte_length; |
write_value.buffer.pointer = temp1->buffer.pointer; |
status = acpi_db_write_to_object(node, &write_value); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Ensure that we can read back the original value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp3); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (memcmp(temp1->buffer.pointer, temp3->buffer.pointer, byte_length)) { |
acpi_os_printf(" MISMATCH 3: While restoring original buffer"); |
} |
exit: |
ACPI_FREE(buffer); |
if (temp1) { |
acpi_os_free(temp1); |
} |
if (temp2) { |
acpi_os_free(temp2); |
} |
if (temp3) { |
acpi_os_free(temp3); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_test_string_type |
* |
* PARAMETERS: node - Parent NS node for the object |
* byte_length - Actual length of the object. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Test read/write for an String-valued object. Performs a |
* write/read/compare of an arbitrary new value, then performs |
* a write/read/compare of the original value. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length) |
{ |
union acpi_object *temp1 = NULL; |
union acpi_object *temp2 = NULL; |
union acpi_object *temp3 = NULL; |
char *value_to_write = "Test String from AML Debugger"; |
union acpi_object write_value; |
acpi_status status; |
/* Read the original value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp1); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
acpi_os_printf(" (%4.4X/%3.3X) \"%s\"", (temp1->string.length * 8), |
temp1->string.length, temp1->string.pointer); |
/* Write a new value */ |
write_value.type = ACPI_TYPE_STRING; |
write_value.string.length = strlen(value_to_write); |
write_value.string.pointer = value_to_write; |
status = acpi_db_write_to_object(node, &write_value); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Ensure that we can read back the new value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp2); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (strcmp(temp2->string.pointer, value_to_write)) { |
acpi_os_printf(" MISMATCH 2: %s, expecting %s", |
temp2->string.pointer, value_to_write); |
} |
/* Write back the original value */ |
write_value.string.length = strlen(temp1->string.pointer); |
write_value.string.pointer = temp1->string.pointer; |
status = acpi_db_write_to_object(node, &write_value); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Ensure that we can read back the original value */ |
status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp3); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (strcmp(temp1->string.pointer, temp3->string.pointer)) { |
acpi_os_printf(" MISMATCH 3: %s, expecting %s", |
temp3->string.pointer, temp1->string.pointer); |
} |
exit: |
if (temp1) { |
acpi_os_free(temp1); |
} |
if (temp2) { |
acpi_os_free(temp2); |
} |
if (temp3) { |
acpi_os_free(temp3); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_read_from_object |
* |
* PARAMETERS: node - Parent NS node for the object |
* expected_type - Object type expected from the read |
* value - Where the value read is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Performs a read from the specified object by invoking the |
* special debugger control method that reads the object. Thus, |
* the AML interpreter is doing all of the work, increasing the |
* validity of the test. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_read_from_object(struct acpi_namespace_node *node, |
acpi_object_type expected_type, |
union acpi_object **value) |
{ |
union acpi_object *ret_value; |
struct acpi_object_list param_objects; |
union acpi_object params[2]; |
struct acpi_buffer return_obj; |
acpi_status status; |
params[0].type = ACPI_TYPE_LOCAL_REFERENCE; |
params[0].reference.actual_type = node->type; |
params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node); |
param_objects.count = 1; |
param_objects.pointer = params; |
return_obj.length = ACPI_ALLOCATE_BUFFER; |
acpi_gbl_method_executing = TRUE; |
status = acpi_evaluate_object(read_handle, NULL, |
¶m_objects, &return_obj); |
acpi_gbl_method_executing = FALSE; |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not read from object, %s", |
acpi_format_exception(status)); |
return (status); |
} |
ret_value = (union acpi_object *)return_obj.pointer; |
switch (ret_value->type) { |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_STRING: |
/* |
* Did we receive the type we wanted? Most important for the |
* Integer/Buffer case (when a field is larger than an Integer, |
* it should return a Buffer). |
*/ |
if (ret_value->type != expected_type) { |
acpi_os_printf |
(" Type mismatch: Expected %s, Received %s", |
acpi_ut_get_type_name(expected_type), |
acpi_ut_get_type_name(ret_value->type)); |
return (AE_TYPE); |
} |
*value = ret_value; |
break; |
default: |
acpi_os_printf(" Unsupported return object type, %s", |
acpi_ut_get_type_name(ret_value->type)); |
acpi_os_free(return_obj.pointer); |
return (AE_TYPE); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_write_to_object |
* |
* PARAMETERS: node - Parent NS node for the object |
* value - Value to be written |
* |
* RETURN: Status |
* |
* DESCRIPTION: Performs a write to the specified object by invoking the |
* special debugger control method that writes the object. Thus, |
* the AML interpreter is doing all of the work, increasing the |
* validity of the test. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_write_to_object(struct acpi_namespace_node *node, |
union acpi_object *value) |
{ |
struct acpi_object_list param_objects; |
union acpi_object params[2]; |
acpi_status status; |
params[0].type = ACPI_TYPE_LOCAL_REFERENCE; |
params[0].reference.actual_type = node->type; |
params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node); |
/* Copy the incoming user parameter */ |
memcpy(¶ms[1], value, sizeof(union acpi_object)); |
param_objects.count = 2; |
param_objects.pointer = params; |
acpi_gbl_method_executing = TRUE; |
status = acpi_evaluate_object(write_handle, NULL, ¶m_objects, NULL); |
acpi_gbl_method_executing = FALSE; |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not write to object, %s", |
acpi_format_exception(status)); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_evaluate_all_predefined_names |
* |
* PARAMETERS: count_arg - Max number of methods to execute |
* |
* RETURN: None |
* |
* DESCRIPTION: Namespace batch execution. Execute predefined names in the |
* namespace, up to the max count, if specified. |
* |
******************************************************************************/ |
static void acpi_db_evaluate_all_predefined_names(char *count_arg) |
{ |
struct acpi_db_execute_walk info; |
info.count = 0; |
info.max_count = ACPI_UINT32_MAX; |
if (count_arg) { |
info.max_count = strtoul(count_arg, NULL, 0); |
} |
/* Search all nodes in namespace */ |
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, |
acpi_db_evaluate_one_predefined_name, NULL, |
(void *)&info, NULL); |
acpi_os_printf("Evaluated %u predefined names in the namespace\n", |
info.count); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_evaluate_one_predefined_name |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Batch execution module. Currently only executes predefined |
* ACPI names. |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
struct acpi_db_execute_walk *info = |
(struct acpi_db_execute_walk *)context; |
char *pathname; |
const union acpi_predefined_info *predefined; |
struct acpi_device_info *obj_info; |
struct acpi_object_list param_objects; |
union acpi_object params[ACPI_METHOD_NUM_ARGS]; |
union acpi_object *this_param; |
struct acpi_buffer return_obj; |
acpi_status status; |
u16 arg_type_list; |
u8 arg_count; |
u8 arg_type; |
u32 i; |
/* The name must be a predefined ACPI name */ |
predefined = acpi_ut_match_predefined_method(node->name.ascii); |
if (!predefined) { |
return (AE_OK); |
} |
if (node->type == ACPI_TYPE_LOCAL_SCOPE) { |
return (AE_OK); |
} |
pathname = acpi_ns_get_external_pathname(node); |
if (!pathname) { |
return (AE_OK); |
} |
/* Get the object info for number of method parameters */ |
status = acpi_get_object_info(obj_handle, &obj_info); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(pathname); |
return (status); |
} |
param_objects.count = 0; |
param_objects.pointer = NULL; |
if (obj_info->type == ACPI_TYPE_METHOD) { |
/* Setup default parameters (with proper types) */ |
arg_type_list = predefined->info.argument_list; |
arg_count = METHOD_GET_ARG_COUNT(arg_type_list); |
/* |
* Setup the ACPI-required number of arguments, regardless of what |
* the actual method defines. If there is a difference, then the |
* method is wrong and a warning will be issued during execution. |
*/ |
this_param = params; |
for (i = 0; i < arg_count; i++) { |
arg_type = METHOD_GET_NEXT_TYPE(arg_type_list); |
this_param->type = arg_type; |
switch (arg_type) { |
case ACPI_TYPE_INTEGER: |
this_param->integer.value = 1; |
break; |
case ACPI_TYPE_STRING: |
this_param->string.pointer = |
"This is the default argument string"; |
this_param->string.length = |
strlen(this_param->string.pointer); |
break; |
case ACPI_TYPE_BUFFER: |
this_param->buffer.pointer = (u8 *)params; /* just a garbage buffer */ |
this_param->buffer.length = 48; |
break; |
case ACPI_TYPE_PACKAGE: |
this_param->package.elements = NULL; |
this_param->package.count = 0; |
break; |
default: |
acpi_os_printf |
("%s: Unsupported argument type: %u\n", |
pathname, arg_type); |
break; |
} |
this_param++; |
} |
param_objects.count = arg_count; |
param_objects.pointer = params; |
} |
ACPI_FREE(obj_info); |
return_obj.pointer = NULL; |
return_obj.length = ACPI_ALLOCATE_BUFFER; |
/* Do the actual method execution */ |
acpi_gbl_method_executing = TRUE; |
status = acpi_evaluate_object(node, NULL, ¶m_objects, &return_obj); |
acpi_os_printf("%-32s returned %s\n", |
pathname, acpi_format_exception(status)); |
acpi_gbl_method_executing = FALSE; |
ACPI_FREE(pathname); |
/* Ignore status from method execution */ |
status = AE_OK; |
/* Update count, check if we have executed enough methods */ |
info->count++; |
if (info->count >= info->max_count) { |
status = AE_CTRL_TERMINATE; |
} |
return (status); |
} |
/drivers/acpi/acpica/dbutils.c |
---|
0,0 → 1,457 |
/******************************************************************************* |
* |
* Module Name: dbutils - AML debugger utilities |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbutils") |
/* Local prototypes */ |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root); |
void acpi_db_dump_buffer(u32 address); |
#endif |
static char *gbl_hex_to_ascii = "0123456789ABCDEF"; |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_match_argument |
* |
* PARAMETERS: user_argument - User command line |
* arguments - Array of commands to match against |
* |
* RETURN: Index into command array or ACPI_TYPE_NOT_FOUND if not found |
* |
* DESCRIPTION: Search command array for a command match |
* |
******************************************************************************/ |
acpi_object_type |
acpi_db_match_argument(char *user_argument, |
struct acpi_db_argument_info *arguments) |
{ |
u32 i; |
if (!user_argument || user_argument[0] == 0) { |
return (ACPI_TYPE_NOT_FOUND); |
} |
for (i = 0; arguments[i].name; i++) { |
if (strstr(arguments[i].name, user_argument) == |
arguments[i].name) { |
return (i); |
} |
} |
/* Argument not recognized */ |
return (ACPI_TYPE_NOT_FOUND); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_set_output_destination |
* |
* PARAMETERS: output_flags - Current flags word |
* |
* RETURN: None |
* |
* DESCRIPTION: Set the current destination for debugger output. Also sets |
* the debug output level accordingly. |
* |
******************************************************************************/ |
void acpi_db_set_output_destination(u32 output_flags) |
{ |
acpi_gbl_db_output_flags = (u8)output_flags; |
if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) && |
acpi_gbl_db_output_to_file) { |
acpi_dbg_level = acpi_gbl_db_debug_level; |
} else { |
acpi_dbg_level = acpi_gbl_db_console_debug_level; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_external_object |
* |
* PARAMETERS: obj_desc - External ACPI object to dump |
* level - Nesting level. |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump the contents of an ACPI external object |
* |
******************************************************************************/ |
void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level) |
{ |
u32 i; |
if (!obj_desc) { |
acpi_os_printf("[Null Object]\n"); |
return; |
} |
for (i = 0; i < level; i++) { |
acpi_os_printf(" "); |
} |
switch (obj_desc->type) { |
case ACPI_TYPE_ANY: |
acpi_os_printf("[Null Object] (Type=0)\n"); |
break; |
case ACPI_TYPE_INTEGER: |
acpi_os_printf("[Integer] = %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(obj_desc->integer.value)); |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf("[String] Length %.2X = ", |
obj_desc->string.length); |
acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX); |
acpi_os_printf("\n"); |
break; |
case ACPI_TYPE_BUFFER: |
acpi_os_printf("[Buffer] Length %.2X = ", |
obj_desc->buffer.length); |
if (obj_desc->buffer.length) { |
if (obj_desc->buffer.length > 16) { |
acpi_os_printf("\n"); |
} |
acpi_ut_debug_dump_buffer(ACPI_CAST_PTR |
(u8, |
obj_desc->buffer.pointer), |
obj_desc->buffer.length, |
DB_BYTE_DISPLAY, _COMPONENT); |
} else { |
acpi_os_printf("\n"); |
} |
break; |
case ACPI_TYPE_PACKAGE: |
acpi_os_printf("[Package] Contains %u Elements:\n", |
obj_desc->package.count); |
for (i = 0; i < obj_desc->package.count; i++) { |
acpi_db_dump_external_object(&obj_desc->package. |
elements[i], level + 1); |
} |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
acpi_os_printf("[Object Reference] = "); |
acpi_db_display_internal_object(obj_desc->reference.handle, |
NULL); |
break; |
case ACPI_TYPE_PROCESSOR: |
acpi_os_printf("[Processor]\n"); |
break; |
case ACPI_TYPE_POWER: |
acpi_os_printf("[Power Resource]\n"); |
break; |
default: |
acpi_os_printf("[Unknown Type] %X\n", obj_desc->type); |
break; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_prep_namestring |
* |
* PARAMETERS: name - String to prepare |
* |
* RETURN: None |
* |
* DESCRIPTION: Translate all forward slashes and dots to backslashes. |
* |
******************************************************************************/ |
void acpi_db_prep_namestring(char *name) |
{ |
if (!name) { |
return; |
} |
acpi_ut_strupr(name); |
/* Convert a leading forward slash to a backslash */ |
if (*name == '/') { |
*name = '\\'; |
} |
/* Ignore a leading backslash, this is the root prefix */ |
if (ACPI_IS_ROOT_PREFIX(*name)) { |
name++; |
} |
/* Convert all slash path separators to dots */ |
while (*name) { |
if ((*name == '/') || (*name == '\\')) { |
*name = '.'; |
} |
name++; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_local_ns_lookup |
* |
* PARAMETERS: name - Name to lookup |
* |
* RETURN: Pointer to a namespace node, null on failure |
* |
* DESCRIPTION: Lookup a name in the ACPI namespace |
* |
* Note: Currently begins search from the root. Could be enhanced to use |
* the current prefix (scope) node as the search beginning point. |
* |
******************************************************************************/ |
struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name) |
{ |
char *internal_path; |
acpi_status status; |
struct acpi_namespace_node *node = NULL; |
acpi_db_prep_namestring(name); |
/* Build an internal namestring */ |
status = acpi_ns_internalize_name(name, &internal_path); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Invalid namestring: %s\n", name); |
return (NULL); |
} |
/* |
* Lookup the name. |
* (Uses root node as the search starting point) |
*/ |
status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY, |
ACPI_IMODE_EXECUTE, |
ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, |
NULL, &node); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not locate name: %s, %s\n", |
name, acpi_format_exception(status)); |
} |
ACPI_FREE(internal_path); |
return (node); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_uint32_to_hex_string |
* |
* PARAMETERS: value - The value to be converted to string |
* buffer - Buffer for result (not less than 11 bytes) |
* |
* RETURN: None |
* |
* DESCRIPTION: Convert the unsigned 32-bit value to the hexadecimal image |
* |
* NOTE: It is the caller's responsibility to ensure that the length of buffer |
* is sufficient. |
* |
******************************************************************************/ |
void acpi_db_uint32_to_hex_string(u32 value, char *buffer) |
{ |
int i; |
if (value == 0) { |
strcpy(buffer, "0"); |
return; |
} |
buffer[8] = '\0'; |
for (i = 7; i >= 0; i--) { |
buffer[i] = gbl_hex_to_ascii[value & 0x0F]; |
value = value >> 4; |
} |
} |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_second_pass_parse |
* |
* PARAMETERS: root - Root of the parse tree |
* |
* RETURN: Status |
* |
* DESCRIPTION: Second pass parse of the ACPI tables. We need to wait until |
* second pass to parse the control methods |
* |
******************************************************************************/ |
acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root) |
{ |
union acpi_parse_object *op = root; |
union acpi_parse_object *method; |
union acpi_parse_object *search_op; |
union acpi_parse_object *start_op; |
acpi_status status = AE_OK; |
u32 base_aml_offset; |
struct acpi_walk_state *walk_state; |
ACPI_FUNCTION_ENTRY(); |
acpi_os_printf("Pass two parse ....\n"); |
while (op) { |
if (op->common.aml_opcode == AML_METHOD_OP) { |
method = op; |
/* Create a new walk state for the parse */ |
walk_state = |
acpi_ds_create_walk_state(0, NULL, NULL, NULL); |
if (!walk_state) { |
return (AE_NO_MEMORY); |
} |
/* Init the Walk State */ |
walk_state->parser_state.aml = |
walk_state->parser_state.aml_start = |
method->named.data; |
walk_state->parser_state.aml_end = |
walk_state->parser_state.pkg_end = |
method->named.data + method->named.length; |
walk_state->parser_state.start_scope = op; |
walk_state->descending_callback = |
acpi_ds_load1_begin_op; |
walk_state->ascending_callback = acpi_ds_load1_end_op; |
/* Perform the AML parse */ |
status = acpi_ps_parse_aml(walk_state); |
base_aml_offset = |
(method->common.value.arg)->common.aml_offset + 1; |
start_op = (method->common.value.arg)->common.next; |
search_op = start_op; |
while (search_op) { |
search_op->common.aml_offset += base_aml_offset; |
search_op = |
acpi_ps_get_depth_next(start_op, search_op); |
} |
} |
if (op->common.aml_opcode == AML_REGION_OP) { |
/* TBD: [Investigate] this isn't quite the right thing to do! */ |
/* |
* |
* Method = (ACPI_DEFERRED_OP *) Op; |
* Status = acpi_ps_parse_aml (Op, Method->Body, Method->body_length); |
*/ |
} |
if (ACPI_FAILURE(status)) { |
break; |
} |
op = acpi_ps_get_depth_next(root, op); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_dump_buffer |
* |
* PARAMETERS: address - Pointer to the buffer |
* |
* RETURN: None |
* |
* DESCRIPTION: Print a portion of a buffer |
* |
******************************************************************************/ |
void acpi_db_dump_buffer(u32 address) |
{ |
acpi_os_printf("\nLocation %X:\n", address); |
acpi_dbg_level |= ACPI_LV_TABLES; |
acpi_ut_debug_dump_buffer(ACPI_TO_POINTER(address), 64, DB_BYTE_DISPLAY, |
ACPI_UINT32_MAX); |
} |
#endif |
/drivers/acpi/acpica/dbxface.c |
---|
0,0 → 1,513 |
/******************************************************************************* |
* |
* Module Name: dbxface - AML Debugger external interfaces |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("dbxface") |
/* Local prototypes */ |
static acpi_status |
acpi_db_start_command(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op); |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
void acpi_db_method_end(struct acpi_walk_state *walk_state); |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_start_command |
* |
* PARAMETERS: walk_state - Current walk |
* op - Current executing Op, from AML interpreter |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enter debugger command loop |
* |
******************************************************************************/ |
static acpi_status |
acpi_db_start_command(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
acpi_status status; |
/* TBD: [Investigate] are there namespace locking issues here? */ |
/* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */ |
/* Go into the command loop and await next user command */ |
acpi_gbl_method_executing = TRUE; |
status = AE_CTRL_TRUE; |
while (status == AE_CTRL_TRUE) { |
if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) { |
/* Handshake with the front-end that gets user command lines */ |
acpi_os_release_mutex(acpi_gbl_db_command_complete); |
status = |
acpi_os_acquire_mutex(acpi_gbl_db_command_ready, |
ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} else { |
/* Single threaded, we must get a command line ourselves */ |
/* Force output to console until a command is entered */ |
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
/* Different prompt if method is executing */ |
if (!acpi_gbl_method_executing) { |
acpi_os_printf("%1c ", |
ACPI_DEBUGGER_COMMAND_PROMPT); |
} else { |
acpi_os_printf("%1c ", |
ACPI_DEBUGGER_EXECUTE_PROMPT); |
} |
/* Get the user input line */ |
status = acpi_os_get_line(acpi_gbl_db_line_buf, |
ACPI_DB_LINE_BUFFER_SIZE, |
NULL); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"While parsing command line")); |
return (status); |
} |
} |
status = |
acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state, |
op); |
} |
/* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */ |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_db_single_step |
* |
* PARAMETERS: walk_state - Current walk |
* op - Current executing op (from aml interpreter) |
* opcode_class - Class of the current AML Opcode |
* |
* RETURN: Status |
* |
* DESCRIPTION: Called just before execution of an AML opcode. |
* |
******************************************************************************/ |
acpi_status |
acpi_db_single_step(struct acpi_walk_state * walk_state, |
union acpi_parse_object * op, u32 opcode_class) |
{ |
union acpi_parse_object *next; |
acpi_status status = AE_OK; |
u32 original_debug_level; |
union acpi_parse_object *display_op; |
union acpi_parse_object *parent_op; |
u32 aml_offset; |
ACPI_FUNCTION_ENTRY(); |
#ifndef ACPI_APPLICATION |
if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { |
return (AE_OK); |
} |
#endif |
/* Check the abort flag */ |
if (acpi_gbl_abort_method) { |
acpi_gbl_abort_method = FALSE; |
return (AE_ABORT_METHOD); |
} |
aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml, |
walk_state->parser_state.aml_start); |
/* Check for single-step breakpoint */ |
if (walk_state->method_breakpoint && |
(walk_state->method_breakpoint <= aml_offset)) { |
/* Check if the breakpoint has been reached or passed */ |
/* Hit the breakpoint, resume single step, reset breakpoint */ |
acpi_os_printf("***Break*** at AML offset %X\n", aml_offset); |
acpi_gbl_cm_single_step = TRUE; |
acpi_gbl_step_to_next_call = FALSE; |
walk_state->method_breakpoint = 0; |
} |
/* Check for user breakpoint (Must be on exact Aml offset) */ |
else if (walk_state->user_breakpoint && |
(walk_state->user_breakpoint == aml_offset)) { |
acpi_os_printf("***UserBreakpoint*** at AML offset %X\n", |
aml_offset); |
acpi_gbl_cm_single_step = TRUE; |
acpi_gbl_step_to_next_call = FALSE; |
walk_state->method_breakpoint = 0; |
} |
/* |
* Check if this is an opcode that we are interested in -- |
* namely, opcodes that have arguments |
*/ |
if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { |
return (AE_OK); |
} |
switch (opcode_class) { |
case AML_CLASS_UNKNOWN: |
case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */ |
return (AE_OK); |
default: |
/* All other opcodes -- continue */ |
break; |
} |
/* |
* Under certain debug conditions, display this opcode and its operands |
*/ |
if ((acpi_gbl_db_output_to_file) || |
(acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) { |
if ((acpi_gbl_db_output_to_file) || |
(acpi_dbg_level & ACPI_LV_PARSE)) { |
acpi_os_printf |
("\n[AmlDebug] Next AML Opcode to execute:\n"); |
} |
/* |
* Display this op (and only this op - zero out the NEXT field |
* temporarily, and disable parser trace output for the duration of |
* the display because we don't want the extraneous debug output) |
*/ |
original_debug_level = acpi_dbg_level; |
acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS); |
next = op->common.next; |
op->common.next = NULL; |
display_op = op; |
parent_op = op->common.parent; |
if (parent_op) { |
if ((walk_state->control_state) && |
(walk_state->control_state->common.state == |
ACPI_CONTROL_PREDICATE_EXECUTING)) { |
/* |
* We are executing the predicate of an IF or WHILE statement |
* Search upwards for the containing IF or WHILE so that the |
* entire predicate can be displayed. |
*/ |
while (parent_op) { |
if ((parent_op->common.aml_opcode == |
AML_IF_OP) |
|| (parent_op->common.aml_opcode == |
AML_WHILE_OP)) { |
display_op = parent_op; |
break; |
} |
parent_op = parent_op->common.parent; |
} |
} else { |
while (parent_op) { |
if ((parent_op->common.aml_opcode == |
AML_IF_OP) |
|| (parent_op->common.aml_opcode == |
AML_ELSE_OP) |
|| (parent_op->common.aml_opcode == |
AML_SCOPE_OP) |
|| (parent_op->common.aml_opcode == |
AML_METHOD_OP) |
|| (parent_op->common.aml_opcode == |
AML_WHILE_OP)) { |
break; |
} |
display_op = parent_op; |
parent_op = parent_op->common.parent; |
} |
} |
} |
/* Now we can display it */ |
#ifdef ACPI_DISASSEMBLER |
acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX); |
#endif |
if ((op->common.aml_opcode == AML_IF_OP) || |
(op->common.aml_opcode == AML_WHILE_OP)) { |
if (walk_state->control_state->common.value) { |
acpi_os_printf |
("Predicate = [True], IF block was executed\n"); |
} else { |
acpi_os_printf |
("Predicate = [False], Skipping IF block\n"); |
} |
} else if (op->common.aml_opcode == AML_ELSE_OP) { |
acpi_os_printf |
("Predicate = [False], ELSE block was executed\n"); |
} |
/* Restore everything */ |
op->common.next = next; |
acpi_os_printf("\n"); |
if ((acpi_gbl_db_output_to_file) || |
(acpi_dbg_level & ACPI_LV_PARSE)) { |
acpi_os_printf("\n"); |
} |
acpi_dbg_level = original_debug_level; |
} |
/* If we are not single stepping, just continue executing the method */ |
if (!acpi_gbl_cm_single_step) { |
return (AE_OK); |
} |
/* |
* If we are executing a step-to-call command, |
* Check if this is a method call. |
*/ |
if (acpi_gbl_step_to_next_call) { |
if (op->common.aml_opcode != AML_INT_METHODCALL_OP) { |
/* Not a method call, just keep executing */ |
return (AE_OK); |
} |
/* Found a method call, stop executing */ |
acpi_gbl_step_to_next_call = FALSE; |
} |
/* |
* If the next opcode is a method call, we will "step over" it |
* by default. |
*/ |
if (op->common.aml_opcode == AML_INT_METHODCALL_OP) { |
/* Force no more single stepping while executing called method */ |
acpi_gbl_cm_single_step = FALSE; |
/* |
* Set the breakpoint on/before the call, it will stop execution |
* as soon as we return |
*/ |
walk_state->method_breakpoint = 1; /* Must be non-zero! */ |
} |
status = acpi_db_start_command(walk_state, op); |
/* User commands complete, continue execution of the interrupted method */ |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_initialize_debugger |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Init and start debugger |
* |
******************************************************************************/ |
acpi_status acpi_initialize_debugger(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_initialize_debugger); |
/* Init globals */ |
acpi_gbl_db_buffer = NULL; |
acpi_gbl_db_filename = NULL; |
acpi_gbl_db_output_to_file = FALSE; |
acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2; |
acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES; |
acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; |
acpi_gbl_db_opt_no_ini_methods = FALSE; |
acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE); |
if (!acpi_gbl_db_buffer) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE); |
/* Initial scope is the root */ |
acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX; |
acpi_gbl_db_scope_buf[1] = 0; |
acpi_gbl_db_scope_node = acpi_gbl_root_node; |
/* Initialize user commands loop */ |
acpi_gbl_db_terminate_loop = FALSE; |
/* |
* If configured for multi-thread support, the debug executor runs in |
* a separate thread so that the front end can be in another address |
* space, environment, or even another machine. |
*/ |
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { |
/* These were created with one unit, grab it */ |
status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete, |
ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not get debugger mutex\n"); |
return_ACPI_STATUS(status); |
} |
status = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, |
ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not get debugger mutex\n"); |
return_ACPI_STATUS(status); |
} |
/* Create the debug execution thread to execute commands */ |
acpi_gbl_db_threads_terminated = FALSE; |
status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD, |
acpi_db_execute_thread, NULL); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not start debugger thread")); |
acpi_gbl_db_threads_terminated = TRUE; |
return_ACPI_STATUS(status); |
} |
} else { |
acpi_gbl_db_thread_id = acpi_os_get_thread_id(); |
} |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_initialize_debugger) |
/******************************************************************************* |
* |
* FUNCTION: acpi_terminate_debugger |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Stop debugger |
* |
******************************************************************************/ |
void acpi_terminate_debugger(void) |
{ |
/* Terminate the AML Debugger */ |
acpi_gbl_db_terminate_loop = TRUE; |
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { |
acpi_os_release_mutex(acpi_gbl_db_command_ready); |
/* Wait the AML Debugger threads */ |
while (!acpi_gbl_db_threads_terminated) { |
acpi_os_sleep(100); |
} |
} |
if (acpi_gbl_db_buffer) { |
acpi_os_free(acpi_gbl_db_buffer); |
acpi_gbl_db_buffer = NULL; |
} |
/* Ensure that debug output is now disabled */ |
acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT; |
} |
ACPI_EXPORT_SYMBOL(acpi_terminate_debugger) |
/******************************************************************************* |
* |
* FUNCTION: acpi_set_debugger_thread_id |
* |
* PARAMETERS: thread_id - Debugger thread ID |
* |
* RETURN: None |
* |
* DESCRIPTION: Set debugger thread ID |
* |
******************************************************************************/ |
void acpi_set_debugger_thread_id(acpi_thread_id thread_id) |
{ |
acpi_gbl_db_thread_id = thread_id; |
} |
ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id) |
/drivers/acpi/acpica/dsargs.c |
---|
0,0 → 1,405 |
/****************************************************************************** |
* |
* Module Name: dsargs - Support for execution of dynamic arguments for static |
* objects (regions, fields, buffer fields, etc.) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsargs") |
/* Local prototypes */ |
static acpi_status |
acpi_ds_execute_arguments(struct acpi_namespace_node *node, |
struct acpi_namespace_node *scope_node, |
u32 aml_length, u8 *aml_start); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_execute_arguments |
* |
* PARAMETERS: node - Object NS node |
* scope_node - Parent NS node |
* aml_length - Length of executable AML |
* aml_start - Pointer to the AML |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Late (deferred) execution of region or field arguments |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_execute_arguments(struct acpi_namespace_node *node, |
struct acpi_namespace_node *scope_node, |
u32 aml_length, u8 *aml_start) |
{ |
acpi_status status; |
union acpi_parse_object *op; |
struct acpi_walk_state *walk_state; |
ACPI_FUNCTION_TRACE(ds_execute_arguments); |
/* Allocate a new parser op to be the root of the parsed tree */ |
op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP, aml_start); |
if (!op) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Save the Node for use in acpi_ps_parse_aml */ |
op->common.node = scope_node; |
/* Create and initialize a new parser state */ |
walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL); |
if (!walk_state) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, |
aml_length, NULL, ACPI_IMODE_LOAD_PASS1); |
if (ACPI_FAILURE(status)) { |
acpi_ds_delete_walk_state(walk_state); |
goto cleanup; |
} |
/* Mark this parse as a deferred opcode */ |
walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP; |
walk_state->deferred_node = node; |
/* Pass1: Parse the entire declaration */ |
status = acpi_ps_parse_aml(walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Get and init the Op created above */ |
op->common.node = node; |
acpi_ps_delete_parse_tree(op); |
/* Evaluate the deferred arguments */ |
op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP, aml_start); |
if (!op) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
op->common.node = scope_node; |
/* Create and initialize a new parser state */ |
walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL); |
if (!walk_state) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Execute the opcode and arguments */ |
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, |
aml_length, NULL, ACPI_IMODE_EXECUTE); |
if (ACPI_FAILURE(status)) { |
acpi_ds_delete_walk_state(walk_state); |
goto cleanup; |
} |
/* Mark this execution as a deferred opcode */ |
walk_state->deferred_node = node; |
status = acpi_ps_parse_aml(walk_state); |
cleanup: |
acpi_ps_delete_parse_tree(op); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_get_buffer_field_arguments |
* |
* PARAMETERS: obj_desc - A valid buffer_field object |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Get buffer_field Buffer and Index. This implements the late |
* evaluation of these field attributes. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) |
{ |
union acpi_operand_object *extra_desc; |
struct acpi_namespace_node *node; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc); |
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Get the AML pointer (method object) and buffer_field node */ |
extra_desc = acpi_ns_get_secondary_object(obj_desc); |
node = obj_desc->buffer_field.node; |
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_BUFFER_FIELD, |
node, NULL)); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n", |
acpi_ut_get_node_name(node))); |
/* Execute the AML code for the term_arg arguments */ |
status = acpi_ds_execute_arguments(node, node->parent, |
extra_desc->extra.aml_length, |
extra_desc->extra.aml_start); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_get_bank_field_arguments |
* |
* PARAMETERS: obj_desc - A valid bank_field object |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Get bank_field bank_value. This implements the late |
* evaluation of these field attributes. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc) |
{ |
union acpi_operand_object *extra_desc; |
struct acpi_namespace_node *node; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc); |
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Get the AML pointer (method object) and bank_field node */ |
extra_desc = acpi_ns_get_secondary_object(obj_desc); |
node = obj_desc->bank_field.node; |
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
(ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL)); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n", |
acpi_ut_get_node_name(node))); |
/* Execute the AML code for the term_arg arguments */ |
status = acpi_ds_execute_arguments(node, node->parent, |
extra_desc->extra.aml_length, |
extra_desc->extra.aml_start); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_ut_add_address_range(obj_desc->region.space_id, |
obj_desc->region.address, |
obj_desc->region.length, node); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_get_buffer_arguments |
* |
* PARAMETERS: obj_desc - A valid Buffer object |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Get Buffer length and initializer byte list. This implements |
* the late evaluation of these attributes. |
* |
******************************************************************************/ |
acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc); |
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Get the Buffer node */ |
node = obj_desc->buffer.node; |
if (!node) { |
ACPI_ERROR((AE_INFO, |
"No pointer back to namespace node in buffer object %p", |
obj_desc)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Buffer Arg Init\n")); |
/* Execute the AML code for the term_arg arguments */ |
status = acpi_ds_execute_arguments(node, node, |
obj_desc->buffer.aml_length, |
obj_desc->buffer.aml_start); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_get_package_arguments |
* |
* PARAMETERS: obj_desc - A valid Package object |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Get Package length and initializer byte list. This implements |
* the late evaluation of these attributes. |
* |
******************************************************************************/ |
acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc); |
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Get the Package node */ |
node = obj_desc->package.node; |
if (!node) { |
ACPI_ERROR((AE_INFO, |
"No pointer back to namespace node in package %p", |
obj_desc)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n")); |
/* Execute the AML code for the term_arg arguments */ |
status = acpi_ds_execute_arguments(node, node, |
obj_desc->package.aml_length, |
obj_desc->package.aml_start); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_get_region_arguments |
* |
* PARAMETERS: obj_desc - A valid region object |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Get region address and length. This implements the late |
* evaluation of these region attributes. |
* |
******************************************************************************/ |
acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
union acpi_operand_object *extra_desc; |
ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc); |
if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { |
return_ACPI_STATUS(AE_OK); |
} |
extra_desc = acpi_ns_get_secondary_object(obj_desc); |
if (!extra_desc) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Get the Region node */ |
node = obj_desc->region.node; |
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
(ACPI_TYPE_REGION, node, NULL)); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n", |
acpi_ut_get_node_name(node), |
extra_desc->extra.aml_start)); |
/* Execute the argument AML */ |
status = acpi_ds_execute_arguments(node, extra_desc->extra.scope_node, |
extra_desc->extra.aml_length, |
extra_desc->extra.aml_start); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_ut_add_address_range(obj_desc->region.space_id, |
obj_desc->region.address, |
obj_desc->region.length, node); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dscontrol.c |
---|
0,0 → 1,410 |
/****************************************************************************** |
* |
* Module Name: dscontrol - Support for execution control opcodes - |
* if/else/while/return |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dscontrol") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_exec_begin_control_op |
* |
* PARAMETERS: walk_list - The list that owns the walk stack |
* op - The control Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handles all control ops encountered during control method |
* execution. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
acpi_status status = AE_OK; |
union acpi_generic_state *control_state; |
ACPI_FUNCTION_NAME(ds_exec_begin_control_op); |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", |
op, op->common.aml_opcode, walk_state)); |
switch (op->common.aml_opcode) { |
case AML_WHILE_OP: |
/* |
* If this is an additional iteration of a while loop, continue. |
* There is no need to allocate a new control state. |
*/ |
if (walk_state->control_state) { |
if (walk_state->control_state->control. |
aml_predicate_start == |
(walk_state->parser_state.aml - 1)) { |
/* Reset the state to start-of-loop */ |
walk_state->control_state->common.state = |
ACPI_CONTROL_CONDITIONAL_EXECUTING; |
break; |
} |
} |
/*lint -fallthrough */ |
case AML_IF_OP: |
/* |
* IF/WHILE: Create a new control state to manage these |
* constructs. We need to manage these as a stack, in order |
* to handle nesting. |
*/ |
control_state = acpi_ut_create_control_state(); |
if (!control_state) { |
status = AE_NO_MEMORY; |
break; |
} |
/* |
* Save a pointer to the predicate for multiple executions |
* of a loop |
*/ |
control_state->control.aml_predicate_start = |
walk_state->parser_state.aml - 1; |
control_state->control.package_end = |
walk_state->parser_state.pkg_end; |
control_state->control.opcode = op->common.aml_opcode; |
/* Push the control state on this walk's control stack */ |
acpi_ut_push_generic_state(&walk_state->control_state, |
control_state); |
break; |
case AML_ELSE_OP: |
/* Predicate is in the state object */ |
/* If predicate is true, the IF was executed, ignore ELSE part */ |
if (walk_state->last_predicate) { |
status = AE_CTRL_TRUE; |
} |
break; |
case AML_RETURN_OP: |
break; |
default: |
break; |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_exec_end_control_op |
* |
* PARAMETERS: walk_list - The list that owns the walk stack |
* op - The control Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handles all control ops encountered during control method |
* execution. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, |
union acpi_parse_object * op) |
{ |
acpi_status status = AE_OK; |
union acpi_generic_state *control_state; |
ACPI_FUNCTION_NAME(ds_exec_end_control_op); |
switch (op->common.aml_opcode) { |
case AML_IF_OP: |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op)); |
/* |
* Save the result of the predicate in case there is an |
* ELSE to come |
*/ |
walk_state->last_predicate = |
(u8)walk_state->control_state->common.value; |
/* |
* Pop the control state that was created at the start |
* of the IF and free it |
*/ |
control_state = |
acpi_ut_pop_generic_state(&walk_state->control_state); |
acpi_ut_delete_generic_state(control_state); |
break; |
case AML_ELSE_OP: |
break; |
case AML_WHILE_OP: |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); |
control_state = walk_state->control_state; |
if (control_state->common.value) { |
/* Predicate was true, the body of the loop was just executed */ |
/* |
* This loop counter mechanism allows the interpreter to escape |
* possibly infinite loops. This can occur in poorly written AML |
* when the hardware does not respond within a while loop and the |
* loop does not implement a timeout. |
*/ |
control_state->control.loop_count++; |
if (control_state->control.loop_count > |
acpi_gbl_max_loop_iterations) { |
status = AE_AML_INFINITE_LOOP; |
break; |
} |
/* |
* Go back and evaluate the predicate and maybe execute the loop |
* another time |
*/ |
status = AE_CTRL_PENDING; |
walk_state->aml_last_while = |
control_state->control.aml_predicate_start; |
break; |
} |
/* Predicate was false, terminate this while loop */ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"[WHILE_OP] termination! Op=%p\n", op)); |
/* Pop this control state and free it */ |
control_state = |
acpi_ut_pop_generic_state(&walk_state->control_state); |
acpi_ut_delete_generic_state(control_state); |
break; |
case AML_RETURN_OP: |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"[RETURN_OP] Op=%p Arg=%p\n", op, |
op->common.value.arg)); |
/* |
* One optional operand -- the return value |
* It can be either an immediate operand or a result that |
* has been bubbled up the tree |
*/ |
if (op->common.value.arg) { |
/* Since we have a real Return(), delete any implicit return */ |
acpi_ds_clear_implicit_return(walk_state); |
/* Return statement has an immediate operand */ |
status = |
acpi_ds_create_operands(walk_state, |
op->common.value.arg); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* If value being returned is a Reference (such as |
* an arg or local), resolve it now because it may |
* cease to exist at the end of the method. |
*/ |
status = |
acpi_ex_resolve_to_value(&walk_state->operands[0], |
walk_state); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* Get the return value and save as the last result |
* value. This is the only place where walk_state->return_desc |
* is set to anything other than zero! |
*/ |
walk_state->return_desc = walk_state->operands[0]; |
} else if (walk_state->result_count) { |
/* Since we have a real Return(), delete any implicit return */ |
acpi_ds_clear_implicit_return(walk_state); |
/* |
* The return value has come from a previous calculation. |
* |
* If value being returned is a Reference (such as |
* an arg or local), resolve it now because it may |
* cease to exist at the end of the method. |
* |
* Allow references created by the Index operator to return |
* unchanged. |
*/ |
if ((ACPI_GET_DESCRIPTOR_TYPE |
(walk_state->results->results.obj_desc[0]) == |
ACPI_DESC_TYPE_OPERAND) |
&& ((walk_state->results->results.obj_desc[0])-> |
common.type == ACPI_TYPE_LOCAL_REFERENCE) |
&& ((walk_state->results->results.obj_desc[0])-> |
reference.class != ACPI_REFCLASS_INDEX)) { |
status = |
acpi_ex_resolve_to_value(&walk_state-> |
results->results. |
obj_desc[0], |
walk_state); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
walk_state->return_desc = |
walk_state->results->results.obj_desc[0]; |
} else { |
/* No return operand */ |
if (walk_state->num_operands) { |
acpi_ut_remove_reference(walk_state-> |
operands[0]); |
} |
walk_state->operands[0] = NULL; |
walk_state->num_operands = 0; |
walk_state->return_desc = NULL; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Completed RETURN_OP State=%p, RetVal=%p\n", |
walk_state, walk_state->return_desc)); |
/* End the control method execution right now */ |
status = AE_CTRL_TERMINATE; |
break; |
case AML_NOOP_OP: |
/* Just do nothing! */ |
break; |
case AML_BREAK_POINT_OP: |
/* |
* Set the single-step flag. This will cause the debugger (if present) |
* to break to the console within the AML debugger at the start of the |
* next AML instruction. |
*/ |
ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); |
ACPI_DEBUGGER_EXEC(acpi_os_printf |
("**break** Executed AML BreakPoint opcode\n")); |
/* Call to the OSL in case OS wants a piece of the action */ |
status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, |
"Executed AML Breakpoint opcode"); |
break; |
case AML_BREAK_OP: |
case AML_CONTINUE_OP: /* ACPI 2.0 */ |
/* Pop and delete control states until we find a while */ |
while (walk_state->control_state && |
(walk_state->control_state->control.opcode != |
AML_WHILE_OP)) { |
control_state = |
acpi_ut_pop_generic_state(&walk_state-> |
control_state); |
acpi_ut_delete_generic_state(control_state); |
} |
/* No while found? */ |
if (!walk_state->control_state) { |
return (AE_AML_NO_WHILE); |
} |
/* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */ |
walk_state->aml_last_while = |
walk_state->control_state->control.package_end; |
/* Return status depending on opcode */ |
if (op->common.aml_opcode == AML_BREAK_OP) { |
status = AE_CTRL_BREAK; |
} else { |
status = AE_CTRL_CONTINUE; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p", |
op->common.aml_opcode, op)); |
status = AE_AML_BAD_OPCODE; |
break; |
} |
return (status); |
} |
/drivers/acpi/acpica/dsdebug.c |
---|
0,0 → 1,231 |
/****************************************************************************** |
* |
* Module Name: dsdebug - Parser/Interpreter interface - debugging |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#ifdef ACPI_DISASSEMBLER |
#include "acdisasm.h" |
#endif |
#include "acinterp.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsdebug") |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
/* Local prototypes */ |
static void |
acpi_ds_print_node_pathname(struct acpi_namespace_node *node, |
const char *message); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_print_node_pathname |
* |
* PARAMETERS: node - Object |
* message - Prefix message |
* |
* DESCRIPTION: Print an object's full namespace pathname |
* Manages allocation/freeing of a pathname buffer |
* |
******************************************************************************/ |
static void |
acpi_ds_print_node_pathname(struct acpi_namespace_node *node, |
const char *message) |
{ |
struct acpi_buffer buffer; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ds_print_node_pathname); |
if (!node) { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]")); |
return_VOID; |
} |
/* Convert handle to full pathname and print it (with supplied message) */ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_ns_handle_to_pathname(node, &buffer, TRUE); |
if (ACPI_SUCCESS(status)) { |
if (message) { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ", |
message)); |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)", |
(char *)buffer.pointer, node)); |
ACPI_FREE(buffer.pointer); |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_dump_method_stack |
* |
* PARAMETERS: status - Method execution status |
* walk_state - Current state of the parse tree walk |
* op - Executing parse op |
* |
* RETURN: None |
* |
* DESCRIPTION: Called when a method has been aborted because of an error. |
* Dumps the method execution stack. |
* |
******************************************************************************/ |
void |
acpi_ds_dump_method_stack(acpi_status status, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
union acpi_parse_object *next; |
struct acpi_thread_state *thread; |
struct acpi_walk_state *next_walk_state; |
struct acpi_namespace_node *previous_method = NULL; |
union acpi_operand_object *method_desc; |
ACPI_FUNCTION_TRACE(ds_dump_method_stack); |
/* Ignore control codes, they are not errors */ |
if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) { |
return_VOID; |
} |
/* We may be executing a deferred opcode */ |
if (walk_state->deferred_node) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Executing subtree for Buffer/Package/Region\n")); |
return_VOID; |
} |
/* |
* If there is no Thread, we are not actually executing a method. |
* This can happen when the iASL compiler calls the interpreter |
* to perform constant folding. |
*/ |
thread = walk_state->thread; |
if (!thread) { |
return_VOID; |
} |
/* Display exception and method name */ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"\n**** Exception %s during execution of method ", |
acpi_format_exception(status))); |
acpi_ds_print_node_pathname(walk_state->method_node, NULL); |
/* Display stack of executing methods */ |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, |
"\n\nMethod Execution Stack:\n")); |
next_walk_state = thread->walk_state_list; |
/* Walk list of linked walk states */ |
while (next_walk_state) { |
method_desc = next_walk_state->method_desc; |
if (method_desc) { |
acpi_ex_stop_trace_method((struct acpi_namespace_node *) |
method_desc->method.node, |
method_desc, walk_state); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
" Method [%4.4s] executing: ", |
acpi_ut_get_node_name(next_walk_state-> |
method_node))); |
/* First method is the currently executing method */ |
if (next_walk_state == walk_state) { |
if (op) { |
/* Display currently executing ASL statement */ |
next = op->common.next; |
op->common.next = NULL; |
#ifdef ACPI_DISASSEMBLER |
acpi_dm_disassemble(next_walk_state, op, |
ACPI_UINT32_MAX); |
#endif |
op->common.next = next; |
} |
} else { |
/* |
* This method has called another method |
* NOTE: the method call parse subtree is already deleted at this |
* point, so we cannot disassemble the method invocation. |
*/ |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, |
"Call to method ")); |
acpi_ds_print_node_pathname(previous_method, NULL); |
} |
previous_method = next_walk_state->method_node; |
next_walk_state = next_walk_state->next; |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n")); |
} |
return_VOID; |
} |
#else |
void |
acpi_ds_dump_method_stack(acpi_status status, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
return; |
} |
#endif |
/drivers/acpi/acpica/dsfield.c |
---|
0,0 → 1,794 |
/****************************************************************************** |
* |
* Module Name: dsfield - Dispatcher field routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "acparser.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsfield") |
/* Local prototypes */ |
#ifdef ACPI_ASL_COMPILER |
#include "acdisasm.h" |
static acpi_status |
acpi_ds_create_external_region(acpi_status lookup_status, |
union acpi_parse_object *op, |
char *path, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node **node); |
#endif |
static acpi_status |
acpi_ds_get_field_names(struct acpi_create_field_info *info, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *arg); |
#ifdef ACPI_ASL_COMPILER |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_external_region (iASL Disassembler only) |
* |
* PARAMETERS: lookup_status - Status from ns_lookup operation |
* op - Op containing the Field definition and args |
* path - Pathname of the region |
* ` walk_state - Current method state |
* node - Where the new region node is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Add region to the external list if NOT_FOUND. Create a new |
* region node/object. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_create_external_region(acpi_status lookup_status, |
union acpi_parse_object *op, |
char *path, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node **node) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
if (lookup_status != AE_NOT_FOUND) { |
return (lookup_status); |
} |
/* |
* Table disassembly: |
* operation_region not found. Generate an External for it, and |
* insert the name into the namespace. |
*/ |
acpi_dm_add_op_to_external_list(op, path, ACPI_TYPE_REGION, 0, 0); |
status = acpi_ns_lookup(walk_state->scope_info, path, ACPI_TYPE_REGION, |
ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, |
walk_state, node); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Must create and install a region object for the new node */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION); |
if (!obj_desc) { |
return (AE_NO_MEMORY); |
} |
obj_desc->region.node = *node; |
status = acpi_ns_attach_object(*node, obj_desc, ACPI_TYPE_REGION); |
return (status); |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_buffer_field |
* |
* PARAMETERS: op - Current parse op (create_XXField) |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute the create_field operators: |
* create_bit_field_op, |
* create_byte_field_op, |
* create_word_field_op, |
* create_dword_field_op, |
* create_qword_field_op, |
* create_field_op (all of which define a field in a buffer) |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_create_buffer_field(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_parse_object *arg; |
struct acpi_namespace_node *node; |
acpi_status status; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *second_desc = NULL; |
u32 flags; |
ACPI_FUNCTION_TRACE(ds_create_buffer_field); |
/* |
* Get the name_string argument (name of the new buffer_field) |
*/ |
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { |
/* For create_field, name is the 4th argument */ |
arg = acpi_ps_get_arg(op, 3); |
} else { |
/* For all other create_XXXField operators, name is the 3rd argument */ |
arg = acpi_ps_get_arg(op, 2); |
} |
if (!arg) { |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
if (walk_state->deferred_node) { |
node = walk_state->deferred_node; |
status = AE_OK; |
} else { |
/* Execute flag should always be set when this function is entered */ |
if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* Creating new namespace node, should not already exist */ |
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | |
ACPI_NS_ERROR_IF_FOUND; |
/* |
* Mark node temporary if we are executing a normal control |
* method. (Don't mark if this is a module-level code method) |
*/ |
if (walk_state->method_node && |
!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { |
flags |= ACPI_NS_TEMPORARY; |
} |
/* Enter the name_string into the namespace */ |
status = |
acpi_ns_lookup(walk_state->scope_info, |
arg->common.value.string, ACPI_TYPE_ANY, |
ACPI_IMODE_LOAD_PASS1, flags, walk_state, |
&node); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
return_ACPI_STATUS(status); |
} |
} |
/* |
* We could put the returned object (Node) on the object stack for later, |
* but for now, we will put it in the "op" object that the parser uses, |
* so we can get it again at the end of this scope. |
*/ |
op->common.node = node; |
/* |
* If there is no object attached to the node, this node was just created |
* and we need to create the field object. Otherwise, this was a lookup |
* of an existing node and we don't want to create the field object again. |
*/ |
obj_desc = acpi_ns_get_attached_object(node); |
if (obj_desc) { |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* The Field definition is not fully parsed at this time. |
* (We must save the address of the AML for the buffer and index operands) |
*/ |
/* Create the buffer field object */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER_FIELD); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* Remember location in AML stream of the field unit opcode and operands -- |
* since the buffer and index operands must be evaluated. |
*/ |
second_desc = obj_desc->common.next_object; |
second_desc->extra.aml_start = op->named.data; |
second_desc->extra.aml_length = op->named.length; |
obj_desc->buffer_field.node = node; |
/* Attach constructed field descriptors to parent node */ |
status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_BUFFER_FIELD); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
cleanup: |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_get_field_names |
* |
* PARAMETERS: info - create_field info structure |
* ` walk_state - Current method state |
* arg - First parser arg for the field name list |
* |
* RETURN: Status |
* |
* DESCRIPTION: Process all named fields in a field declaration. Names are |
* entered into the namespace. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_get_field_names(struct acpi_create_field_info *info, |
struct acpi_walk_state *walk_state, |
union acpi_parse_object *arg) |
{ |
acpi_status status; |
u64 position; |
union acpi_parse_object *child; |
ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info); |
/* First field starts at bit zero */ |
info->field_bit_position = 0; |
/* Process all elements in the field list (of parse nodes) */ |
while (arg) { |
/* |
* Four types of field elements are handled: |
* 1) name - Enters a new named field into the namespace |
* 2) offset - specifies a bit offset |
* 3) access_as - changes the access mode/attributes |
* 4) connection - Associate a resource template with the field |
*/ |
switch (arg->common.aml_opcode) { |
case AML_INT_RESERVEDFIELD_OP: |
position = (u64) info->field_bit_position |
+ (u64) arg->common.value.size; |
if (position > ACPI_UINT32_MAX) { |
ACPI_ERROR((AE_INFO, |
"Bit offset within field too large (> 0xFFFFFFFF)")); |
return_ACPI_STATUS(AE_SUPPORT); |
} |
info->field_bit_position = (u32) position; |
break; |
case AML_INT_ACCESSFIELD_OP: |
case AML_INT_EXTACCESSFIELD_OP: |
/* |
* Get new access_type, access_attribute, and access_length fields |
* -- to be used for all field units that follow, until the |
* end-of-field or another access_as keyword is encountered. |
* NOTE. These three bytes are encoded in the integer value |
* of the parseop for convenience. |
* |
* In field_flags, preserve the flag bits other than the |
* ACCESS_TYPE bits. |
*/ |
/* access_type (byte_acc, word_acc, etc.) */ |
info->field_flags = (u8) |
((info-> |
field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | |
((u8)((u32)(arg->common.value.integer & 0x07)))); |
/* access_attribute (attrib_quick, attrib_byte, etc.) */ |
info->attribute = |
(u8)((arg->common.value.integer >> 8) & 0xFF); |
/* access_length (for serial/buffer protocols) */ |
info->access_length = |
(u8)((arg->common.value.integer >> 16) & 0xFF); |
break; |
case AML_INT_CONNECTION_OP: |
/* |
* Clear any previous connection. New connection is used for all |
* fields that follow, similar to access_as |
*/ |
info->resource_buffer = NULL; |
info->connection_node = NULL; |
info->pin_number_index = 0; |
/* |
* A Connection() is either an actual resource descriptor (buffer) |
* or a named reference to a resource template |
*/ |
child = arg->common.value.arg; |
if (child->common.aml_opcode == AML_INT_BYTELIST_OP) { |
info->resource_buffer = child->named.data; |
info->resource_length = |
(u16)child->named.value.integer; |
} else { |
/* Lookup the Connection() namepath, it should already exist */ |
status = acpi_ns_lookup(walk_state->scope_info, |
child->common.value. |
name, ACPI_TYPE_ANY, |
ACPI_IMODE_EXECUTE, |
ACPI_NS_DONT_OPEN_SCOPE, |
walk_state, |
&info->connection_node); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(child->common. |
value.name, |
status); |
return_ACPI_STATUS(status); |
} |
} |
break; |
case AML_INT_NAMEDFIELD_OP: |
/* Lookup the name, it should already exist */ |
status = acpi_ns_lookup(walk_state->scope_info, |
(char *)&arg->named.name, |
info->field_type, |
ACPI_IMODE_EXECUTE, |
ACPI_NS_DONT_OPEN_SCOPE, |
walk_state, &info->field_node); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE((char *)&arg->named.name, |
status); |
return_ACPI_STATUS(status); |
} else { |
arg->common.node = info->field_node; |
info->field_bit_length = arg->common.value.size; |
/* |
* If there is no object attached to the node, this node was |
* just created and we need to create the field object. |
* Otherwise, this was a lookup of an existing node and we |
* don't want to create the field object again. |
*/ |
if (!acpi_ns_get_attached_object |
(info->field_node)) { |
status = acpi_ex_prep_field_value(info); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} |
/* Keep track of bit position for the next field */ |
position = (u64) info->field_bit_position |
+ (u64) arg->common.value.size; |
if (position > ACPI_UINT32_MAX) { |
ACPI_ERROR((AE_INFO, |
"Field [%4.4s] bit offset too large (> 0xFFFFFFFF)", |
ACPI_CAST_PTR(char, |
&info->field_node-> |
name))); |
return_ACPI_STATUS(AE_SUPPORT); |
} |
info->field_bit_position += info->field_bit_length; |
info->pin_number_index++; /* Index relative to previous Connection() */ |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Invalid opcode in field list: 0x%X", |
arg->common.aml_opcode)); |
return_ACPI_STATUS(AE_AML_BAD_OPCODE); |
} |
arg = arg->common.next; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_field |
* |
* PARAMETERS: op - Op containing the Field definition and args |
* region_node - Object for the containing Operation Region |
* ` walk_state - Current method state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new field in the specified operation region |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_create_field(union acpi_parse_object *op, |
struct acpi_namespace_node *region_node, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_parse_object *arg; |
struct acpi_create_field_info info; |
ACPI_FUNCTION_TRACE_PTR(ds_create_field, op); |
/* First arg is the name of the parent op_region (must already exist) */ |
arg = op->common.value.arg; |
if (!region_node) { |
status = |
acpi_ns_lookup(walk_state->scope_info, |
arg->common.value.name, ACPI_TYPE_REGION, |
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, |
walk_state, ®ion_node); |
#ifdef ACPI_ASL_COMPILER |
status = acpi_ds_create_external_region(status, arg, |
arg->common.value.name, |
walk_state, |
®ion_node); |
#endif |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(arg->common.value.name, status); |
return_ACPI_STATUS(status); |
} |
} |
memset(&info, 0, sizeof(struct acpi_create_field_info)); |
/* Second arg is the field flags */ |
arg = arg->common.next; |
info.field_flags = (u8) arg->common.value.integer; |
info.attribute = 0; |
/* Each remaining arg is a Named Field */ |
info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD; |
info.region_node = region_node; |
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_init_field_objects |
* |
* PARAMETERS: op - Op containing the Field definition and args |
* ` walk_state - Current method state |
* |
* RETURN: Status |
* |
* DESCRIPTION: For each "Field Unit" name in the argument list that is |
* part of the field declaration, enter the name into the |
* namespace. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_init_field_objects(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_parse_object *arg = NULL; |
struct acpi_namespace_node *node; |
u8 type = 0; |
u32 flags; |
ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op); |
/* Execute flag should always be set when this function is entered */ |
if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { |
if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) { |
/* bank_field Op is deferred, just return OK */ |
return_ACPI_STATUS(AE_OK); |
} |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* |
* Get the field_list argument for this opcode. This is the start of the |
* list of field elements. |
*/ |
switch (walk_state->opcode) { |
case AML_FIELD_OP: |
arg = acpi_ps_get_arg(op, 2); |
type = ACPI_TYPE_LOCAL_REGION_FIELD; |
break; |
case AML_BANK_FIELD_OP: |
arg = acpi_ps_get_arg(op, 4); |
type = ACPI_TYPE_LOCAL_BANK_FIELD; |
break; |
case AML_INDEX_FIELD_OP: |
arg = acpi_ps_get_arg(op, 3); |
type = ACPI_TYPE_LOCAL_INDEX_FIELD; |
break; |
default: |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Creating new namespace node(s), should not already exist */ |
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | |
ACPI_NS_ERROR_IF_FOUND; |
/* |
* Mark node(s) temporary if we are executing a normal control |
* method. (Don't mark if this is a module-level code method) |
*/ |
if (walk_state->method_node && |
!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { |
flags |= ACPI_NS_TEMPORARY; |
} |
/* |
* Walk the list of entries in the field_list |
* Note: field_list can be of zero length. In this case, Arg will be NULL. |
*/ |
while (arg) { |
/* |
* Ignore OFFSET/ACCESSAS/CONNECTION terms here; we are only interested |
* in the field names in order to enter them into the namespace. |
*/ |
if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { |
status = acpi_ns_lookup(walk_state->scope_info, |
(char *)&arg->named.name, type, |
ACPI_IMODE_LOAD_PASS1, flags, |
walk_state, &node); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE((char *)&arg->named.name, |
status); |
if (status != AE_ALREADY_EXISTS) { |
return_ACPI_STATUS(status); |
} |
/* Name already exists, just ignore this error */ |
status = AE_OK; |
} |
arg->common.node = node; |
} |
/* Get the next field element in the list */ |
arg = arg->common.next; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_bank_field |
* |
* PARAMETERS: op - Op containing the Field definition and args |
* region_node - Object for the containing Operation Region |
* walk_state - Current method state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new bank field in the specified operation region |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_create_bank_field(union acpi_parse_object *op, |
struct acpi_namespace_node *region_node, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_parse_object *arg; |
struct acpi_create_field_info info; |
ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op); |
/* First arg is the name of the parent op_region (must already exist) */ |
arg = op->common.value.arg; |
if (!region_node) { |
status = |
acpi_ns_lookup(walk_state->scope_info, |
arg->common.value.name, ACPI_TYPE_REGION, |
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, |
walk_state, ®ion_node); |
#ifdef ACPI_ASL_COMPILER |
status = acpi_ds_create_external_region(status, arg, |
arg->common.value.name, |
walk_state, |
®ion_node); |
#endif |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(arg->common.value.name, status); |
return_ACPI_STATUS(status); |
} |
} |
/* Second arg is the Bank Register (Field) (must already exist) */ |
arg = arg->common.next; |
status = |
acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, |
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, |
ACPI_NS_SEARCH_PARENT, walk_state, |
&info.register_node); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
return_ACPI_STATUS(status); |
} |
/* |
* Third arg is the bank_value |
* This arg is a term_arg, not a constant |
* It will be evaluated later, by acpi_ds_eval_bank_field_operands |
*/ |
arg = arg->common.next; |
/* Fourth arg is the field flags */ |
arg = arg->common.next; |
info.field_flags = (u8) arg->common.value.integer; |
/* Each remaining arg is a Named Field */ |
info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD; |
info.region_node = region_node; |
/* |
* Use Info.data_register_node to store bank_field Op |
* It's safe because data_register_node will never be used when create bank field |
* We store aml_start and aml_length in the bank_field Op for late evaluation |
* Used in acpi_ex_prep_field_value(Info) |
* |
* TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"? |
*/ |
info.data_register_node = (struct acpi_namespace_node *)op; |
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_index_field |
* |
* PARAMETERS: op - Op containing the Field definition and args |
* region_node - Object for the containing Operation Region |
* ` walk_state - Current method state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new index field in the specified operation region |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_create_index_field(union acpi_parse_object *op, |
struct acpi_namespace_node *region_node, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_parse_object *arg; |
struct acpi_create_field_info info; |
ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op); |
/* First arg is the name of the Index register (must already exist) */ |
arg = op->common.value.arg; |
status = |
acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, |
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, |
ACPI_NS_SEARCH_PARENT, walk_state, |
&info.register_node); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
return_ACPI_STATUS(status); |
} |
/* Second arg is the data register (must already exist) */ |
arg = arg->common.next; |
status = |
acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, |
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, |
ACPI_NS_SEARCH_PARENT, walk_state, |
&info.data_register_node); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
return_ACPI_STATUS(status); |
} |
/* Next arg is the field flags */ |
arg = arg->common.next; |
info.field_flags = (u8) arg->common.value.integer; |
/* Each remaining arg is a Named Field */ |
info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD; |
info.region_node = region_node; |
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dsinit.c |
---|
0,0 → 1,263 |
/****************************************************************************** |
* |
* Module Name: dsinit - Object initialization namespace walk |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#include "actables.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsinit") |
/* Local prototypes */ |
static acpi_status |
acpi_ds_init_one_object(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_init_one_object |
* |
* PARAMETERS: obj_handle - Node for the object |
* level - Current nesting level |
* context - Points to a init info struct |
* return_value - Not used |
* |
* RETURN: Status |
* |
* DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object |
* within the namespace. |
* |
* Currently, the only objects that require initialization are: |
* 1) Methods |
* 2) Operation Regions |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_init_one_object(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
struct acpi_init_walk_info *info = |
(struct acpi_init_walk_info *)context; |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
acpi_status status; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_ENTRY(); |
/* |
* We are only interested in NS nodes owned by the table that |
* was just loaded |
*/ |
if (node->owner_id != info->owner_id) { |
return (AE_OK); |
} |
info->object_count++; |
/* And even then, we are only interested in a few object types */ |
switch (acpi_ns_get_type(obj_handle)) { |
case ACPI_TYPE_REGION: |
status = acpi_ds_initialize_region(obj_handle); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"During Region initialization %p [%4.4s]", |
obj_handle, |
acpi_ut_get_node_name(obj_handle))); |
} |
info->op_region_count++; |
break; |
case ACPI_TYPE_METHOD: |
/* |
* Auto-serialization support. We will examine each method that is |
* not_serialized to determine if it creates any Named objects. If |
* it does, it will be marked serialized to prevent problems if |
* the method is entered by two or more threads and an attempt is |
* made to create the same named object twice -- which results in |
* an AE_ALREADY_EXISTS exception and method abort. |
*/ |
info->method_count++; |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
break; |
} |
/* Ignore if already serialized */ |
if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) { |
info->serial_method_count++; |
break; |
} |
if (acpi_gbl_auto_serialize_methods) { |
/* Parse/scan method and serialize it if necessary */ |
acpi_ds_auto_serialize_method(node, obj_desc); |
if (obj_desc->method. |
info_flags & ACPI_METHOD_SERIALIZED) { |
/* Method was just converted to Serialized */ |
info->serial_method_count++; |
info->serialized_method_count++; |
break; |
} |
} |
info->non_serial_method_count++; |
break; |
case ACPI_TYPE_DEVICE: |
info->device_count++; |
break; |
default: |
break; |
} |
/* |
* We ignore errors from above, and always return OK, since |
* we don't want to abort the walk on a single error. |
*/ |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_initialize_objects |
* |
* PARAMETERS: table_desc - Descriptor for parent ACPI table |
* start_node - Root of subtree to be initialized. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walk the namespace starting at "StartNode" and perform any |
* necessary initialization on the objects found therein |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_initialize_objects(u32 table_index, |
struct acpi_namespace_node * start_node) |
{ |
acpi_status status; |
struct acpi_init_walk_info info; |
struct acpi_table_header *table; |
acpi_owner_id owner_id; |
ACPI_FUNCTION_TRACE(ds_initialize_objects); |
status = acpi_tb_get_owner_id(table_index, &owner_id); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"**** Starting initialization of namespace objects ****\n")); |
/* Set all init info to zero */ |
memset(&info, 0, sizeof(struct acpi_init_walk_info)); |
info.owner_id = owner_id; |
info.table_index = table_index; |
/* Walk entire namespace from the supplied root */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* We don't use acpi_walk_namespace since we do not want to acquire |
* the namespace reader lock. |
*/ |
status = |
acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, |
ACPI_NS_WALK_UNLOCK, acpi_ds_init_one_object, |
NULL, &info, NULL); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
status = acpi_get_table_by_index(table_index, &table); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* DSDT is always the first AML table */ |
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT)) { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
"\nInitializing Namespace objects:\n")); |
} |
/* Summary of objects initialized */ |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
"Table [%4.4s:%8.8s] (id %.2X) - %4u Objects with %3u Devices, " |
"%3u Regions, %4u Methods (%u/%u/%u Serial/Non/Cvt)\n", |
table->signature, table->oem_table_id, owner_id, |
info.object_count, info.device_count, |
info.op_region_count, info.method_count, |
info.serial_method_count, |
info.non_serial_method_count, |
info.serialized_method_count)); |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "%u Methods, %u Regions\n", |
info.method_count, info.op_region_count)); |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/dsmethod.c |
---|
0,0 → 1,840 |
/****************************************************************************** |
* |
* Module Name: dsmethod - Parser/Interpreter interface - control method parsing |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsmethod") |
/* Local prototypes */ |
static acpi_status |
acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, |
union acpi_parse_object **out_op); |
static acpi_status |
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_auto_serialize_method |
* |
* PARAMETERS: node - Namespace Node of the method |
* obj_desc - Method object attached to node |
* |
* RETURN: Status |
* |
* DESCRIPTION: Parse a control method AML to scan for control methods that |
* need serialization due to the creation of named objects. |
* |
* NOTE: It is a bit of overkill to mark all such methods serialized, since |
* there is only a problem if the method actually blocks during execution. |
* A blocking operation is, for example, a Sleep() operation, or any access |
* to an operation region. However, it is probably not possible to easily |
* detect whether a method will block or not, so we simply mark all suspicious |
* methods as serialized. |
* |
* NOTE2: This code is essentially a generic routine for parsing a single |
* control method. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, |
union acpi_operand_object *obj_desc) |
{ |
acpi_status status; |
union acpi_parse_object *op = NULL; |
struct acpi_walk_state *walk_state; |
ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node); |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Method auto-serialization parse [%4.4s] %p\n", |
acpi_ut_get_node_name(node), node)); |
/* Create/Init a root op for the method parse tree */ |
op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start); |
if (!op) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
acpi_ps_set_name(op, node->name.integer); |
op->common.node = node; |
/* Create and initialize a new walk state */ |
walk_state = |
acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL); |
if (!walk_state) { |
acpi_ps_free_op(op); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
status = |
acpi_ds_init_aml_walk(walk_state, op, node, |
obj_desc->method.aml_start, |
obj_desc->method.aml_length, NULL, 0); |
if (ACPI_FAILURE(status)) { |
acpi_ds_delete_walk_state(walk_state); |
acpi_ps_free_op(op); |
return_ACPI_STATUS(status); |
} |
walk_state->descending_callback = acpi_ds_detect_named_opcodes; |
/* Parse the method, scan for creation of named objects */ |
status = acpi_ps_parse_aml(walk_state); |
acpi_ps_delete_parse_tree(op); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_detect_named_opcodes |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* out_op - Unused, required for parser interface |
* |
* RETURN: Status |
* |
* DESCRIPTION: Descending callback used during the loading of ACPI tables. |
* Currently used to detect methods that must be marked serialized |
* in order to avoid problems with the creation of named objects. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, |
union acpi_parse_object **out_op) |
{ |
ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes); |
/* We are only interested in opcodes that create a new name */ |
if (! |
(walk_state->op_info-> |
flags & (AML_NAMED | AML_CREATE | AML_FIELD))) { |
return (AE_OK); |
} |
/* |
* At this point, we know we have a Named object opcode. |
* Mark the method as serialized. Later code will create a mutex for |
* this method to enforce serialization. |
* |
* Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the |
* Sync Level mechanism for this method, even though it is now serialized. |
* Otherwise, there can be conflicts with existing ASL code that actually |
* uses sync levels. |
*/ |
walk_state->method_desc->method.sync_level = 0; |
walk_state->method_desc->method.info_flags |= |
(ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Method serialized [%4.4s] %p - [%s] (%4.4X)\n", |
walk_state->method_node->name.ascii, |
walk_state->method_node, walk_state->op_info->name, |
walk_state->opcode)); |
/* Abort the parse, no need to examine this method any further */ |
return (AE_CTRL_TERMINATE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_error |
* |
* PARAMETERS: status - Execution status |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Called on method error. Invoke the global exception handler if |
* present, dump the method data if the debugger is configured |
* |
* Note: Allows the exception handler to change the status code |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) |
{ |
u32 aml_offset; |
ACPI_FUNCTION_ENTRY(); |
/* Ignore AE_OK and control exception codes */ |
if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) { |
return (status); |
} |
/* Invoke the global exception handler */ |
if (acpi_gbl_exception_handler) { |
/* Exit the interpreter, allow handler to execute methods */ |
acpi_ex_exit_interpreter(); |
/* |
* Handler can map the exception code to anything it wants, including |
* AE_OK, in which case the executing method will not be aborted. |
*/ |
aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml, |
walk_state->parser_state. |
aml_start); |
status = acpi_gbl_exception_handler(status, |
walk_state->method_node ? |
walk_state->method_node-> |
name.integer : 0, |
walk_state->opcode, |
aml_offset, NULL); |
acpi_ex_enter_interpreter(); |
} |
acpi_ds_clear_implicit_return(walk_state); |
if (ACPI_FAILURE(status)) { |
acpi_ds_dump_method_stack(status, walk_state, walk_state->op); |
/* Display method locals/args if debugger is present */ |
#ifdef ACPI_DEBUGGER |
acpi_db_dump_method_info(status, walk_state); |
#endif |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_method_mutex |
* |
* PARAMETERS: obj_desc - The method object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a mutex object for a serialized control method |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc) |
{ |
union acpi_operand_object *mutex_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ds_create_method_mutex); |
/* Create the new mutex object */ |
mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX); |
if (!mutex_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Create the actual OS Mutex */ |
status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex); |
if (ACPI_FAILURE(status)) { |
acpi_ut_delete_object_desc(mutex_desc); |
return_ACPI_STATUS(status); |
} |
mutex_desc->mutex.sync_level = method_desc->method.sync_level; |
method_desc->method.mutex = mutex_desc; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_begin_method_execution |
* |
* PARAMETERS: method_node - Node of the method |
* obj_desc - The method object |
* walk_state - current state, NULL if not yet executing |
* a method. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Prepare a method for execution. Parses the method if necessary, |
* increments the thread count, and waits at the method semaphore |
* for clearance to execute. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); |
if (!method_node) { |
return_ACPI_STATUS(AE_NULL_ENTRY); |
} |
acpi_ex_start_trace_method(method_node, obj_desc, walk_state); |
/* Prevent wraparound of thread count */ |
if (obj_desc->method.thread_count == ACPI_UINT8_MAX) { |
ACPI_ERROR((AE_INFO, |
"Method reached maximum reentrancy limit (255)")); |
return_ACPI_STATUS(AE_AML_METHOD_LIMIT); |
} |
/* |
* If this method is serialized, we need to acquire the method mutex. |
*/ |
if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) { |
/* |
* Create a mutex for the method if it is defined to be Serialized |
* and a mutex has not already been created. We defer the mutex creation |
* until a method is actually executed, to minimize the object count |
*/ |
if (!obj_desc->method.mutex) { |
status = acpi_ds_create_method_mutex(obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* |
* The current_sync_level (per-thread) must be less than or equal to |
* the sync level of the method. This mechanism provides some |
* deadlock prevention. |
* |
* If the method was auto-serialized, we just ignore the sync level |
* mechanism, because auto-serialization of methods can interfere |
* with ASL code that actually uses sync levels. |
* |
* Top-level method invocation has no walk state at this point |
*/ |
if (walk_state && |
(!(obj_desc->method. |
info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) |
&& (walk_state->thread->current_sync_level > |
obj_desc->method.mutex->mutex.sync_level)) { |
ACPI_ERROR((AE_INFO, |
"Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", |
acpi_ut_get_node_name(method_node), |
walk_state->thread->current_sync_level)); |
return_ACPI_STATUS(AE_AML_MUTEX_ORDER); |
} |
/* |
* Obtain the method mutex if necessary. Do not acquire mutex for a |
* recursive call. |
*/ |
if (!walk_state || |
!obj_desc->method.mutex->mutex.thread_id || |
(walk_state->thread->thread_id != |
obj_desc->method.mutex->mutex.thread_id)) { |
/* |
* Acquire the method mutex. This releases the interpreter if we |
* block (and reacquires it before it returns) |
*/ |
status = |
acpi_ex_system_wait_mutex(obj_desc->method.mutex-> |
mutex.os_mutex, |
ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Update the mutex and walk info and save the original sync_level */ |
if (walk_state) { |
obj_desc->method.mutex->mutex. |
original_sync_level = |
walk_state->thread->current_sync_level; |
obj_desc->method.mutex->mutex.thread_id = |
walk_state->thread->thread_id; |
walk_state->thread->current_sync_level = |
obj_desc->method.sync_level; |
} else { |
obj_desc->method.mutex->mutex. |
original_sync_level = |
obj_desc->method.mutex->mutex.sync_level; |
obj_desc->method.mutex->mutex.thread_id = |
acpi_os_get_thread_id(); |
} |
} |
/* Always increase acquisition depth */ |
obj_desc->method.mutex->mutex.acquisition_depth++; |
} |
/* |
* Allocate an Owner ID for this method, only if this is the first thread |
* to begin concurrent execution. We only need one owner_id, even if the |
* method is invoked recursively. |
*/ |
if (!obj_desc->method.owner_id) { |
status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
} |
/* |
* Increment the method parse tree thread count since it has been |
* reentered one more time (even if it is the same thread) |
*/ |
obj_desc->method.thread_count++; |
acpi_method_count++; |
return_ACPI_STATUS(status); |
cleanup: |
/* On error, must release the method mutex (if present) */ |
if (obj_desc->method.mutex) { |
acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_call_control_method |
* |
* PARAMETERS: thread - Info for this thread |
* this_walk_state - Current walk state |
* op - Current Op to be walked |
* |
* RETURN: Status |
* |
* DESCRIPTION: Transfer execution to a called control method |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_call_control_method(struct acpi_thread_state *thread, |
struct acpi_walk_state *this_walk_state, |
union acpi_parse_object *op) |
{ |
acpi_status status; |
struct acpi_namespace_node *method_node; |
struct acpi_walk_state *next_walk_state = NULL; |
union acpi_operand_object *obj_desc; |
struct acpi_evaluate_info *info; |
u32 i; |
ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Calling method %p, currentstate=%p\n", |
this_walk_state->prev_op, this_walk_state)); |
/* |
* Get the namespace entry for the control method we are about to call |
*/ |
method_node = this_walk_state->method_call_node; |
if (!method_node) { |
return_ACPI_STATUS(AE_NULL_ENTRY); |
} |
obj_desc = acpi_ns_get_attached_object(method_node); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NULL_OBJECT); |
} |
/* Init for new method, possibly wait on method mutex */ |
status = acpi_ds_begin_method_execution(method_node, obj_desc, |
this_walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Begin method parse/execution. Create a new walk state */ |
next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, |
NULL, obj_desc, thread); |
if (!next_walk_state) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* The resolved arguments were put on the previous walk state's operand |
* stack. Operands on the previous walk state stack always |
* start at index 0. Also, null terminate the list of arguments |
*/ |
this_walk_state->operands[this_walk_state->num_operands] = NULL; |
/* |
* Allocate and initialize the evaluation information block |
* TBD: this is somewhat inefficient, should change interface to |
* ds_init_aml_walk. For now, keeps this struct off the CPU stack |
*/ |
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
info->parameters = &this_walk_state->operands[0]; |
status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node, |
obj_desc->method.aml_start, |
obj_desc->method.aml_length, info, |
ACPI_IMODE_EXECUTE); |
ACPI_FREE(info); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* |
* Delete the operands on the previous walkstate operand stack |
* (they were copied to new objects) |
*/ |
for (i = 0; i < obj_desc->method.param_count; i++) { |
acpi_ut_remove_reference(this_walk_state->operands[i]); |
this_walk_state->operands[i] = NULL; |
} |
/* Clear the operand stack */ |
this_walk_state->num_operands = 0; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"**** Begin nested execution of [%4.4s] **** WalkState=%p\n", |
method_node->name.ascii, next_walk_state)); |
/* Invoke an internal method if necessary */ |
if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { |
status = |
obj_desc->method.dispatch.implementation(next_walk_state); |
if (status == AE_OK) { |
status = AE_CTRL_TERMINATE; |
} |
} |
return_ACPI_STATUS(status); |
cleanup: |
/* On error, we must terminate the method properly */ |
acpi_ds_terminate_control_method(obj_desc, next_walk_state); |
acpi_ds_delete_walk_state(next_walk_state); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_restart_control_method |
* |
* PARAMETERS: walk_state - State for preempted method (caller) |
* return_desc - Return value from the called method |
* |
* RETURN: Status |
* |
* DESCRIPTION: Restart a method that was preempted by another (nested) method |
* invocation. Handle the return value (if any) from the callee. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, |
union acpi_operand_object *return_desc) |
{ |
acpi_status status; |
int same_as_implicit_return; |
ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state); |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", |
acpi_ut_get_node_name(walk_state->method_node), |
walk_state->method_call_op, return_desc)); |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
" ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", |
walk_state->return_used, |
walk_state->results, walk_state)); |
/* Did the called method return a value? */ |
if (return_desc) { |
/* Is the implicit return object the same as the return desc? */ |
same_as_implicit_return = |
(walk_state->implicit_return_obj == return_desc); |
/* Are we actually going to use the return value? */ |
if (walk_state->return_used) { |
/* Save the return value from the previous method */ |
status = acpi_ds_result_push(return_desc, walk_state); |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(return_desc); |
return_ACPI_STATUS(status); |
} |
/* |
* Save as THIS method's return value in case it is returned |
* immediately to yet another method |
*/ |
walk_state->return_desc = return_desc; |
} |
/* |
* The following code is the optional support for the so-called |
* "implicit return". Some AML code assumes that the last value of the |
* method is "implicitly" returned to the caller, in the absence of an |
* explicit return value. |
* |
* Just save the last result of the method as the return value. |
* |
* NOTE: this is optional because the ASL language does not actually |
* support this behavior. |
*/ |
else if (!acpi_ds_do_implicit_return |
(return_desc, walk_state, FALSE) |
|| same_as_implicit_return) { |
/* |
* Delete the return value if it will not be used by the |
* calling method or remove one reference if the explicit return |
* is the same as the implicit return value. |
*/ |
acpi_ut_remove_reference(return_desc); |
} |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_terminate_control_method |
* |
* PARAMETERS: method_desc - Method object |
* walk_state - State associated with the method |
* |
* RETURN: None |
* |
* DESCRIPTION: Terminate a control method. Delete everything that the method |
* created, delete all locals and arguments, and delete the parse |
* tree if requested. |
* |
* MUTEX: Interpreter is locked |
* |
******************************************************************************/ |
void |
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, |
struct acpi_walk_state *walk_state) |
{ |
ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); |
/* method_desc is required, walk_state is optional */ |
if (!method_desc) { |
return_VOID; |
} |
if (walk_state) { |
/* Delete all arguments and locals */ |
acpi_ds_method_data_delete_all(walk_state); |
/* |
* If method is serialized, release the mutex and restore the |
* current sync level for this thread |
*/ |
if (method_desc->method.mutex) { |
/* Acquisition Depth handles recursive calls */ |
method_desc->method.mutex->mutex.acquisition_depth--; |
if (!method_desc->method.mutex->mutex.acquisition_depth) { |
walk_state->thread->current_sync_level = |
method_desc->method.mutex->mutex. |
original_sync_level; |
acpi_os_release_mutex(method_desc->method. |
mutex->mutex.os_mutex); |
method_desc->method.mutex->mutex.thread_id = 0; |
} |
} |
/* |
* Delete any namespace objects created anywhere within the |
* namespace by the execution of this method. Unless: |
* 1) This method is a module-level executable code method, in which |
* case we want make the objects permanent. |
* 2) There are other threads executing the method, in which case we |
* will wait until the last thread has completed. |
*/ |
if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) |
&& (method_desc->method.thread_count == 1)) { |
/* Delete any direct children of (created by) this method */ |
acpi_ns_delete_namespace_subtree(walk_state-> |
method_node); |
/* |
* Delete any objects that were created by this method |
* elsewhere in the namespace (if any were created). |
* Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the |
* deletion such that we don't have to perform an entire |
* namespace walk for every control method execution. |
*/ |
if (method_desc->method. |
info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) { |
acpi_ns_delete_namespace_by_owner(method_desc-> |
method. |
owner_id); |
method_desc->method.info_flags &= |
~ACPI_METHOD_MODIFIED_NAMESPACE; |
} |
} |
} |
/* Decrement the thread count on the method */ |
if (method_desc->method.thread_count) { |
method_desc->method.thread_count--; |
} else { |
ACPI_ERROR((AE_INFO, "Invalid zero thread count in method")); |
} |
/* Are there any other threads currently executing this method? */ |
if (method_desc->method.thread_count) { |
/* |
* Additional threads. Do not release the owner_id in this case, |
* we immediately reuse it for the next thread executing this method |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"*** Completed execution of one thread, %u threads remaining\n", |
method_desc->method.thread_count)); |
} else { |
/* This is the only executing thread for this method */ |
/* |
* Support to dynamically change a method from not_serialized to |
* Serialized if it appears that the method is incorrectly written and |
* does not support multiple thread execution. The best example of this |
* is if such a method creates namespace objects and blocks. A second |
* thread will fail with an AE_ALREADY_EXISTS exception. |
* |
* This code is here because we must wait until the last thread exits |
* before marking the method as serialized. |
*/ |
if (method_desc->method. |
info_flags & ACPI_METHOD_SERIALIZED_PENDING) { |
if (walk_state) { |
ACPI_INFO((AE_INFO, |
"Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", |
walk_state->method_node->name. |
ascii)); |
} |
/* |
* Method tried to create an object twice and was marked as |
* "pending serialized". The probable cause is that the method |
* cannot handle reentrancy. |
* |
* The method was created as not_serialized, but it tried to create |
* a named object and then blocked, causing the second thread |
* entrance to begin and then fail. Workaround this problem by |
* marking the method permanently as Serialized when the last |
* thread exits here. |
*/ |
method_desc->method.info_flags &= |
~ACPI_METHOD_SERIALIZED_PENDING; |
method_desc->method.info_flags |= |
(ACPI_METHOD_SERIALIZED | |
ACPI_METHOD_IGNORE_SYNC_LEVEL); |
method_desc->method.sync_level = 0; |
} |
/* No more threads, we can free the owner_id */ |
if (! |
(method_desc->method. |
info_flags & ACPI_METHOD_MODULE_LEVEL)) { |
acpi_ut_release_owner_id(&method_desc->method.owner_id); |
} |
} |
acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc-> |
method.node, method_desc, walk_state); |
return_VOID; |
} |
/drivers/acpi/acpica/dsmthdat.c |
---|
0,0 → 1,714 |
/******************************************************************************* |
* |
* Module Name: dsmthdat - control method arguments and local variables |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsmthdat") |
/* Local prototypes */ |
static void |
acpi_ds_method_data_delete_value(u8 type, |
u32 index, struct acpi_walk_state *walk_state); |
static acpi_status |
acpi_ds_method_data_set_value(u8 type, |
u32 index, |
union acpi_operand_object *object, |
struct acpi_walk_state *walk_state); |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
acpi_object_type |
acpi_ds_method_data_get_type(u16 opcode, |
u32 index, struct acpi_walk_state *walk_state); |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_init |
* |
* PARAMETERS: walk_state - Current walk state object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize the data structures that hold the method's arguments |
* and locals. The data struct is an array of namespace nodes for |
* each - this allows ref_of and de_ref_of to work properly for these |
* special data types. |
* |
* NOTES: walk_state fields are initialized to zero by the |
* ACPI_ALLOCATE_ZEROED(). |
* |
* A pseudo-Namespace Node is assigned to each argument and local |
* so that ref_of() can return a pointer to the Node. |
* |
******************************************************************************/ |
void acpi_ds_method_data_init(struct acpi_walk_state *walk_state) |
{ |
u32 i; |
ACPI_FUNCTION_TRACE(ds_method_data_init); |
/* Init the method arguments */ |
for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { |
ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name, |
NAMEOF_ARG_NTE); |
walk_state->arguments[i].name.integer |= (i << 24); |
walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED; |
walk_state->arguments[i].type = ACPI_TYPE_ANY; |
walk_state->arguments[i].flags = ANOBJ_METHOD_ARG; |
} |
/* Init the method locals */ |
for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { |
ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name, |
NAMEOF_LOCAL_NTE); |
walk_state->local_variables[i].name.integer |= (i << 24); |
walk_state->local_variables[i].descriptor_type = |
ACPI_DESC_TYPE_NAMED; |
walk_state->local_variables[i].type = ACPI_TYPE_ANY; |
walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL; |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_delete_all |
* |
* PARAMETERS: walk_state - Current walk state object |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete method locals and arguments. Arguments are only |
* deleted if this method was called from another method. |
* |
******************************************************************************/ |
void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state) |
{ |
u32 index; |
ACPI_FUNCTION_TRACE(ds_method_data_delete_all); |
/* Detach the locals */ |
for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) { |
if (walk_state->local_variables[index].object) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n", |
index, |
walk_state->local_variables[index]. |
object)); |
/* Detach object (if present) and remove a reference */ |
acpi_ns_detach_object(&walk_state-> |
local_variables[index]); |
} |
} |
/* Detach the arguments */ |
for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) { |
if (walk_state->arguments[index].object) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n", |
index, |
walk_state->arguments[index].object)); |
/* Detach object (if present) and remove a reference */ |
acpi_ns_detach_object(&walk_state->arguments[index]); |
} |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_init_args |
* |
* PARAMETERS: *params - Pointer to a parameter list for the method |
* max_param_count - The arg count for this method |
* walk_state - Current walk state object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize arguments for a method. The parameter list is a list |
* of ACPI operand objects, either null terminated or whose length |
* is defined by max_param_count. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_method_data_init_args(union acpi_operand_object **params, |
u32 max_param_count, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
u32 index = 0; |
ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params); |
if (!params) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"No param list passed to method\n")); |
return_ACPI_STATUS(AE_OK); |
} |
/* Copy passed parameters into the new method stack frame */ |
while ((index < ACPI_METHOD_NUM_ARGS) && |
(index < max_param_count) && params[index]) { |
/* |
* A valid parameter. |
* Store the argument in the method/walk descriptor. |
* Do not copy the arg in order to implement call by reference |
*/ |
status = acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index, |
params[index], |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
index++; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_get_node |
* |
* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or |
* ACPI_REFCLASS_ARG |
* index - Which Local or Arg whose type to get |
* walk_state - Current walk state object |
* node - Where the node is returned. |
* |
* RETURN: Status and node |
* |
* DESCRIPTION: Get the Node associated with a local or arg. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_method_data_get_node(u8 type, |
u32 index, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node **node) |
{ |
ACPI_FUNCTION_TRACE(ds_method_data_get_node); |
/* |
* Method Locals and Arguments are supported |
*/ |
switch (type) { |
case ACPI_REFCLASS_LOCAL: |
if (index > ACPI_METHOD_MAX_LOCAL) { |
ACPI_ERROR((AE_INFO, |
"Local index %u is invalid (max %u)", |
index, ACPI_METHOD_MAX_LOCAL)); |
return_ACPI_STATUS(AE_AML_INVALID_INDEX); |
} |
/* Return a pointer to the pseudo-node */ |
*node = &walk_state->local_variables[index]; |
break; |
case ACPI_REFCLASS_ARG: |
if (index > ACPI_METHOD_MAX_ARG) { |
ACPI_ERROR((AE_INFO, |
"Arg index %u is invalid (max %u)", |
index, ACPI_METHOD_MAX_ARG)); |
return_ACPI_STATUS(AE_AML_INVALID_INDEX); |
} |
/* Return a pointer to the pseudo-node */ |
*node = &walk_state->arguments[index]; |
break; |
default: |
ACPI_ERROR((AE_INFO, "Type %u is invalid", type)); |
return_ACPI_STATUS(AE_TYPE); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_set_value |
* |
* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or |
* ACPI_REFCLASS_ARG |
* index - Which Local or Arg to get |
* object - Object to be inserted into the stack entry |
* walk_state - Current walk state object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index. |
* Note: There is no "implicit conversion" for locals. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_method_data_set_value(u8 type, |
u32 index, |
union acpi_operand_object *object, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(ds_method_data_set_value); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"NewObj %p Type %2.2X, Refs=%u [%s]\n", object, |
type, object->common.reference_count, |
acpi_ut_get_type_name(object->common.type))); |
/* Get the namespace node for the arg/local */ |
status = acpi_ds_method_data_get_node(type, index, walk_state, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Increment ref count so object can't be deleted while installed. |
* NOTE: We do not copy the object in order to preserve the call by |
* reference semantics of ACPI Control Method invocation. |
* (See ACPI Specification 2.0C) |
*/ |
acpi_ut_add_reference(object); |
/* Install the object */ |
node->object = object; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_get_value |
* |
* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or |
* ACPI_REFCLASS_ARG |
* index - Which localVar or argument to get |
* walk_state - Current walk state object |
* dest_desc - Where Arg or Local value is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Retrieve value of selected Arg or Local for this method |
* Used only in acpi_ex_resolve_to_value(). |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_method_data_get_value(u8 type, |
u32 index, |
struct acpi_walk_state *walk_state, |
union acpi_operand_object **dest_desc) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
union acpi_operand_object *object; |
ACPI_FUNCTION_TRACE(ds_method_data_get_value); |
/* Validate the object descriptor */ |
if (!dest_desc) { |
ACPI_ERROR((AE_INFO, "Null object descriptor pointer")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Get the namespace node for the arg/local */ |
status = acpi_ds_method_data_get_node(type, index, walk_state, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get the object from the node */ |
object = node->object; |
/* Examine the returned object, it must be valid. */ |
if (!object) { |
/* |
* Index points to uninitialized object. |
* This means that either 1) The expected argument was |
* not passed to the method, or 2) A local variable |
* was referenced by the method (via the ASL) |
* before it was initialized. Either case is an error. |
*/ |
/* If slack enabled, init the local_x/arg_x to an Integer of value zero */ |
if (acpi_gbl_enable_interpreter_slack) { |
object = acpi_ut_create_integer_object((u64) 0); |
if (!object) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
node->object = object; |
} |
/* Otherwise, return the error */ |
else |
switch (type) { |
case ACPI_REFCLASS_ARG: |
ACPI_ERROR((AE_INFO, |
"Uninitialized Arg[%u] at node %p", |
index, node)); |
return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG); |
case ACPI_REFCLASS_LOCAL: |
/* |
* No error message for this case, will be trapped again later to |
* detect and ignore cases of Store(local_x,local_x) |
*/ |
return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL); |
default: |
ACPI_ERROR((AE_INFO, |
"Not a Arg/Local opcode: 0x%X", |
type)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
} |
/* |
* The Index points to an initialized and valid object. |
* Return an additional reference to the object |
*/ |
*dest_desc = object; |
acpi_ut_add_reference(object); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_delete_value |
* |
* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or |
* ACPI_REFCLASS_ARG |
* index - Which localVar or argument to delete |
* walk_state - Current walk state object |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete the entry at Opcode:Index. Inserts |
* a null into the stack slot after the object is deleted. |
* |
******************************************************************************/ |
static void |
acpi_ds_method_data_delete_value(u8 type, |
u32 index, struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
union acpi_operand_object *object; |
ACPI_FUNCTION_TRACE(ds_method_data_delete_value); |
/* Get the namespace node for the arg/local */ |
status = acpi_ds_method_data_get_node(type, index, walk_state, &node); |
if (ACPI_FAILURE(status)) { |
return_VOID; |
} |
/* Get the associated object */ |
object = acpi_ns_get_attached_object(node); |
/* |
* Undefine the Arg or Local by setting its descriptor |
* pointer to NULL. Locals/Args can contain both |
* ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs |
*/ |
node->object = NULL; |
if ((object) && |
(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) { |
/* |
* There is a valid object. |
* Decrement the reference count by one to balance the |
* increment when the object was stored. |
*/ |
acpi_ut_remove_reference(object); |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_store_object_to_local |
* |
* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or |
* ACPI_REFCLASS_ARG |
* index - Which Local or Arg to set |
* obj_desc - Value to be stored |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed |
* as the new value for the Arg or Local and the reference count |
* for obj_desc is incremented. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_store_object_to_local(u8 type, |
u32 index, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
union acpi_operand_object *current_obj_desc; |
union acpi_operand_object *new_obj_desc; |
ACPI_FUNCTION_TRACE(ds_store_object_to_local); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n", |
type, index, obj_desc)); |
/* Parameter validation */ |
if (!obj_desc) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Get the namespace node for the arg/local */ |
status = acpi_ds_method_data_get_node(type, index, walk_state, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
current_obj_desc = acpi_ns_get_attached_object(node); |
if (current_obj_desc == obj_desc) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n", |
obj_desc)); |
return_ACPI_STATUS(status); |
} |
/* |
* If the reference count on the object is more than one, we must |
* take a copy of the object before we store. A reference count |
* of exactly 1 means that the object was just created during the |
* evaluation of an expression, and we can safely use it since it |
* is not used anywhere else. |
*/ |
new_obj_desc = obj_desc; |
if (obj_desc->common.reference_count > 1) { |
status = |
acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* |
* If there is an object already in this slot, we either |
* have to delete it, or if this is an argument and there |
* is an object reference stored there, we have to do |
* an indirect store! |
*/ |
if (current_obj_desc) { |
/* |
* Check for an indirect store if an argument |
* contains an object reference (stored as an Node). |
* We don't allow this automatic dereferencing for |
* locals, since a store to a local should overwrite |
* anything there, including an object reference. |
* |
* If both Arg0 and Local0 contain ref_of (Local4): |
* |
* Store (1, Arg0) - Causes indirect store to local4 |
* Store (1, Local0) - Stores 1 in local0, overwriting |
* the reference to local4 |
* Store (1, de_refof (Local0)) - Causes indirect store to local4 |
* |
* Weird, but true. |
*/ |
if (type == ACPI_REFCLASS_ARG) { |
/* |
* If we have a valid reference object that came from ref_of(), |
* do the indirect store |
*/ |
if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) == |
ACPI_DESC_TYPE_OPERAND) |
&& (current_obj_desc->common.type == |
ACPI_TYPE_LOCAL_REFERENCE) |
&& (current_obj_desc->reference.class == |
ACPI_REFCLASS_REFOF)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Arg (%p) is an ObjRef(Node), storing in node %p\n", |
new_obj_desc, |
current_obj_desc)); |
/* |
* Store this object to the Node (perform the indirect store) |
* NOTE: No implicit conversion is performed, as per the ACPI |
* specification rules on storing to Locals/Args. |
*/ |
status = |
acpi_ex_store_object_to_node(new_obj_desc, |
current_obj_desc-> |
reference. |
object, |
walk_state, |
ACPI_NO_IMPLICIT_CONVERSION); |
/* Remove local reference if we copied the object above */ |
if (new_obj_desc != obj_desc) { |
acpi_ut_remove_reference(new_obj_desc); |
} |
return_ACPI_STATUS(status); |
} |
} |
/* Delete the existing object before storing the new one */ |
acpi_ds_method_data_delete_value(type, index, walk_state); |
} |
/* |
* Install the Obj descriptor (*new_obj_desc) into |
* the descriptor for the Arg or Local. |
* (increments the object reference count by one) |
*/ |
status = |
acpi_ds_method_data_set_value(type, index, new_obj_desc, |
walk_state); |
/* Remove local reference if we copied the object above */ |
if (new_obj_desc != obj_desc) { |
acpi_ut_remove_reference(new_obj_desc); |
} |
return_ACPI_STATUS(status); |
} |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_method_data_get_type |
* |
* PARAMETERS: opcode - Either AML_LOCAL_OP or AML_ARG_OP |
* index - Which Local or Arg whose type to get |
* walk_state - Current walk state object |
* |
* RETURN: Data type of current value of the selected Arg or Local |
* |
* DESCRIPTION: Get the type of the object stored in the Local or Arg |
* |
******************************************************************************/ |
acpi_object_type |
acpi_ds_method_data_get_type(u16 opcode, |
u32 index, struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
union acpi_operand_object *object; |
ACPI_FUNCTION_TRACE(ds_method_data_get_type); |
/* Get the namespace node for the arg/local */ |
status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node); |
if (ACPI_FAILURE(status)) { |
return_VALUE((ACPI_TYPE_NOT_FOUND)); |
} |
/* Get the object */ |
object = acpi_ns_get_attached_object(node); |
if (!object) { |
/* Uninitialized local/arg, return TYPE_ANY */ |
return_VALUE(ACPI_TYPE_ANY); |
} |
/* Get the object type */ |
return_VALUE(object->type); |
} |
#endif |
/drivers/acpi/acpica/dsobject.c |
---|
0,0 → 1,849 |
/****************************************************************************** |
* |
* Module Name: dsobject - Dispatcher object management routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsobject") |
/* Local prototypes */ |
static acpi_status |
acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
union acpi_operand_object **obj_desc_ptr); |
#ifndef ACPI_NO_METHOD_EXECUTION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_build_internal_object |
* |
* PARAMETERS: walk_state - Current walk state |
* op - Parser object to be translated |
* obj_desc_ptr - Where the ACPI internal object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Translate a parser Op object to the equivalent namespace object |
* Simple objects are any objects other than a package object! |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
union acpi_operand_object **obj_desc_ptr) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
acpi_object_type type; |
ACPI_FUNCTION_TRACE(ds_build_internal_object); |
*obj_desc_ptr = NULL; |
if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { |
/* |
* This is a named object reference. If this name was |
* previously looked up in the namespace, it was stored in this op. |
* Otherwise, go ahead and look it up now |
*/ |
if (!op->common.node) { |
status = acpi_ns_lookup(walk_state->scope_info, |
op->common.value.string, |
ACPI_TYPE_ANY, |
ACPI_IMODE_EXECUTE, |
ACPI_NS_SEARCH_PARENT | |
ACPI_NS_DONT_OPEN_SCOPE, NULL, |
ACPI_CAST_INDIRECT_PTR(struct |
acpi_namespace_node, |
&(op-> |
common. |
node))); |
if (ACPI_FAILURE(status)) { |
/* Check if we are resolving a named reference within a package */ |
if ((status == AE_NOT_FOUND) |
&& (acpi_gbl_enable_interpreter_slack) |
&& |
((op->common.parent->common.aml_opcode == |
AML_PACKAGE_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_VAR_PACKAGE_OP))) { |
/* |
* We didn't find the target and we are populating elements |
* of a package - ignore if slack enabled. Some ASL code |
* contains dangling invalid references in packages and |
* expects that no exception will be issued. Leave the |
* element as a null element. It cannot be used, but it |
* can be overwritten by subsequent ASL code - this is |
* typically the case. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Ignoring unresolved reference in package [%4.4s]\n", |
walk_state-> |
scope_info->scope. |
node->name.ascii)); |
return_ACPI_STATUS(AE_OK); |
} else { |
ACPI_ERROR_NAMESPACE(op->common.value. |
string, status); |
} |
return_ACPI_STATUS(status); |
} |
} |
/* Special object resolution for elements of a package */ |
if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || |
(op->common.parent->common.aml_opcode == |
AML_VAR_PACKAGE_OP)) { |
/* |
* Attempt to resolve the node to a value before we insert it into |
* the package. If this is a reference to a common data type, |
* resolve it immediately. According to the ACPI spec, package |
* elements can only be "data objects" or method references. |
* Attempt to resolve to an Integer, Buffer, String or Package. |
* If cannot, return the named reference (for things like Devices, |
* Methods, etc.) Buffer Fields and Fields will resolve to simple |
* objects (int/buf/str/pkg). |
* |
* NOTE: References to things like Devices, Methods, Mutexes, etc. |
* will remain as named references. This behavior is not described |
* in the ACPI spec, but it appears to be an oversight. |
*/ |
obj_desc = |
ACPI_CAST_PTR(union acpi_operand_object, |
op->common.node); |
status = |
acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR |
(struct |
acpi_namespace_node, |
&obj_desc), |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Special handling for Alias objects. We need to setup the type |
* and the Op->Common.Node to point to the Alias target. Note, |
* Alias has at most one level of indirection internally. |
*/ |
type = op->common.node->type; |
if (type == ACPI_TYPE_LOCAL_ALIAS) { |
type = obj_desc->common.type; |
op->common.node = |
ACPI_CAST_PTR(struct acpi_namespace_node, |
op->common.node->object); |
} |
switch (type) { |
/* |
* For these types, we need the actual node, not the subobject. |
* However, the subobject did not get an extra reference count above. |
* |
* TBD: should ex_resolve_node_to_value be changed to fix this? |
*/ |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_THERMAL: |
acpi_ut_add_reference(op->common.node->object); |
/*lint -fallthrough */ |
/* |
* For these types, we need the actual node, not the subobject. |
* The subobject got an extra reference count in ex_resolve_node_to_value. |
*/ |
case ACPI_TYPE_MUTEX: |
case ACPI_TYPE_METHOD: |
case ACPI_TYPE_POWER: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_EVENT: |
case ACPI_TYPE_REGION: |
/* We will create a reference object for these types below */ |
break; |
default: |
/* |
* All other types - the node was resolved to an actual |
* object, we are done. |
*/ |
goto exit; |
} |
} |
} |
/* Create and init a new internal ACPI object */ |
obj_desc = acpi_ut_create_internal_object((acpi_ps_get_opcode_info |
(op->common.aml_opcode))-> |
object_type); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
status = |
acpi_ds_init_object_from_op(walk_state, op, op->common.aml_opcode, |
&obj_desc); |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
exit: |
*obj_desc_ptr = obj_desc; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_build_internal_buffer_obj |
* |
* PARAMETERS: walk_state - Current walk state |
* op - Parser object to be translated |
* buffer_length - Length of the buffer |
* obj_desc_ptr - Where the ACPI internal object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Translate a parser Op package object to the equivalent |
* namespace object |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
u32 buffer_length, |
union acpi_operand_object **obj_desc_ptr) |
{ |
union acpi_parse_object *arg; |
union acpi_operand_object *obj_desc; |
union acpi_parse_object *byte_list; |
u32 byte_list_length = 0; |
ACPI_FUNCTION_TRACE(ds_build_internal_buffer_obj); |
/* |
* If we are evaluating a Named buffer object "Name (xxxx, Buffer)". |
* The buffer object already exists (from the NS node), otherwise it must |
* be created. |
*/ |
obj_desc = *obj_desc_ptr; |
if (!obj_desc) { |
/* Create a new buffer object */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER); |
*obj_desc_ptr = obj_desc; |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
} |
/* |
* Second arg is the buffer data (optional) byte_list can be either |
* individual bytes or a string initializer. In either case, a |
* byte_list appears in the AML. |
*/ |
arg = op->common.value.arg; /* skip first arg */ |
byte_list = arg->named.next; |
if (byte_list) { |
if (byte_list->common.aml_opcode != AML_INT_BYTELIST_OP) { |
ACPI_ERROR((AE_INFO, |
"Expecting bytelist, found AML opcode 0x%X in op %p", |
byte_list->common.aml_opcode, byte_list)); |
acpi_ut_remove_reference(obj_desc); |
return (AE_TYPE); |
} |
byte_list_length = (u32) byte_list->common.value.integer; |
} |
/* |
* The buffer length (number of bytes) will be the larger of: |
* 1) The specified buffer length and |
* 2) The length of the initializer byte list |
*/ |
obj_desc->buffer.length = buffer_length; |
if (byte_list_length > buffer_length) { |
obj_desc->buffer.length = byte_list_length; |
} |
/* Allocate the buffer */ |
if (obj_desc->buffer.length == 0) { |
obj_desc->buffer.pointer = NULL; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Buffer defined with zero length in AML, creating\n")); |
} else { |
obj_desc->buffer.pointer = |
ACPI_ALLOCATE_ZEROED(obj_desc->buffer.length); |
if (!obj_desc->buffer.pointer) { |
acpi_ut_delete_object_desc(obj_desc); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Initialize buffer from the byte_list (if present) */ |
if (byte_list) { |
memcpy(obj_desc->buffer.pointer, byte_list->named.data, |
byte_list_length); |
} |
} |
obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; |
op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_build_internal_package_obj |
* |
* PARAMETERS: walk_state - Current walk state |
* op - Parser object to be translated |
* element_count - Number of elements in the package - this is |
* the num_elements argument to Package() |
* obj_desc_ptr - Where the ACPI internal object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Translate a parser Op package object to the equivalent |
* namespace object |
* |
* NOTE: The number of elements in the package will be always be the num_elements |
* count, regardless of the number of elements in the package list. If |
* num_elements is smaller, only that many package list elements are used. |
* if num_elements is larger, the Package object is padded out with |
* objects of type Uninitialized (as per ACPI spec.) |
* |
* Even though the ASL compilers do not allow num_elements to be smaller |
* than the Package list length (for the fixed length package opcode), some |
* BIOS code modifies the AML on the fly to adjust the num_elements, and |
* this code compensates for that. This also provides compatibility with |
* other AML interpreters. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
u32 element_count, |
union acpi_operand_object **obj_desc_ptr) |
{ |
union acpi_parse_object *arg; |
union acpi_parse_object *parent; |
union acpi_operand_object *obj_desc = NULL; |
acpi_status status = AE_OK; |
u32 i; |
u16 index; |
u16 reference_count; |
ACPI_FUNCTION_TRACE(ds_build_internal_package_obj); |
/* Find the parent of a possibly nested package */ |
parent = op->common.parent; |
while ((parent->common.aml_opcode == AML_PACKAGE_OP) || |
(parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { |
parent = parent->common.parent; |
} |
/* |
* If we are evaluating a Named package object "Name (xxxx, Package)", |
* the package object already exists, otherwise it must be created. |
*/ |
obj_desc = *obj_desc_ptr; |
if (!obj_desc) { |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE); |
*obj_desc_ptr = obj_desc; |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
obj_desc->package.node = parent->common.node; |
} |
/* |
* Allocate the element array (array of pointers to the individual |
* objects) based on the num_elements parameter. Add an extra pointer slot |
* so that the list is always null terminated. |
*/ |
obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) |
element_count + |
1) * sizeof(void *)); |
if (!obj_desc->package.elements) { |
acpi_ut_delete_object_desc(obj_desc); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
obj_desc->package.count = element_count; |
/* |
* Initialize the elements of the package, up to the num_elements count. |
* Package is automatically padded with uninitialized (NULL) elements |
* if num_elements is greater than the package list length. Likewise, |
* Package is truncated if num_elements is less than the list length. |
*/ |
arg = op->common.value.arg; |
arg = arg->common.next; |
for (i = 0; arg && (i < element_count); i++) { |
if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { |
if (arg->common.node->type == ACPI_TYPE_METHOD) { |
/* |
* A method reference "looks" to the parser to be a method |
* invocation, so we special case it here |
*/ |
arg->common.aml_opcode = AML_INT_NAMEPATH_OP; |
status = |
acpi_ds_build_internal_object(walk_state, |
arg, |
&obj_desc-> |
package. |
elements[i]); |
} else { |
/* This package element is already built, just get it */ |
obj_desc->package.elements[i] = |
ACPI_CAST_PTR(union acpi_operand_object, |
arg->common.node); |
} |
} else { |
status = acpi_ds_build_internal_object(walk_state, arg, |
&obj_desc-> |
package. |
elements[i]); |
} |
if (*obj_desc_ptr) { |
/* Existing package, get existing reference count */ |
reference_count = |
(*obj_desc_ptr)->common.reference_count; |
if (reference_count > 1) { |
/* Make new element ref count match original ref count */ |
for (index = 0; index < (reference_count - 1); |
index++) { |
acpi_ut_add_reference((obj_desc-> |
package. |
elements[i])); |
} |
} |
} |
arg = arg->common.next; |
} |
/* Check for match between num_elements and actual length of package_list */ |
if (arg) { |
/* |
* num_elements was exhausted, but there are remaining elements in the |
* package_list. Truncate the package to num_elements. |
* |
* Note: technically, this is an error, from ACPI spec: "It is an error |
* for NumElements to be less than the number of elements in the |
* PackageList". However, we just print a message and |
* no exception is returned. This provides Windows compatibility. Some |
* BIOSs will alter the num_elements on the fly, creating this type |
* of ill-formed package object. |
*/ |
while (arg) { |
/* |
* We must delete any package elements that were created earlier |
* and are not going to be used because of the package truncation. |
*/ |
if (arg->common.node) { |
acpi_ut_remove_reference(ACPI_CAST_PTR |
(union |
acpi_operand_object, |
arg->common.node)); |
arg->common.node = NULL; |
} |
/* Find out how many elements there really are */ |
i++; |
arg = arg->common.next; |
} |
ACPI_INFO((AE_INFO, |
"Actual Package length (%u) is larger than NumElements field (%u), truncated", |
i, element_count)); |
} else if (i < element_count) { |
/* |
* Arg list (elements) was exhausted, but we did not reach num_elements count. |
* Note: this is not an error, the package is padded out with NULLs. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Package List length (%u) smaller than NumElements count (%u), padded with null elements\n", |
i, element_count)); |
} |
obj_desc->package.flags |= AOPOBJ_DATA_VALID; |
op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_node |
* |
* PARAMETERS: walk_state - Current walk state |
* node - NS Node to be initialized |
* op - Parser object to be translated |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create the object to be associated with a namespace node |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_create_node(struct acpi_walk_state *walk_state, |
struct acpi_namespace_node *node, |
union acpi_parse_object *op) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_TRACE_PTR(ds_create_node, op); |
/* |
* Because of the execution pass through the non-control-method |
* parts of the table, we can arrive here twice. Only init |
* the named object node the first time through |
*/ |
if (acpi_ns_get_attached_object(node)) { |
return_ACPI_STATUS(AE_OK); |
} |
if (!op->common.value.arg) { |
/* No arguments, there is nothing to do */ |
return_ACPI_STATUS(AE_OK); |
} |
/* Build an internal object for the argument(s) */ |
status = acpi_ds_build_internal_object(walk_state, op->common.value.arg, |
&obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Re-type the object according to its argument */ |
node->type = obj_desc->common.type; |
/* Attach obj to node */ |
status = acpi_ns_attach_object(node, obj_desc, node->type); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
#endif /* ACPI_NO_METHOD_EXECUTION */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_init_object_from_op |
* |
* PARAMETERS: walk_state - Current walk state |
* op - Parser op used to init the internal object |
* opcode - AML opcode associated with the object |
* ret_obj_desc - Namespace object to be initialized |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize a namespace object from a parser Op and its |
* associated arguments. The namespace object is a more compact |
* representation of the Op and its arguments. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
u16 opcode, |
union acpi_operand_object **ret_obj_desc) |
{ |
const struct acpi_opcode_info *op_info; |
union acpi_operand_object *obj_desc; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ds_init_object_from_op); |
obj_desc = *ret_obj_desc; |
op_info = acpi_ps_get_opcode_info(opcode); |
if (op_info->class == AML_CLASS_UNKNOWN) { |
/* Unknown opcode */ |
return_ACPI_STATUS(AE_TYPE); |
} |
/* Perform per-object initialization */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_BUFFER: |
/* |
* Defer evaluation of Buffer term_arg operand |
*/ |
obj_desc->buffer.node = |
ACPI_CAST_PTR(struct acpi_namespace_node, |
walk_state->operands[0]); |
obj_desc->buffer.aml_start = op->named.data; |
obj_desc->buffer.aml_length = op->named.length; |
break; |
case ACPI_TYPE_PACKAGE: |
/* |
* Defer evaluation of Package term_arg operand |
*/ |
obj_desc->package.node = |
ACPI_CAST_PTR(struct acpi_namespace_node, |
walk_state->operands[0]); |
obj_desc->package.aml_start = op->named.data; |
obj_desc->package.aml_length = op->named.length; |
break; |
case ACPI_TYPE_INTEGER: |
switch (op_info->type) { |
case AML_TYPE_CONSTANT: |
/* |
* Resolve AML Constants here - AND ONLY HERE! |
* All constants are integers. |
* We mark the integer with a flag that indicates that it started |
* life as a constant -- so that stores to constants will perform |
* as expected (noop). zero_op is used as a placeholder for optional |
* target operands. |
*/ |
obj_desc->common.flags = AOPOBJ_AML_CONSTANT; |
switch (opcode) { |
case AML_ZERO_OP: |
obj_desc->integer.value = 0; |
break; |
case AML_ONE_OP: |
obj_desc->integer.value = 1; |
break; |
case AML_ONES_OP: |
obj_desc->integer.value = ACPI_UINT64_MAX; |
/* Truncate value if we are executing from a 32-bit ACPI table */ |
#ifndef ACPI_NO_METHOD_EXECUTION |
(void)acpi_ex_truncate_for32bit_table(obj_desc); |
#endif |
break; |
case AML_REVISION_OP: |
obj_desc->integer.value = ACPI_CA_VERSION; |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown constant opcode 0x%X", |
opcode)); |
status = AE_AML_OPERAND_TYPE; |
break; |
} |
break; |
case AML_TYPE_LITERAL: |
obj_desc->integer.value = op->common.value.integer; |
#ifndef ACPI_NO_METHOD_EXECUTION |
if (acpi_ex_truncate_for32bit_table(obj_desc)) { |
/* Warn if we found a 64-bit constant in a 32-bit table */ |
ACPI_WARNING((AE_INFO, |
"Truncated 64-bit constant found in 32-bit table: %8.8X%8.8X => %8.8X", |
ACPI_FORMAT_UINT64(op->common. |
value.integer), |
(u32)obj_desc->integer.value)); |
} |
#endif |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown Integer type 0x%X", |
op_info->type)); |
status = AE_AML_OPERAND_TYPE; |
break; |
} |
break; |
case ACPI_TYPE_STRING: |
obj_desc->string.pointer = op->common.value.string; |
obj_desc->string.length = (u32)strlen(op->common.value.string); |
/* |
* The string is contained in the ACPI table, don't ever try |
* to delete it |
*/ |
obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; |
break; |
case ACPI_TYPE_METHOD: |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
switch (op_info->type) { |
case AML_TYPE_LOCAL_VARIABLE: |
/* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ |
obj_desc->reference.value = |
((u32)opcode) - AML_LOCAL_OP; |
obj_desc->reference.class = ACPI_REFCLASS_LOCAL; |
#ifndef ACPI_NO_METHOD_EXECUTION |
status = |
acpi_ds_method_data_get_node(ACPI_REFCLASS_LOCAL, |
obj_desc->reference. |
value, walk_state, |
ACPI_CAST_INDIRECT_PTR |
(struct |
acpi_namespace_node, |
&obj_desc->reference. |
object)); |
#endif |
break; |
case AML_TYPE_METHOD_ARGUMENT: |
/* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ |
obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP; |
obj_desc->reference.class = ACPI_REFCLASS_ARG; |
#ifndef ACPI_NO_METHOD_EXECUTION |
status = acpi_ds_method_data_get_node(ACPI_REFCLASS_ARG, |
obj_desc-> |
reference.value, |
walk_state, |
ACPI_CAST_INDIRECT_PTR |
(struct |
acpi_namespace_node, |
&obj_desc-> |
reference. |
object)); |
#endif |
break; |
default: /* Object name or Debug object */ |
switch (op->common.aml_opcode) { |
case AML_INT_NAMEPATH_OP: |
/* Node was saved in Op */ |
obj_desc->reference.node = op->common.node; |
obj_desc->reference.object = |
op->common.node->object; |
obj_desc->reference.class = ACPI_REFCLASS_NAME; |
break; |
case AML_DEBUG_OP: |
obj_desc->reference.class = ACPI_REFCLASS_DEBUG; |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unimplemented reference type for AML opcode: 0x%4.4X", |
opcode)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
break; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unimplemented data type: 0x%X", |
obj_desc->common.type)); |
status = AE_AML_OPERAND_TYPE; |
break; |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dsopcode.c |
---|
0,0 → 1,766 |
/****************************************************************************** |
* |
* Module Name: dsopcode - Dispatcher support for regions and fields |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "acevents.h" |
#include "actables.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsopcode") |
/* Local prototypes */ |
static acpi_status |
acpi_ds_init_buffer_field(u16 aml_opcode, |
union acpi_operand_object *obj_desc, |
union acpi_operand_object *buffer_desc, |
union acpi_operand_object *offset_desc, |
union acpi_operand_object *length_desc, |
union acpi_operand_object *result_desc); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_initialize_region |
* |
* PARAMETERS: obj_handle - Region namespace node |
* |
* RETURN: Status |
* |
* DESCRIPTION: Front end to ev_initialize_region |
* |
******************************************************************************/ |
acpi_status acpi_ds_initialize_region(acpi_handle obj_handle) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
obj_desc = acpi_ns_get_attached_object(obj_handle); |
/* Namespace is NOT locked */ |
status = acpi_ev_initialize_region(obj_desc, FALSE); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_init_buffer_field |
* |
* PARAMETERS: aml_opcode - create_xxx_field |
* obj_desc - buffer_field object |
* buffer_desc - Host Buffer |
* offset_desc - Offset into buffer |
* length_desc - Length of field (CREATE_FIELD_OP only) |
* result_desc - Where to store the result |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform actual initialization of a buffer field |
* |
******************************************************************************/ |
static acpi_status |
acpi_ds_init_buffer_field(u16 aml_opcode, |
union acpi_operand_object *obj_desc, |
union acpi_operand_object *buffer_desc, |
union acpi_operand_object *offset_desc, |
union acpi_operand_object *length_desc, |
union acpi_operand_object *result_desc) |
{ |
u32 offset; |
u32 bit_offset; |
u32 bit_count; |
u8 field_flags; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc); |
/* Host object must be a Buffer */ |
if (buffer_desc->common.type != ACPI_TYPE_BUFFER) { |
ACPI_ERROR((AE_INFO, |
"Target of Create Field is not a Buffer object - %s", |
acpi_ut_get_object_type_name(buffer_desc))); |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
/* |
* The last parameter to all of these opcodes (result_desc) started |
* out as a name_string, and should therefore now be a NS node |
* after resolution in acpi_ex_resolve_operands(). |
*/ |
if (ACPI_GET_DESCRIPTOR_TYPE(result_desc) != ACPI_DESC_TYPE_NAMED) { |
ACPI_ERROR((AE_INFO, |
"(%s) destination not a NS Node [%s]", |
acpi_ps_get_opcode_name(aml_opcode), |
acpi_ut_get_descriptor_name(result_desc))); |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
offset = (u32) offset_desc->integer.value; |
/* |
* Setup the Bit offsets and counts, according to the opcode |
*/ |
switch (aml_opcode) { |
case AML_CREATE_FIELD_OP: |
/* Offset is in bits, count is in bits */ |
field_flags = AML_FIELD_ACCESS_BYTE; |
bit_offset = offset; |
bit_count = (u32) length_desc->integer.value; |
/* Must have a valid (>0) bit count */ |
if (bit_count == 0) { |
ACPI_ERROR((AE_INFO, |
"Attempt to CreateField of length zero")); |
status = AE_AML_OPERAND_VALUE; |
goto cleanup; |
} |
break; |
case AML_CREATE_BIT_FIELD_OP: |
/* Offset is in bits, Field is one bit */ |
bit_offset = offset; |
bit_count = 1; |
field_flags = AML_FIELD_ACCESS_BYTE; |
break; |
case AML_CREATE_BYTE_FIELD_OP: |
/* Offset is in bytes, field is one byte */ |
bit_offset = 8 * offset; |
bit_count = 8; |
field_flags = AML_FIELD_ACCESS_BYTE; |
break; |
case AML_CREATE_WORD_FIELD_OP: |
/* Offset is in bytes, field is one word */ |
bit_offset = 8 * offset; |
bit_count = 16; |
field_flags = AML_FIELD_ACCESS_WORD; |
break; |
case AML_CREATE_DWORD_FIELD_OP: |
/* Offset is in bytes, field is one dword */ |
bit_offset = 8 * offset; |
bit_count = 32; |
field_flags = AML_FIELD_ACCESS_DWORD; |
break; |
case AML_CREATE_QWORD_FIELD_OP: |
/* Offset is in bytes, field is one qword */ |
bit_offset = 8 * offset; |
bit_count = 64; |
field_flags = AML_FIELD_ACCESS_QWORD; |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown field creation opcode 0x%02X", |
aml_opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
/* Entire field must fit within the current length of the buffer */ |
if ((bit_offset + bit_count) > (8 * (u32) buffer_desc->buffer.length)) { |
ACPI_ERROR((AE_INFO, |
"Field [%4.4s] at %u exceeds Buffer [%4.4s] size %u (bits)", |
acpi_ut_get_node_name(result_desc), |
bit_offset + bit_count, |
acpi_ut_get_node_name(buffer_desc->buffer.node), |
8 * (u32) buffer_desc->buffer.length)); |
status = AE_AML_BUFFER_LIMIT; |
goto cleanup; |
} |
/* |
* Initialize areas of the field object that are common to all fields |
* For field_flags, use LOCK_RULE = 0 (NO_LOCK), |
* UPDATE_RULE = 0 (UPDATE_PRESERVE) |
*/ |
status = acpi_ex_prep_common_field_object(obj_desc, field_flags, 0, |
bit_offset, bit_count); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
obj_desc->buffer_field.buffer_obj = buffer_desc; |
/* Reference count for buffer_desc inherits obj_desc count */ |
buffer_desc->common.reference_count = (u16) |
(buffer_desc->common.reference_count + |
obj_desc->common.reference_count); |
cleanup: |
/* Always delete the operands */ |
acpi_ut_remove_reference(offset_desc); |
acpi_ut_remove_reference(buffer_desc); |
if (aml_opcode == AML_CREATE_FIELD_OP) { |
acpi_ut_remove_reference(length_desc); |
} |
/* On failure, delete the result descriptor */ |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(result_desc); /* Result descriptor */ |
} else { |
/* Now the address and length are valid for this buffer_field */ |
obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_eval_buffer_field_operands |
* |
* PARAMETERS: walk_state - Current walk |
* op - A valid buffer_field Op object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get buffer_field Buffer and Index |
* Called from acpi_ds_exec_end_op during buffer_field parse tree walk |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
union acpi_parse_object *next_op; |
ACPI_FUNCTION_TRACE_PTR(ds_eval_buffer_field_operands, op); |
/* |
* This is where we evaluate the address and length fields of the |
* create_xxx_field declaration |
*/ |
node = op->common.node; |
/* next_op points to the op that holds the Buffer */ |
next_op = op->common.value.arg; |
/* Evaluate/create the address and length operands */ |
status = acpi_ds_create_operands(walk_state, next_op); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Resolve the operands */ |
status = acpi_ex_resolve_operands(op->common.aml_opcode, |
ACPI_WALK_OPERANDS, walk_state); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, "(%s) bad operand(s), status 0x%X", |
acpi_ps_get_opcode_name(op->common.aml_opcode), |
status)); |
return_ACPI_STATUS(status); |
} |
/* Initialize the Buffer Field */ |
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { |
/* NOTE: Slightly different operands for this opcode */ |
status = |
acpi_ds_init_buffer_field(op->common.aml_opcode, obj_desc, |
walk_state->operands[0], |
walk_state->operands[1], |
walk_state->operands[2], |
walk_state->operands[3]); |
} else { |
/* All other, create_xxx_field opcodes */ |
status = |
acpi_ds_init_buffer_field(op->common.aml_opcode, obj_desc, |
walk_state->operands[0], |
walk_state->operands[1], NULL, |
walk_state->operands[2]); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_eval_region_operands |
* |
* PARAMETERS: walk_state - Current walk |
* op - A valid region Op object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get region address and length |
* Called from acpi_ds_exec_end_op during op_region parse tree walk |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *operand_desc; |
struct acpi_namespace_node *node; |
union acpi_parse_object *next_op; |
ACPI_FUNCTION_TRACE_PTR(ds_eval_region_operands, op); |
/* |
* This is where we evaluate the address and length fields of the |
* op_region declaration |
*/ |
node = op->common.node; |
/* next_op points to the op that holds the space_ID */ |
next_op = op->common.value.arg; |
/* next_op points to address op */ |
next_op = next_op->common.next; |
/* Evaluate/create the address and length operands */ |
status = acpi_ds_create_operands(walk_state, next_op); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Resolve the length and address operands to numbers */ |
status = acpi_ex_resolve_operands(op->common.aml_opcode, |
ACPI_WALK_OPERANDS, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* |
* Get the length operand and save it |
* (at Top of stack) |
*/ |
operand_desc = walk_state->operands[walk_state->num_operands - 1]; |
obj_desc->region.length = (u32) operand_desc->integer.value; |
acpi_ut_remove_reference(operand_desc); |
/* |
* Get the address and save it |
* (at top of stack - 1) |
*/ |
operand_desc = walk_state->operands[walk_state->num_operands - 2]; |
obj_desc->region.address = (acpi_physical_address) |
operand_desc->integer.value; |
acpi_ut_remove_reference(operand_desc); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", |
obj_desc, |
ACPI_FORMAT_UINT64(obj_desc->region.address), |
obj_desc->region.length)); |
/* Now the address and length are valid for this opregion */ |
obj_desc->region.flags |= AOPOBJ_DATA_VALID; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_eval_table_region_operands |
* |
* PARAMETERS: walk_state - Current walk |
* op - A valid region Op object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get region address and length. |
* Called from acpi_ds_exec_end_op during data_table_region parse |
* tree walk. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object **operand; |
struct acpi_namespace_node *node; |
union acpi_parse_object *next_op; |
struct acpi_table_header *table; |
u32 table_index; |
ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op); |
/* |
* This is where we evaluate the Signature string, oem_id string, |
* and oem_table_id string of the Data Table Region declaration |
*/ |
node = op->common.node; |
/* next_op points to Signature string op */ |
next_op = op->common.value.arg; |
/* |
* Evaluate/create the Signature string, oem_id string, |
* and oem_table_id string operands |
*/ |
status = acpi_ds_create_operands(walk_state, next_op); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
operand = &walk_state->operands[0]; |
/* |
* Resolve the Signature string, oem_id string, |
* and oem_table_id string operands |
*/ |
status = acpi_ex_resolve_operands(op->common.aml_opcode, |
ACPI_WALK_OPERANDS, walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Find the ACPI table */ |
status = acpi_tb_find_table(operand[0]->string.pointer, |
operand[1]->string.pointer, |
operand[2]->string.pointer, &table_index); |
if (ACPI_FAILURE(status)) { |
if (status == AE_NOT_FOUND) { |
ACPI_ERROR((AE_INFO, |
"ACPI Table [%4.4s] OEM:(%s, %s) not found in RSDT/XSDT", |
operand[0]->string.pointer, |
operand[1]->string.pointer, |
operand[2]->string.pointer)); |
} |
goto cleanup; |
} |
status = acpi_get_table_by_index(table_index, &table); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
status = AE_NOT_EXIST; |
goto cleanup; |
} |
obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table); |
obj_desc->region.length = table->length; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", |
obj_desc, |
ACPI_FORMAT_UINT64(obj_desc->region.address), |
obj_desc->region.length)); |
/* Now the address and length are valid for this opregion */ |
obj_desc->region.flags |= AOPOBJ_DATA_VALID; |
cleanup: |
acpi_ut_remove_reference(operand[0]); |
acpi_ut_remove_reference(operand[1]); |
acpi_ut_remove_reference(operand[2]); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_eval_data_object_operands |
* |
* PARAMETERS: walk_state - Current walk |
* op - A valid data_object Op object |
* obj_desc - data_object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get the operands and complete the following data object types: |
* Buffer, Package. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
union acpi_operand_object *obj_desc) |
{ |
acpi_status status; |
union acpi_operand_object *arg_desc; |
u32 length; |
ACPI_FUNCTION_TRACE(ds_eval_data_object_operands); |
/* The first operand (for all of these data objects) is the length */ |
/* |
* Set proper index into operand stack for acpi_ds_obj_stack_push |
* invoked inside acpi_ds_create_operand. |
*/ |
walk_state->operand_index = walk_state->num_operands; |
status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_ex_resolve_operands(walk_state->opcode, |
&(walk_state-> |
operands[walk_state->num_operands - |
1]), walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Extract length operand */ |
arg_desc = walk_state->operands[walk_state->num_operands - 1]; |
length = (u32) arg_desc->integer.value; |
/* Cleanup for length operand */ |
status = acpi_ds_obj_stack_pop(1, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_ut_remove_reference(arg_desc); |
/* |
* Create the actual data object |
*/ |
switch (op->common.aml_opcode) { |
case AML_BUFFER_OP: |
status = |
acpi_ds_build_internal_buffer_obj(walk_state, op, length, |
&obj_desc); |
break; |
case AML_PACKAGE_OP: |
case AML_VAR_PACKAGE_OP: |
status = |
acpi_ds_build_internal_package_obj(walk_state, op, length, |
&obj_desc); |
break; |
default: |
return_ACPI_STATUS(AE_AML_BAD_OPCODE); |
} |
if (ACPI_SUCCESS(status)) { |
/* |
* Return the object in the walk_state, unless the parent is a package - |
* in this case, the return object will be stored in the parse tree |
* for the package. |
*/ |
if ((!op->common.parent) || |
((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && |
(op->common.parent->common.aml_opcode != |
AML_VAR_PACKAGE_OP) |
&& (op->common.parent->common.aml_opcode != |
AML_NAME_OP))) { |
walk_state->result_obj = obj_desc; |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_eval_bank_field_operands |
* |
* PARAMETERS: walk_state - Current walk |
* op - A valid bank_field Op object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get bank_field bank_value |
* Called from acpi_ds_exec_end_op during bank_field parse tree walk |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *operand_desc; |
struct acpi_namespace_node *node; |
union acpi_parse_object *next_op; |
union acpi_parse_object *arg; |
ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op); |
/* |
* This is where we evaluate the bank_value field of the |
* bank_field declaration |
*/ |
/* next_op points to the op that holds the Region */ |
next_op = op->common.value.arg; |
/* next_op points to the op that holds the Bank Register */ |
next_op = next_op->common.next; |
/* next_op points to the op that holds the Bank Value */ |
next_op = next_op->common.next; |
/* |
* Set proper index into operand stack for acpi_ds_obj_stack_push |
* invoked inside acpi_ds_create_operand. |
* |
* We use walk_state->Operands[0] to store the evaluated bank_value |
*/ |
walk_state->operand_index = 0; |
status = acpi_ds_create_operand(walk_state, next_op, 0); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, |
acpi_ps_get_opcode_name(op->common.aml_opcode), 1); |
/* |
* Get the bank_value operand and save it |
* (at Top of stack) |
*/ |
operand_desc = walk_state->operands[0]; |
/* Arg points to the start Bank Field */ |
arg = acpi_ps_get_arg(op, 4); |
while (arg) { |
/* Ignore OFFSET and ACCESSAS terms here */ |
if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { |
node = arg->common.node; |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
obj_desc->bank_field.value = |
(u32) operand_desc->integer.value; |
} |
/* Move to next field in the list */ |
arg = arg->common.next; |
} |
acpi_ut_remove_reference(operand_desc); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dsutils.c |
---|
0,0 → 1,879 |
/******************************************************************************* |
* |
* Module Name: dsutils - Dispatcher utilities |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dsutils") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_clear_implicit_return |
* |
* PARAMETERS: walk_state - Current State |
* |
* RETURN: None. |
* |
* DESCRIPTION: Clear and remove a reference on an implicit return value. Used |
* to delete "stale" return values (if enabled, the return value |
* from every operator is saved at least momentarily, in case the |
* parent method exits.) |
* |
******************************************************************************/ |
void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state) |
{ |
ACPI_FUNCTION_NAME(ds_clear_implicit_return); |
/* |
* Slack must be enabled for this feature |
*/ |
if (!acpi_gbl_enable_interpreter_slack) { |
return; |
} |
if (walk_state->implicit_return_obj) { |
/* |
* Delete any "stale" implicit return. However, in |
* complex statements, the implicit return value can be |
* bubbled up several levels. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Removing reference on stale implicit return obj %p\n", |
walk_state->implicit_return_obj)); |
acpi_ut_remove_reference(walk_state->implicit_return_obj); |
walk_state->implicit_return_obj = NULL; |
} |
} |
#ifndef ACPI_NO_METHOD_EXECUTION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_do_implicit_return |
* |
* PARAMETERS: return_desc - The return value |
* walk_state - Current State |
* add_reference - True if a reference should be added to the |
* return object |
* |
* RETURN: TRUE if implicit return enabled, FALSE otherwise |
* |
* DESCRIPTION: Implements the optional "implicit return". We save the result |
* of every ASL operator and control method invocation in case the |
* parent method exit. Before storing a new return value, we |
* delete the previous return value. |
* |
******************************************************************************/ |
u8 |
acpi_ds_do_implicit_return(union acpi_operand_object *return_desc, |
struct acpi_walk_state *walk_state, u8 add_reference) |
{ |
ACPI_FUNCTION_NAME(ds_do_implicit_return); |
/* |
* Slack must be enabled for this feature, and we must |
* have a valid return object |
*/ |
if ((!acpi_gbl_enable_interpreter_slack) || (!return_desc)) { |
return (FALSE); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Result %p will be implicitly returned; Prev=%p\n", |
return_desc, walk_state->implicit_return_obj)); |
/* |
* Delete any "stale" implicit return value first. However, in |
* complex statements, the implicit return value can be |
* bubbled up several levels, so we don't clear the value if it |
* is the same as the return_desc. |
*/ |
if (walk_state->implicit_return_obj) { |
if (walk_state->implicit_return_obj == return_desc) { |
return (TRUE); |
} |
acpi_ds_clear_implicit_return(walk_state); |
} |
/* Save the implicit return value, add a reference if requested */ |
walk_state->implicit_return_obj = return_desc; |
if (add_reference) { |
acpi_ut_add_reference(return_desc); |
} |
return (TRUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_is_result_used |
* |
* PARAMETERS: op - Current Op |
* walk_state - Current State |
* |
* RETURN: TRUE if result is used, FALSE otherwise |
* |
* DESCRIPTION: Check if a result object will be used by the parent |
* |
******************************************************************************/ |
u8 |
acpi_ds_is_result_used(union acpi_parse_object * op, |
struct acpi_walk_state * walk_state) |
{ |
const struct acpi_opcode_info *parent_info; |
ACPI_FUNCTION_TRACE_PTR(ds_is_result_used, op); |
/* Must have both an Op and a Result Object */ |
if (!op) { |
ACPI_ERROR((AE_INFO, "Null Op")); |
return_UINT8(TRUE); |
} |
/* |
* We know that this operator is not a |
* Return() operator (would not come here.) The following code is the |
* optional support for a so-called "implicit return". Some AML code |
* assumes that the last value of the method is "implicitly" returned |
* to the caller. Just save the last result as the return value. |
* NOTE: this is optional because the ASL language does not actually |
* support this behavior. |
*/ |
(void)acpi_ds_do_implicit_return(walk_state->result_obj, walk_state, |
TRUE); |
/* |
* Now determine if the parent will use the result |
* |
* If there is no parent, or the parent is a scope_op, we are executing |
* at the method level. An executing method typically has no parent, |
* since each method is parsed separately. A method invoked externally |
* via execute_control_method has a scope_op as the parent. |
*/ |
if ((!op->common.parent) || |
(op->common.parent->common.aml_opcode == AML_SCOPE_OP)) { |
/* No parent, the return value cannot possibly be used */ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"At Method level, result of [%s] not used\n", |
acpi_ps_get_opcode_name(op->common. |
aml_opcode))); |
return_UINT8(FALSE); |
} |
/* Get info on the parent. The root_op is AML_SCOPE */ |
parent_info = |
acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode); |
if (parent_info->class == AML_CLASS_UNKNOWN) { |
ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op)); |
return_UINT8(FALSE); |
} |
/* |
* Decide what to do with the result based on the parent. If |
* the parent opcode will not use the result, delete the object. |
* Otherwise leave it as is, it will be deleted when it is used |
* as an operand later. |
*/ |
switch (parent_info->class) { |
case AML_CLASS_CONTROL: |
switch (op->common.parent->common.aml_opcode) { |
case AML_RETURN_OP: |
/* Never delete the return value associated with a return opcode */ |
goto result_used; |
case AML_IF_OP: |
case AML_WHILE_OP: |
/* |
* If we are executing the predicate AND this is the predicate op, |
* we will use the return value |
*/ |
if ((walk_state->control_state->common.state == |
ACPI_CONTROL_PREDICATE_EXECUTING) |
&& (walk_state->control_state->control. |
predicate_op == op)) { |
goto result_used; |
} |
break; |
default: |
/* Ignore other control opcodes */ |
break; |
} |
/* The general control opcode returns no result */ |
goto result_not_used; |
case AML_CLASS_CREATE: |
/* |
* These opcodes allow term_arg(s) as operands and therefore |
* the operands can be method calls. The result is used. |
*/ |
goto result_used; |
case AML_CLASS_NAMED_OBJECT: |
if ((op->common.parent->common.aml_opcode == AML_REGION_OP) || |
(op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) |
|| (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_VAR_PACKAGE_OP) |
|| (op->common.parent->common.aml_opcode == AML_BUFFER_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_INT_EVAL_SUBTREE_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_BANK_FIELD_OP)) { |
/* |
* These opcodes allow term_arg(s) as operands and therefore |
* the operands can be method calls. The result is used. |
*/ |
goto result_used; |
} |
goto result_not_used; |
default: |
/* |
* In all other cases. the parent will actually use the return |
* object, so keep it. |
*/ |
goto result_used; |
} |
result_used: |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Result of [%s] used by Parent [%s] Op=%p\n", |
acpi_ps_get_opcode_name(op->common.aml_opcode), |
acpi_ps_get_opcode_name(op->common.parent->common. |
aml_opcode), op)); |
return_UINT8(TRUE); |
result_not_used: |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Result of [%s] not used by Parent [%s] Op=%p\n", |
acpi_ps_get_opcode_name(op->common.aml_opcode), |
acpi_ps_get_opcode_name(op->common.parent->common. |
aml_opcode), op)); |
return_UINT8(FALSE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_delete_result_if_not_used |
* |
* PARAMETERS: op - Current parse Op |
* result_obj - Result of the operation |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Used after interpretation of an opcode. If there is an internal |
* result descriptor, check if the parent opcode will actually use |
* this result. If not, delete the result now so that it will |
* not become orphaned. |
* |
******************************************************************************/ |
void |
acpi_ds_delete_result_if_not_used(union acpi_parse_object *op, |
union acpi_operand_object *result_obj, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ds_delete_result_if_not_used, result_obj); |
if (!op) { |
ACPI_ERROR((AE_INFO, "Null Op")); |
return_VOID; |
} |
if (!result_obj) { |
return_VOID; |
} |
if (!acpi_ds_is_result_used(op, walk_state)) { |
/* Must pop the result stack (obj_desc should be equal to result_obj) */ |
status = acpi_ds_result_pop(&obj_desc, walk_state); |
if (ACPI_SUCCESS(status)) { |
acpi_ut_remove_reference(result_obj); |
} |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_resolve_operands |
* |
* PARAMETERS: walk_state - Current walk state with operands on stack |
* |
* RETURN: Status |
* |
* DESCRIPTION: Resolve all operands to their values. Used to prepare |
* arguments to a control method invocation (a call from one |
* method to another.) |
* |
******************************************************************************/ |
acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state) |
{ |
u32 i; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_PTR(ds_resolve_operands, walk_state); |
/* |
* Attempt to resolve each of the valid operands |
* Method arguments are passed by reference, not by value. This means |
* that the actual objects are passed, not copies of the objects. |
*/ |
for (i = 0; i < walk_state->num_operands; i++) { |
status = |
acpi_ex_resolve_to_value(&walk_state->operands[i], |
walk_state); |
if (ACPI_FAILURE(status)) { |
break; |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_clear_operands |
* |
* PARAMETERS: walk_state - Current walk state with operands on stack |
* |
* RETURN: None |
* |
* DESCRIPTION: Clear all operands on the current walk state operand stack. |
* |
******************************************************************************/ |
void acpi_ds_clear_operands(struct acpi_walk_state *walk_state) |
{ |
u32 i; |
ACPI_FUNCTION_TRACE_PTR(ds_clear_operands, walk_state); |
/* Remove a reference on each operand on the stack */ |
for (i = 0; i < walk_state->num_operands; i++) { |
/* |
* Remove a reference to all operands, including both |
* "Arguments" and "Targets". |
*/ |
acpi_ut_remove_reference(walk_state->operands[i]); |
walk_state->operands[i] = NULL; |
} |
walk_state->num_operands = 0; |
return_VOID; |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_operand |
* |
* PARAMETERS: walk_state - Current walk state |
* arg - Parse object for the argument |
* arg_index - Which argument (zero based) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Translate a parse tree object that is an argument to an AML |
* opcode to the equivalent interpreter object. This may include |
* looking up a name or entering a new name into the internal |
* namespace. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_create_operand(struct acpi_walk_state *walk_state, |
union acpi_parse_object *arg, u32 arg_index) |
{ |
acpi_status status = AE_OK; |
char *name_string; |
u32 name_length; |
union acpi_operand_object *obj_desc; |
union acpi_parse_object *parent_op; |
u16 opcode; |
acpi_interpreter_mode interpreter_mode; |
const struct acpi_opcode_info *op_info; |
ACPI_FUNCTION_TRACE_PTR(ds_create_operand, arg); |
/* A valid name must be looked up in the namespace */ |
if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && |
(arg->common.value.string) && |
!(arg->common.flags & ACPI_PARSEOP_IN_STACK)) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", |
arg)); |
/* Get the entire name string from the AML stream */ |
status = |
acpi_ex_get_name_string(ACPI_TYPE_ANY, |
arg->common.value.buffer, |
&name_string, &name_length); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* All prefixes have been handled, and the name is in name_string */ |
/* |
* Special handling for buffer_field declarations. This is a deferred |
* opcode that unfortunately defines the field name as the last |
* parameter instead of the first. We get here when we are performing |
* the deferred execution, so the actual name of the field is already |
* in the namespace. We don't want to attempt to look it up again |
* because we may be executing in a different scope than where the |
* actual opcode exists. |
*/ |
if ((walk_state->deferred_node) && |
(walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) |
&& (arg_index == |
(u32) ((walk_state->opcode == |
AML_CREATE_FIELD_OP) ? 3 : 2))) { |
obj_desc = |
ACPI_CAST_PTR(union acpi_operand_object, |
walk_state->deferred_node); |
status = AE_OK; |
} else { /* All other opcodes */ |
/* |
* Differentiate between a namespace "create" operation |
* versus a "lookup" operation (IMODE_LOAD_PASS2 vs. |
* IMODE_EXECUTE) in order to support the creation of |
* namespace objects during the execution of control methods. |
*/ |
parent_op = arg->common.parent; |
op_info = |
acpi_ps_get_opcode_info(parent_op->common. |
aml_opcode); |
if ((op_info->flags & AML_NSNODE) |
&& (parent_op->common.aml_opcode != |
AML_INT_METHODCALL_OP) |
&& (parent_op->common.aml_opcode != AML_REGION_OP) |
&& (parent_op->common.aml_opcode != |
AML_INT_NAMEPATH_OP)) { |
/* Enter name into namespace if not found */ |
interpreter_mode = ACPI_IMODE_LOAD_PASS2; |
} else { |
/* Return a failure if name not found */ |
interpreter_mode = ACPI_IMODE_EXECUTE; |
} |
status = |
acpi_ns_lookup(walk_state->scope_info, name_string, |
ACPI_TYPE_ANY, interpreter_mode, |
ACPI_NS_SEARCH_PARENT | |
ACPI_NS_DONT_OPEN_SCOPE, walk_state, |
ACPI_CAST_INDIRECT_PTR(struct |
acpi_namespace_node, |
&obj_desc)); |
/* |
* The only case where we pass through (ignore) a NOT_FOUND |
* error is for the cond_ref_of opcode. |
*/ |
if (status == AE_NOT_FOUND) { |
if (parent_op->common.aml_opcode == |
AML_COND_REF_OF_OP) { |
/* |
* For the Conditional Reference op, it's OK if |
* the name is not found; We just need a way to |
* indicate this to the interpreter, set the |
* object to the root |
*/ |
obj_desc = |
ACPI_CAST_PTR(union |
acpi_operand_object, |
acpi_gbl_root_node); |
status = AE_OK; |
} else if (parent_op->common.aml_opcode == |
AML_EXTERNAL_OP) { |
/* TBD: May only be temporary */ |
obj_desc = |
acpi_ut_create_string_object((acpi_size) name_length); |
strncpy(obj_desc->string.pointer, |
name_string, name_length); |
status = AE_OK; |
} else { |
/* |
* We just plain didn't find it -- which is a |
* very serious error at this point |
*/ |
status = AE_AML_NAME_NOT_FOUND; |
} |
} |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(name_string, status); |
} |
} |
/* Free the namestring created above */ |
ACPI_FREE(name_string); |
/* Check status from the lookup */ |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Put the resulting object onto the current object stack */ |
status = acpi_ds_obj_stack_push(obj_desc, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object |
(obj_desc, walk_state)); |
} else { |
/* Check for null name case */ |
if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && |
!(arg->common.flags & ACPI_PARSEOP_IN_STACK)) { |
/* |
* If the name is null, this means that this is an |
* optional result parameter that was not specified |
* in the original ASL. Create a Zero Constant for a |
* placeholder. (Store to a constant is a Noop.) |
*/ |
opcode = AML_ZERO_OP; /* Has no arguments! */ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Null namepath: Arg=%p\n", arg)); |
} else { |
opcode = arg->common.aml_opcode; |
} |
/* Get the object type of the argument */ |
op_info = acpi_ps_get_opcode_info(opcode); |
if (op_info->object_type == ACPI_TYPE_INVALID) { |
return_ACPI_STATUS(AE_NOT_IMPLEMENTED); |
} |
if ((op_info->flags & AML_HAS_RETVAL) |
|| (arg->common.flags & ACPI_PARSEOP_IN_STACK)) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Argument previously created, already stacked\n")); |
ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object |
(walk_state-> |
operands[walk_state->num_operands - |
1], walk_state)); |
/* |
* Use value that was already previously returned |
* by the evaluation of this argument |
*/ |
status = acpi_ds_result_pop(&obj_desc, walk_state); |
if (ACPI_FAILURE(status)) { |
/* |
* Only error is underflow, and this indicates |
* a missing or null operand! |
*/ |
ACPI_EXCEPTION((AE_INFO, status, |
"Missing or null operand")); |
return_ACPI_STATUS(status); |
} |
} else { |
/* Create an ACPI_INTERNAL_OBJECT for the argument */ |
obj_desc = |
acpi_ut_create_internal_object(op_info-> |
object_type); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Initialize the new object */ |
status = |
acpi_ds_init_object_from_op(walk_state, arg, opcode, |
&obj_desc); |
if (ACPI_FAILURE(status)) { |
acpi_ut_delete_object_desc(obj_desc); |
return_ACPI_STATUS(status); |
} |
} |
/* Put the operand object on the object stack */ |
status = acpi_ds_obj_stack_push(obj_desc, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object |
(obj_desc, walk_state)); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_operands |
* |
* PARAMETERS: walk_state - Current state |
* first_arg - First argument of a parser argument tree |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an operator's arguments from a parse tree format to |
* namespace objects and place those argument object on the object |
* stack in preparation for evaluation by the interpreter. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_create_operands(struct acpi_walk_state *walk_state, |
union acpi_parse_object *first_arg) |
{ |
acpi_status status = AE_OK; |
union acpi_parse_object *arg; |
union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS]; |
u32 arg_count = 0; |
u32 index = walk_state->num_operands; |
u32 i; |
ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg); |
/* Get all arguments in the list */ |
arg = first_arg; |
while (arg) { |
if (index >= ACPI_OBJ_NUM_OPERANDS) { |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
arguments[index] = arg; |
walk_state->operands[index] = NULL; |
/* Move on to next argument, if any */ |
arg = arg->common.next; |
arg_count++; |
index++; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"NumOperands %d, ArgCount %d, Index %d\n", |
walk_state->num_operands, arg_count, index)); |
/* Create the interpreter arguments, in reverse order */ |
index--; |
for (i = 0; i < arg_count; i++) { |
arg = arguments[index]; |
walk_state->operand_index = (u8)index; |
status = acpi_ds_create_operand(walk_state, arg, index); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Created Arg #%u (%p) %u args total\n", |
index, arg, arg_count)); |
index--; |
} |
return_ACPI_STATUS(status); |
cleanup: |
/* |
* We must undo everything done above; meaning that we must |
* pop everything off of the operand stack and delete those |
* objects |
*/ |
acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state); |
ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index)); |
return_ACPI_STATUS(status); |
} |
/***************************************************************************** |
* |
* FUNCTION: acpi_ds_evaluate_name_path |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk, |
* the opcode of current operation should be |
* AML_INT_NAMEPATH_OP |
* |
* RETURN: Status |
* |
* DESCRIPTION: Translate the -name_path- parse tree object to the equivalent |
* interpreter object, convert it to value, if needed, duplicate |
* it, if needed, and push it onto the current result stack. |
* |
****************************************************************************/ |
acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_parse_object *op = walk_state->op; |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *new_obj_desc; |
u8 type; |
ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state); |
if (!op->common.parent) { |
/* This happens after certain exception processing */ |
goto exit; |
} |
if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || |
(op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) || |
(op->common.parent->common.aml_opcode == AML_REF_OF_OP)) { |
/* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */ |
goto exit; |
} |
status = acpi_ds_create_operand(walk_state, op, 0); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (op->common.flags & ACPI_PARSEOP_TARGET) { |
new_obj_desc = *operand; |
goto push_result; |
} |
type = (*operand)->common.type; |
status = acpi_ex_resolve_to_value(operand, walk_state); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
if (type == ACPI_TYPE_INTEGER) { |
/* It was incremented by acpi_ex_resolve_to_value */ |
acpi_ut_remove_reference(*operand); |
status = |
acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
} else { |
/* |
* The object either was anew created or is |
* a Namespace node - don't decrement it. |
*/ |
new_obj_desc = *operand; |
} |
/* Cleanup for name-path operand */ |
status = acpi_ds_obj_stack_pop(1, walk_state); |
if (ACPI_FAILURE(status)) { |
walk_state->result_obj = new_obj_desc; |
goto exit; |
} |
push_result: |
walk_state->result_obj = new_obj_desc; |
status = acpi_ds_result_push(walk_state->result_obj, walk_state); |
if (ACPI_SUCCESS(status)) { |
/* Force to take it from stack */ |
op->common.flags |= ACPI_PARSEOP_IN_STACK; |
} |
exit: |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dswexec.c |
---|
0,0 → 1,759 |
/****************************************************************************** |
* |
* Module Name: dswexec - Dispatcher method execution callbacks; |
* dispatch to interpreter. |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dswexec") |
/* |
* Dispatch table for opcode classes |
*/ |
static acpi_execute_op acpi_gbl_op_type_dispatch[] = { |
acpi_ex_opcode_0A_0T_1R, |
acpi_ex_opcode_1A_0T_0R, |
acpi_ex_opcode_1A_0T_1R, |
acpi_ex_opcode_1A_1T_0R, |
acpi_ex_opcode_1A_1T_1R, |
acpi_ex_opcode_2A_0T_0R, |
acpi_ex_opcode_2A_0T_1R, |
acpi_ex_opcode_2A_1T_1R, |
acpi_ex_opcode_2A_2T_1R, |
acpi_ex_opcode_3A_0T_0R, |
acpi_ex_opcode_3A_1T_1R, |
acpi_ex_opcode_6A_0T_1R |
}; |
/***************************************************************************** |
* |
* FUNCTION: acpi_ds_get_predicate_value |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* result_obj - if non-zero, pop result from result stack |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get the result of a predicate evaluation |
* |
****************************************************************************/ |
acpi_status |
acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, |
union acpi_operand_object *result_obj) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *local_obj_desc = NULL; |
ACPI_FUNCTION_TRACE_PTR(ds_get_predicate_value, walk_state); |
walk_state->control_state->common.state = 0; |
if (result_obj) { |
status = acpi_ds_result_pop(&obj_desc, walk_state); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not get result from predicate evaluation")); |
return_ACPI_STATUS(status); |
} |
} else { |
status = acpi_ds_create_operand(walk_state, walk_state->op, 0); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = |
acpi_ex_resolve_to_value(&walk_state->operands[0], |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
obj_desc = walk_state->operands[0]; |
} |
if (!obj_desc) { |
ACPI_ERROR((AE_INFO, |
"No predicate ObjDesc=%p State=%p", |
obj_desc, walk_state)); |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
/* |
* Result of predicate evaluation must be an Integer |
* object. Implicitly convert the argument if necessary. |
*/ |
status = acpi_ex_convert_to_integer(obj_desc, &local_obj_desc, 16); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
if (local_obj_desc->common.type != ACPI_TYPE_INTEGER) { |
ACPI_ERROR((AE_INFO, |
"Bad predicate (not an integer) ObjDesc=%p State=%p Type=0x%X", |
obj_desc, walk_state, obj_desc->common.type)); |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
/* Truncate the predicate to 32-bits if necessary */ |
(void)acpi_ex_truncate_for32bit_table(local_obj_desc); |
/* |
* Save the result of the predicate evaluation on |
* the control stack |
*/ |
if (local_obj_desc->integer.value) { |
walk_state->control_state->common.value = TRUE; |
} else { |
/* |
* Predicate is FALSE, we will just toss the |
* rest of the package |
*/ |
walk_state->control_state->common.value = FALSE; |
status = AE_CTRL_FALSE; |
} |
/* Predicate can be used for an implicit return value */ |
(void)acpi_ds_do_implicit_return(local_obj_desc, walk_state, TRUE); |
cleanup: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n", |
walk_state->control_state->common.value, |
walk_state->op)); |
/* Break to debugger to display result */ |
ACPI_DEBUGGER_EXEC(acpi_db_display_result_object |
(local_obj_desc, walk_state)); |
/* |
* Delete the predicate result object (we know that |
* we don't need it anymore) |
*/ |
if (local_obj_desc != obj_desc) { |
acpi_ut_remove_reference(local_obj_desc); |
} |
acpi_ut_remove_reference(obj_desc); |
walk_state->control_state->common.state = ACPI_CONTROL_NORMAL; |
return_ACPI_STATUS(status); |
} |
/***************************************************************************** |
* |
* FUNCTION: acpi_ds_exec_begin_op |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* out_op - Where to return op if a new one is created |
* |
* RETURN: Status |
* |
* DESCRIPTION: Descending callback used during the execution of control |
* methods. This is where most operators and operands are |
* dispatched to the interpreter. |
* |
****************************************************************************/ |
acpi_status |
acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object **out_op) |
{ |
union acpi_parse_object *op; |
acpi_status status = AE_OK; |
u32 opcode_class; |
ACPI_FUNCTION_TRACE_PTR(ds_exec_begin_op, walk_state); |
op = walk_state->op; |
if (!op) { |
status = acpi_ds_load2_begin_op(walk_state, out_op); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
op = *out_op; |
walk_state->op = op; |
walk_state->opcode = op->common.aml_opcode; |
walk_state->op_info = |
acpi_ps_get_opcode_info(op->common.aml_opcode); |
if (acpi_ns_opens_scope(walk_state->op_info->object_type)) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"(%s) Popping scope for Op %p\n", |
acpi_ut_get_type_name(walk_state-> |
op_info-> |
object_type), |
op)); |
status = acpi_ds_scope_stack_pop(walk_state); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
} |
} |
if (op == walk_state->origin) { |
if (out_op) { |
*out_op = op; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* If the previous opcode was a conditional, this opcode |
* must be the beginning of the associated predicate. |
* Save this knowledge in the current scope descriptor |
*/ |
if ((walk_state->control_state) && |
(walk_state->control_state->common.state == |
ACPI_CONTROL_CONDITIONAL_EXECUTING)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Exec predicate Op=%p State=%p\n", op, |
walk_state)); |
walk_state->control_state->common.state = |
ACPI_CONTROL_PREDICATE_EXECUTING; |
/* Save start of predicate */ |
walk_state->control_state->control.predicate_op = op; |
} |
opcode_class = walk_state->op_info->class; |
/* We want to send namepaths to the load code */ |
if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { |
opcode_class = AML_CLASS_NAMED_OBJECT; |
} |
/* |
* Handle the opcode based upon the opcode type |
*/ |
switch (opcode_class) { |
case AML_CLASS_CONTROL: |
status = acpi_ds_exec_begin_control_op(walk_state, op); |
break; |
case AML_CLASS_NAMED_OBJECT: |
if (walk_state->walk_type & ACPI_WALK_METHOD) { |
/* |
* Found a named object declaration during method execution; |
* we must enter this object into the namespace. The created |
* object is temporary and will be deleted upon completion of |
* the execution of this method. |
* |
* Note 10/2010: Except for the Scope() op. This opcode does |
* not actually create a new object, it refers to an existing |
* object. However, for Scope(), we want to indeed open a |
* new scope. |
*/ |
if (op->common.aml_opcode != AML_SCOPE_OP) { |
status = |
acpi_ds_load2_begin_op(walk_state, NULL); |
} else { |
status = |
acpi_ds_scope_stack_push(op->named.node, |
op->named.node-> |
type, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} |
break; |
case AML_CLASS_EXECUTE: |
case AML_CLASS_CREATE: |
break; |
default: |
break; |
} |
/* Nothing to do here during method execution */ |
return_ACPI_STATUS(status); |
error_exit: |
status = acpi_ds_method_error(status, walk_state); |
return_ACPI_STATUS(status); |
} |
/***************************************************************************** |
* |
* FUNCTION: acpi_ds_exec_end_op |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* |
* RETURN: Status |
* |
* DESCRIPTION: Ascending callback used during the execution of control |
* methods. The only thing we really need to do here is to |
* notice the beginning of IF, ELSE, and WHILE blocks. |
* |
****************************************************************************/ |
acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) |
{ |
union acpi_parse_object *op; |
acpi_status status = AE_OK; |
u32 op_type; |
u32 op_class; |
union acpi_parse_object *next_op; |
union acpi_parse_object *first_arg; |
ACPI_FUNCTION_TRACE_PTR(ds_exec_end_op, walk_state); |
op = walk_state->op; |
op_type = walk_state->op_info->type; |
op_class = walk_state->op_info->class; |
if (op_class == AML_CLASS_UNKNOWN) { |
ACPI_ERROR((AE_INFO, "Unknown opcode 0x%X", |
op->common.aml_opcode)); |
return_ACPI_STATUS(AE_NOT_IMPLEMENTED); |
} |
first_arg = op->common.value.arg; |
/* Init the walk state */ |
walk_state->num_operands = 0; |
walk_state->operand_index = 0; |
walk_state->return_desc = NULL; |
walk_state->result_obj = NULL; |
/* Call debugger for single step support (DEBUG build only) */ |
ACPI_DEBUGGER_EXEC(status = |
acpi_db_single_step(walk_state, op, op_class)); |
ACPI_DEBUGGER_EXEC(if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status);} |
) ; |
/* Decode the Opcode Class */ |
switch (op_class) { |
case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */ |
if (walk_state->opcode == AML_INT_NAMEPATH_OP) { |
status = acpi_ds_evaluate_name_path(walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
} |
break; |
case AML_CLASS_EXECUTE: /* Most operators with arguments */ |
/* Build resolved operand stack */ |
status = acpi_ds_create_operands(walk_state, first_arg); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* |
* All opcodes require operand resolution, with the only exceptions |
* being the object_type and size_of operators. |
*/ |
if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) { |
/* Resolve all operands */ |
status = acpi_ex_resolve_operands(walk_state->opcode, |
&(walk_state-> |
operands |
[walk_state-> |
num_operands - 1]), |
walk_state); |
} |
if (ACPI_SUCCESS(status)) { |
/* |
* Dispatch the request to the appropriate interpreter handler |
* routine. There is one routine per opcode "type" based upon the |
* number of opcode arguments and return type. |
*/ |
status = |
acpi_gbl_op_type_dispatch[op_type] (walk_state); |
} else { |
/* |
* Treat constructs of the form "Store(LocalX,LocalX)" as noops when the |
* Local is uninitialized. |
*/ |
if ((status == AE_AML_UNINITIALIZED_LOCAL) && |
(walk_state->opcode == AML_STORE_OP) && |
(walk_state->operands[0]->common.type == |
ACPI_TYPE_LOCAL_REFERENCE) |
&& (walk_state->operands[1]->common.type == |
ACPI_TYPE_LOCAL_REFERENCE) |
&& (walk_state->operands[0]->reference.class == |
walk_state->operands[1]->reference.class) |
&& (walk_state->operands[0]->reference.value == |
walk_state->operands[1]->reference.value)) { |
status = AE_OK; |
} else { |
ACPI_EXCEPTION((AE_INFO, status, |
"While resolving operands for [%s]", |
acpi_ps_get_opcode_name |
(walk_state->opcode))); |
} |
} |
/* Always delete the argument objects and clear the operand stack */ |
acpi_ds_clear_operands(walk_state); |
/* |
* If a result object was returned from above, push it on the |
* current result stack |
*/ |
if (ACPI_SUCCESS(status) && walk_state->result_obj) { |
status = |
acpi_ds_result_push(walk_state->result_obj, |
walk_state); |
} |
break; |
default: |
switch (op_type) { |
case AML_TYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */ |
/* 1 Operand, 0 external_result, 0 internal_result */ |
status = acpi_ds_exec_end_control_op(walk_state, op); |
break; |
case AML_TYPE_METHOD_CALL: |
/* |
* If the method is referenced from within a package |
* declaration, it is not a invocation of the method, just |
* a reference to it. |
*/ |
if ((op->asl.parent) && |
((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) |
|| (op->asl.parent->asl.aml_opcode == |
AML_VAR_PACKAGE_OP))) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Method Reference in a Package, Op=%p\n", |
op)); |
op->common.node = |
(struct acpi_namespace_node *)op->asl.value. |
arg->asl.node; |
acpi_ut_add_reference(op->asl.value.arg->asl. |
node->object); |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Method invocation, Op=%p\n", op)); |
/* |
* (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains |
* the method Node pointer |
*/ |
/* next_op points to the op that holds the method name */ |
next_op = first_arg; |
/* next_op points to first argument op */ |
next_op = next_op->common.next; |
/* |
* Get the method's arguments and put them on the operand stack |
*/ |
status = acpi_ds_create_operands(walk_state, next_op); |
if (ACPI_FAILURE(status)) { |
break; |
} |
/* |
* Since the operands will be passed to another control method, |
* we must resolve all local references here (Local variables, |
* arguments to *this* method, etc.) |
*/ |
status = acpi_ds_resolve_operands(walk_state); |
if (ACPI_FAILURE(status)) { |
/* On error, clear all resolved operands */ |
acpi_ds_clear_operands(walk_state); |
break; |
} |
/* |
* Tell the walk loop to preempt this running method and |
* execute the new method |
*/ |
status = AE_CTRL_TRANSFER; |
/* |
* Return now; we don't want to disturb anything, |
* especially the operand count! |
*/ |
return_ACPI_STATUS(status); |
case AML_TYPE_CREATE_FIELD: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Executing CreateField Buffer/Index Op=%p\n", |
op)); |
status = acpi_ds_load2_end_op(walk_state); |
if (ACPI_FAILURE(status)) { |
break; |
} |
status = |
acpi_ds_eval_buffer_field_operands(walk_state, op); |
break; |
case AML_TYPE_CREATE_OBJECT: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Executing CreateObject (Buffer/Package) Op=%p\n", |
op)); |
switch (op->common.parent->common.aml_opcode) { |
case AML_NAME_OP: |
/* |
* Put the Node on the object stack (Contains the ACPI Name |
* of this object) |
*/ |
walk_state->operands[0] = |
(void *)op->common.parent->common.node; |
walk_state->num_operands = 1; |
status = acpi_ds_create_node(walk_state, |
op->common.parent-> |
common.node, |
op->common.parent); |
if (ACPI_FAILURE(status)) { |
break; |
} |
/* Fall through */ |
/*lint -fallthrough */ |
case AML_INT_EVAL_SUBTREE_OP: |
status = |
acpi_ds_eval_data_object_operands |
(walk_state, op, |
acpi_ns_get_attached_object(op->common. |
parent->common. |
node)); |
break; |
default: |
status = |
acpi_ds_eval_data_object_operands |
(walk_state, op, NULL); |
break; |
} |
/* |
* If a result object was returned from above, push it on the |
* current result stack |
*/ |
if (walk_state->result_obj) { |
status = |
acpi_ds_result_push(walk_state->result_obj, |
walk_state); |
} |
break; |
case AML_TYPE_NAMED_FIELD: |
case AML_TYPE_NAMED_COMPLEX: |
case AML_TYPE_NAMED_SIMPLE: |
case AML_TYPE_NAMED_NO_OBJ: |
status = acpi_ds_load2_end_op(walk_state); |
if (ACPI_FAILURE(status)) { |
break; |
} |
if (op->common.aml_opcode == AML_REGION_OP) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Executing OpRegion Address/Length Op=%p\n", |
op)); |
status = |
acpi_ds_eval_region_operands(walk_state, |
op); |
if (ACPI_FAILURE(status)) { |
break; |
} |
} else if (op->common.aml_opcode == AML_DATA_REGION_OP) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Executing DataTableRegion Strings Op=%p\n", |
op)); |
status = |
acpi_ds_eval_table_region_operands |
(walk_state, op); |
if (ACPI_FAILURE(status)) { |
break; |
} |
} else if (op->common.aml_opcode == AML_BANK_FIELD_OP) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Executing BankField Op=%p\n", |
op)); |
status = |
acpi_ds_eval_bank_field_operands(walk_state, |
op); |
if (ACPI_FAILURE(status)) { |
break; |
} |
} |
break; |
case AML_TYPE_UNDEFINED: |
ACPI_ERROR((AE_INFO, |
"Undefined opcode type Op=%p", op)); |
return_ACPI_STATUS(AE_NOT_IMPLEMENTED); |
case AML_TYPE_BOGUS: |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Internal opcode=%X type Op=%p\n", |
walk_state->opcode, op)); |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unimplemented opcode, class=0x%X type=0x%X Opcode=0x%X Op=%p", |
op_class, op_type, op->common.aml_opcode, |
op)); |
status = AE_NOT_IMPLEMENTED; |
break; |
} |
} |
/* |
* ACPI 2.0 support for 64-bit integers: Truncate numeric |
* result value if we are executing from a 32-bit ACPI table |
*/ |
(void)acpi_ex_truncate_for32bit_table(walk_state->result_obj); |
/* |
* Check if we just completed the evaluation of a |
* conditional predicate |
*/ |
if ((ACPI_SUCCESS(status)) && |
(walk_state->control_state) && |
(walk_state->control_state->common.state == |
ACPI_CONTROL_PREDICATE_EXECUTING) && |
(walk_state->control_state->control.predicate_op == op)) { |
status = |
acpi_ds_get_predicate_value(walk_state, |
walk_state->result_obj); |
walk_state->result_obj = NULL; |
} |
cleanup: |
if (walk_state->result_obj) { |
/* Break to debugger to display result */ |
ACPI_DEBUGGER_EXEC(acpi_db_display_result_object |
(walk_state->result_obj, walk_state)); |
/* |
* Delete the result op if and only if: |
* Parent will not use the result -- such as any |
* non-nested type2 op in a method (parent will be method) |
*/ |
acpi_ds_delete_result_if_not_used(op, walk_state->result_obj, |
walk_state); |
} |
#ifdef _UNDER_DEVELOPMENT |
if (walk_state->parser_state.aml == walk_state->parser_state.aml_end) { |
acpi_db_method_end(walk_state); |
} |
#endif |
/* Invoke exception handler on error */ |
if (ACPI_FAILURE(status)) { |
status = acpi_ds_method_error(status, walk_state); |
} |
/* Always clear the object stack */ |
walk_state->num_operands = 0; |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dswload.c |
---|
0,0 → 1,579 |
/****************************************************************************** |
* |
* Module Name: dswload - Dispatcher first pass namespace load callbacks |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#ifdef ACPI_ASL_COMPILER |
#include "acdisasm.h" |
#endif |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dswload") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_init_callbacks |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* pass_number - 1, 2, or 3 |
* |
* RETURN: Status |
* |
* DESCRIPTION: Init walk state callbacks |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number) |
{ |
switch (pass_number) { |
case 0: |
/* Parse only - caller will setup callbacks */ |
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | |
ACPI_PARSE_DELETE_TREE | ACPI_PARSE_DISASSEMBLE; |
walk_state->descending_callback = NULL; |
walk_state->ascending_callback = NULL; |
break; |
case 1: |
/* Load pass 1 */ |
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | |
ACPI_PARSE_DELETE_TREE; |
walk_state->descending_callback = acpi_ds_load1_begin_op; |
walk_state->ascending_callback = acpi_ds_load1_end_op; |
break; |
case 2: |
/* Load pass 2 */ |
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | |
ACPI_PARSE_DELETE_TREE; |
walk_state->descending_callback = acpi_ds_load2_begin_op; |
walk_state->ascending_callback = acpi_ds_load2_end_op; |
break; |
case 3: |
/* Execution pass */ |
#ifndef ACPI_NO_METHOD_EXECUTION |
walk_state->parse_flags |= ACPI_PARSE_EXECUTE | |
ACPI_PARSE_DELETE_TREE; |
walk_state->descending_callback = acpi_ds_exec_begin_op; |
walk_state->ascending_callback = acpi_ds_exec_end_op; |
#endif |
break; |
default: |
return (AE_BAD_PARAMETER); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_load1_begin_op |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* out_op - Where to return op if a new one is created |
* |
* RETURN: Status |
* |
* DESCRIPTION: Descending callback used during the loading of ACPI tables. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, |
union acpi_parse_object ** out_op) |
{ |
union acpi_parse_object *op; |
struct acpi_namespace_node *node; |
acpi_status status; |
acpi_object_type object_type; |
char *path; |
u32 flags; |
ACPI_FUNCTION_TRACE(ds_load1_begin_op); |
op = walk_state->op; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, |
walk_state)); |
/* We are only interested in opcodes that have an associated name */ |
if (op) { |
if (!(walk_state->op_info->flags & AML_NAMED)) { |
*out_op = op; |
return_ACPI_STATUS(AE_OK); |
} |
/* Check if this object has already been installed in the namespace */ |
if (op->common.node) { |
*out_op = op; |
return_ACPI_STATUS(AE_OK); |
} |
} |
path = acpi_ps_get_next_namestring(&walk_state->parser_state); |
/* Map the raw opcode into an internal object type */ |
object_type = walk_state->op_info->object_type; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"State=%p Op=%p [%s]\n", walk_state, op, |
acpi_ut_get_type_name(object_type))); |
switch (walk_state->opcode) { |
case AML_SCOPE_OP: |
/* |
* The target name of the Scope() operator must exist at this point so |
* that we can actually open the scope to enter new names underneath it. |
* Allow search-to-root for single namesegs. |
*/ |
status = |
acpi_ns_lookup(walk_state->scope_info, path, object_type, |
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, |
walk_state, &(node)); |
#ifdef ACPI_ASL_COMPILER |
if (status == AE_NOT_FOUND) { |
/* |
* Table disassembly: |
* Target of Scope() not found. Generate an External for it, and |
* insert the name into the namespace. |
*/ |
acpi_dm_add_op_to_external_list(op, path, |
ACPI_TYPE_DEVICE, 0, 0); |
status = |
acpi_ns_lookup(walk_state->scope_info, path, |
object_type, ACPI_IMODE_LOAD_PASS1, |
ACPI_NS_SEARCH_PARENT, walk_state, |
&node); |
} |
#endif |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(path, status); |
return_ACPI_STATUS(status); |
} |
/* |
* Check to make sure that the target is |
* one of the opcodes that actually opens a scope |
*/ |
switch (node->type) { |
case ACPI_TYPE_ANY: |
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_POWER: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_THERMAL: |
/* These are acceptable types */ |
break; |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
/* |
* These types we will allow, but we will change the type. |
* This enables some existing code of the form: |
* |
* Name (DEB, 0) |
* Scope (DEB) { ... } |
* |
* Note: silently change the type here. On the second pass, |
* we will report a warning |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Type override - [%4.4s] had invalid type (%s) " |
"for Scope operator, changed to type ANY\n", |
acpi_ut_get_node_name(node), |
acpi_ut_get_type_name(node->type))); |
node->type = ACPI_TYPE_ANY; |
walk_state->scope_info->common.value = ACPI_TYPE_ANY; |
break; |
case ACPI_TYPE_METHOD: |
/* |
* Allow scope change to root during execution of module-level |
* code. Root is typed METHOD during this time. |
*/ |
if ((node == acpi_gbl_root_node) && |
(walk_state-> |
parse_flags & ACPI_PARSE_MODULE_LEVEL)) { |
break; |
} |
/*lint -fallthrough */ |
default: |
/* All other types are an error */ |
ACPI_ERROR((AE_INFO, |
"Invalid type (%s) for target of " |
"Scope operator [%4.4s] (Cannot override)", |
acpi_ut_get_type_name(node->type), |
acpi_ut_get_node_name(node))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
break; |
default: |
/* |
* For all other named opcodes, we will enter the name into |
* the namespace. |
* |
* Setup the search flags. |
* Since we are entering a name into the namespace, we do not want to |
* enable the search-to-root upsearch. |
* |
* There are only two conditions where it is acceptable that the name |
* already exists: |
* 1) the Scope() operator can reopen a scoping object that was |
* previously defined (Scope, Method, Device, etc.) |
* 2) Whenever we are parsing a deferred opcode (op_region, Buffer, |
* buffer_field, or Package), the name of the object is already |
* in the namespace. |
*/ |
if (walk_state->deferred_node) { |
/* This name is already in the namespace, get the node */ |
node = walk_state->deferred_node; |
status = AE_OK; |
break; |
} |
/* |
* If we are executing a method, do not create any namespace objects |
* during the load phase, only during execution. |
*/ |
if (walk_state->method_node) { |
node = NULL; |
status = AE_OK; |
break; |
} |
flags = ACPI_NS_NO_UPSEARCH; |
if ((walk_state->opcode != AML_SCOPE_OP) && |
(!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) { |
if (walk_state->namespace_override) { |
flags |= ACPI_NS_OVERRIDE_IF_FOUND; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"[%s] Override allowed\n", |
acpi_ut_get_type_name |
(object_type))); |
} else { |
flags |= ACPI_NS_ERROR_IF_FOUND; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"[%s] Cannot already exist\n", |
acpi_ut_get_type_name |
(object_type))); |
} |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"[%s] Both Find or Create allowed\n", |
acpi_ut_get_type_name(object_type))); |
} |
/* |
* Enter the named type into the internal namespace. We enter the name |
* as we go downward in the parse tree. Any necessary subobjects that |
* involve arguments to the opcode must be created as we go back up the |
* parse tree later. |
*/ |
status = |
acpi_ns_lookup(walk_state->scope_info, path, object_type, |
ACPI_IMODE_LOAD_PASS1, flags, walk_state, |
&node); |
if (ACPI_FAILURE(status)) { |
if (status == AE_ALREADY_EXISTS) { |
/* The name already exists in this scope */ |
if (node->flags & ANOBJ_IS_EXTERNAL) { |
/* |
* Allow one create on an object or segment that was |
* previously declared External |
*/ |
node->flags &= ~ANOBJ_IS_EXTERNAL; |
node->type = (u8) object_type; |
/* Just retyped a node, probably will need to open a scope */ |
if (acpi_ns_opens_scope(object_type)) { |
status = |
acpi_ds_scope_stack_push |
(node, object_type, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS |
(status); |
} |
} |
status = AE_OK; |
} |
} |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(path, status); |
return_ACPI_STATUS(status); |
} |
} |
break; |
} |
/* Common exit */ |
if (!op) { |
/* Create a new op */ |
op = acpi_ps_alloc_op(walk_state->opcode, walk_state->aml); |
if (!op) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
} |
/* Initialize the op */ |
#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) |
op->named.path = ACPI_CAST_PTR(u8, path); |
#endif |
if (node) { |
/* |
* Put the Node in the "op" object that the parser uses, so we |
* can get it again quickly when this scope is closed |
*/ |
op->common.node = node; |
op->named.name = node->name.integer; |
} |
acpi_ps_append_arg(acpi_ps_get_parent_scope(&walk_state->parser_state), |
op); |
*out_op = op; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_load1_end_op |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* |
* RETURN: Status |
* |
* DESCRIPTION: Ascending callback used during the loading of the namespace, |
* both control methods and everything else. |
* |
******************************************************************************/ |
acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) |
{ |
union acpi_parse_object *op; |
acpi_object_type object_type; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ds_load1_end_op); |
op = walk_state->op; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, |
walk_state)); |
/* We are only interested in opcodes that have an associated name */ |
if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Get the object type to determine if we should pop the scope */ |
object_type = walk_state->op_info->object_type; |
#ifndef ACPI_NO_METHOD_EXECUTION |
if (walk_state->op_info->flags & AML_FIELD) { |
/* |
* If we are executing a method, do not create any namespace objects |
* during the load phase, only during execution. |
*/ |
if (!walk_state->method_node) { |
if (walk_state->opcode == AML_FIELD_OP || |
walk_state->opcode == AML_BANK_FIELD_OP || |
walk_state->opcode == AML_INDEX_FIELD_OP) { |
status = |
acpi_ds_init_field_objects(op, walk_state); |
} |
} |
return_ACPI_STATUS(status); |
} |
/* |
* If we are executing a method, do not create any namespace objects |
* during the load phase, only during execution. |
*/ |
if (!walk_state->method_node) { |
if (op->common.aml_opcode == AML_REGION_OP) { |
status = |
acpi_ex_create_region(op->named.data, |
op->named.length, |
(acpi_adr_space_type) ((op-> |
common. |
value. |
arg)-> |
common. |
value. |
integer), |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} else if (op->common.aml_opcode == AML_DATA_REGION_OP) { |
status = |
acpi_ex_create_region(op->named.data, |
op->named.length, |
ACPI_ADR_SPACE_DATA_TABLE, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} |
#endif |
if (op->common.aml_opcode == AML_NAME_OP) { |
/* For Name opcode, get the object type from the argument */ |
if (op->common.value.arg) { |
object_type = (acpi_ps_get_opcode_info((op->common. |
value.arg)-> |
common. |
aml_opcode))-> |
object_type; |
/* Set node type if we have a namespace node */ |
if (op->common.node) { |
op->common.node->type = (u8) object_type; |
} |
} |
} |
/* |
* If we are executing a method, do not create any namespace objects |
* during the load phase, only during execution. |
*/ |
if (!walk_state->method_node) { |
if (op->common.aml_opcode == AML_METHOD_OP) { |
/* |
* method_op pkg_length name_string method_flags term_list |
* |
* Note: We must create the method node/object pair as soon as we |
* see the method declaration. This allows later pass1 parsing |
* of invocations of the method (need to know the number of |
* arguments.) |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"LOADING-Method: State=%p Op=%p NamedObj=%p\n", |
walk_state, op, op->named.node)); |
if (!acpi_ns_get_attached_object(op->named.node)) { |
walk_state->operands[0] = |
ACPI_CAST_PTR(void, op->named.node); |
walk_state->num_operands = 1; |
status = |
acpi_ds_create_operands(walk_state, |
op->common.value. |
arg); |
if (ACPI_SUCCESS(status)) { |
status = |
acpi_ex_create_method(op->named. |
data, |
op->named. |
length, |
walk_state); |
} |
walk_state->operands[0] = NULL; |
walk_state->num_operands = 0; |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} |
} |
/* Pop the scope stack (only if loading a table) */ |
if (!walk_state->method_node && acpi_ns_opens_scope(object_type)) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"(%s): Popping scope for Op %p\n", |
acpi_ut_get_type_name(object_type), op)); |
status = acpi_ds_scope_stack_pop(walk_state); |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dswload2.c |
---|
0,0 → 1,738 |
/****************************************************************************** |
* |
* Module Name: dswload2 - Dispatcher second pass namespace load callbacks |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dswload2") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_load2_begin_op |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* out_op - Wher to return op if a new one is created |
* |
* RETURN: Status |
* |
* DESCRIPTION: Descending callback used during the loading of ACPI tables. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object **out_op) |
{ |
union acpi_parse_object *op; |
struct acpi_namespace_node *node; |
acpi_status status; |
acpi_object_type object_type; |
char *buffer_ptr; |
u32 flags; |
ACPI_FUNCTION_TRACE(ds_load2_begin_op); |
op = walk_state->op; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, |
walk_state)); |
if (op) { |
if ((walk_state->control_state) && |
(walk_state->control_state->common.state == |
ACPI_CONTROL_CONDITIONAL_EXECUTING)) { |
/* We are executing a while loop outside of a method */ |
status = acpi_ds_exec_begin_op(walk_state, out_op); |
return_ACPI_STATUS(status); |
} |
/* We only care about Namespace opcodes here */ |
if ((!(walk_state->op_info->flags & AML_NSOPCODE) && |
(walk_state->opcode != AML_INT_NAMEPATH_OP)) || |
(!(walk_state->op_info->flags & AML_NAMED))) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Get the name we are going to enter or lookup in the namespace */ |
if (walk_state->opcode == AML_INT_NAMEPATH_OP) { |
/* For Namepath op, get the path string */ |
buffer_ptr = op->common.value.string; |
if (!buffer_ptr) { |
/* No name, just exit */ |
return_ACPI_STATUS(AE_OK); |
} |
} else { |
/* Get name from the op */ |
buffer_ptr = ACPI_CAST_PTR(char, &op->named.name); |
} |
} else { |
/* Get the namestring from the raw AML */ |
buffer_ptr = |
acpi_ps_get_next_namestring(&walk_state->parser_state); |
} |
/* Map the opcode into an internal object type */ |
object_type = walk_state->op_info->object_type; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"State=%p Op=%p Type=%X\n", walk_state, op, |
object_type)); |
switch (walk_state->opcode) { |
case AML_FIELD_OP: |
case AML_BANK_FIELD_OP: |
case AML_INDEX_FIELD_OP: |
node = NULL; |
status = AE_OK; |
break; |
case AML_INT_NAMEPATH_OP: |
/* |
* The name_path is an object reference to an existing object. |
* Don't enter the name into the namespace, but look it up |
* for use later. |
*/ |
status = |
acpi_ns_lookup(walk_state->scope_info, buffer_ptr, |
object_type, ACPI_IMODE_EXECUTE, |
ACPI_NS_SEARCH_PARENT, walk_state, &(node)); |
break; |
case AML_SCOPE_OP: |
/* Special case for Scope(\) -> refers to the Root node */ |
if (op && (op->named.node == acpi_gbl_root_node)) { |
node = op->named.node; |
status = |
acpi_ds_scope_stack_push(node, object_type, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} else { |
/* |
* The Path is an object reference to an existing object. |
* Don't enter the name into the namespace, but look it up |
* for use later. |
*/ |
status = |
acpi_ns_lookup(walk_state->scope_info, buffer_ptr, |
object_type, ACPI_IMODE_EXECUTE, |
ACPI_NS_SEARCH_PARENT, walk_state, |
&(node)); |
if (ACPI_FAILURE(status)) { |
#ifdef ACPI_ASL_COMPILER |
if (status == AE_NOT_FOUND) { |
status = AE_OK; |
} else { |
ACPI_ERROR_NAMESPACE(buffer_ptr, |
status); |
} |
#else |
ACPI_ERROR_NAMESPACE(buffer_ptr, status); |
#endif |
return_ACPI_STATUS(status); |
} |
} |
/* |
* We must check to make sure that the target is |
* one of the opcodes that actually opens a scope |
*/ |
switch (node->type) { |
case ACPI_TYPE_ANY: |
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_POWER: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_THERMAL: |
/* These are acceptable types */ |
break; |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
/* |
* These types we will allow, but we will change the type. |
* This enables some existing code of the form: |
* |
* Name (DEB, 0) |
* Scope (DEB) { ... } |
*/ |
ACPI_WARNING((AE_INFO, |
"Type override - [%4.4s] had invalid type (%s) " |
"for Scope operator, changed to type ANY", |
acpi_ut_get_node_name(node), |
acpi_ut_get_type_name(node->type))); |
node->type = ACPI_TYPE_ANY; |
walk_state->scope_info->common.value = ACPI_TYPE_ANY; |
break; |
case ACPI_TYPE_METHOD: |
/* |
* Allow scope change to root during execution of module-level |
* code. Root is typed METHOD during this time. |
*/ |
if ((node == acpi_gbl_root_node) && |
(walk_state-> |
parse_flags & ACPI_PARSE_MODULE_LEVEL)) { |
break; |
} |
/*lint -fallthrough */ |
default: |
/* All other types are an error */ |
ACPI_ERROR((AE_INFO, |
"Invalid type (%s) for target of " |
"Scope operator [%4.4s] (Cannot override)", |
acpi_ut_get_type_name(node->type), |
acpi_ut_get_node_name(node))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
break; |
default: |
/* All other opcodes */ |
if (op && op->common.node) { |
/* This op/node was previously entered into the namespace */ |
node = op->common.node; |
if (acpi_ns_opens_scope(object_type)) { |
status = |
acpi_ds_scope_stack_push(node, object_type, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Enter the named type into the internal namespace. We enter the name |
* as we go downward in the parse tree. Any necessary subobjects that |
* involve arguments to the opcode must be created as we go back up the |
* parse tree later. |
* |
* Note: Name may already exist if we are executing a deferred opcode. |
*/ |
if (walk_state->deferred_node) { |
/* This name is already in the namespace, get the node */ |
node = walk_state->deferred_node; |
status = AE_OK; |
break; |
} |
flags = ACPI_NS_NO_UPSEARCH; |
if (walk_state->pass_number == ACPI_IMODE_EXECUTE) { |
/* Execution mode, node cannot already exist, node is temporary */ |
flags |= ACPI_NS_ERROR_IF_FOUND; |
if (! |
(walk_state-> |
parse_flags & ACPI_PARSE_MODULE_LEVEL)) { |
flags |= ACPI_NS_TEMPORARY; |
} |
} |
/* Add new entry or lookup existing entry */ |
status = |
acpi_ns_lookup(walk_state->scope_info, buffer_ptr, |
object_type, ACPI_IMODE_LOAD_PASS2, flags, |
walk_state, &node); |
if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"***New Node [%4.4s] %p is temporary\n", |
acpi_ut_get_node_name(node), node)); |
} |
break; |
} |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(buffer_ptr, status); |
return_ACPI_STATUS(status); |
} |
if (!op) { |
/* Create a new op */ |
op = acpi_ps_alloc_op(walk_state->opcode, walk_state->aml); |
if (!op) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Initialize the new op */ |
if (node) { |
op->named.name = node->name.integer; |
} |
*out_op = op; |
} |
/* |
* Put the Node in the "op" object that the parser uses, so we |
* can get it again quickly when this scope is closed |
*/ |
op->common.node = node; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_load2_end_op |
* |
* PARAMETERS: walk_state - Current state of the parse tree walk |
* |
* RETURN: Status |
* |
* DESCRIPTION: Ascending callback used during the loading of the namespace, |
* both control methods and everything else. |
* |
******************************************************************************/ |
acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) |
{ |
union acpi_parse_object *op; |
acpi_status status = AE_OK; |
acpi_object_type object_type; |
struct acpi_namespace_node *node; |
union acpi_parse_object *arg; |
struct acpi_namespace_node *new_node; |
#ifndef ACPI_NO_METHOD_EXECUTION |
u32 i; |
u8 region_space; |
#endif |
ACPI_FUNCTION_TRACE(ds_load2_end_op); |
op = walk_state->op; |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", |
walk_state->op_info->name, op, walk_state)); |
/* Check if opcode had an associated namespace object */ |
if (!(walk_state->op_info->flags & AML_NSOBJECT)) { |
return_ACPI_STATUS(AE_OK); |
} |
if (op->common.aml_opcode == AML_SCOPE_OP) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Ending scope Op=%p State=%p\n", op, |
walk_state)); |
} |
object_type = walk_state->op_info->object_type; |
/* |
* Get the Node/name from the earlier lookup |
* (It was saved in the *op structure) |
*/ |
node = op->common.node; |
/* |
* Put the Node on the object stack (Contains the ACPI Name of |
* this object) |
*/ |
walk_state->operands[0] = (void *)node; |
walk_state->num_operands = 1; |
/* Pop the scope stack */ |
if (acpi_ns_opens_scope(object_type) && |
(op->common.aml_opcode != AML_INT_METHODCALL_OP)) { |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"(%s) Popping scope for Op %p\n", |
acpi_ut_get_type_name(object_type), op)); |
status = acpi_ds_scope_stack_pop(walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
} |
/* |
* Named operations are as follows: |
* |
* AML_ALIAS |
* AML_BANKFIELD |
* AML_CREATEBITFIELD |
* AML_CREATEBYTEFIELD |
* AML_CREATEDWORDFIELD |
* AML_CREATEFIELD |
* AML_CREATEQWORDFIELD |
* AML_CREATEWORDFIELD |
* AML_DATA_REGION |
* AML_DEVICE |
* AML_EVENT |
* AML_FIELD |
* AML_INDEXFIELD |
* AML_METHOD |
* AML_METHODCALL |
* AML_MUTEX |
* AML_NAME |
* AML_NAMEDFIELD |
* AML_OPREGION |
* AML_POWERRES |
* AML_PROCESSOR |
* AML_SCOPE |
* AML_THERMALZONE |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"Create-Load [%s] State=%p Op=%p NamedObj=%p\n", |
acpi_ps_get_opcode_name(op->common.aml_opcode), |
walk_state, op, node)); |
/* Decode the opcode */ |
arg = op->common.value.arg; |
switch (walk_state->op_info->type) { |
#ifndef ACPI_NO_METHOD_EXECUTION |
case AML_TYPE_CREATE_FIELD: |
/* |
* Create the field object, but the field buffer and index must |
* be evaluated later during the execution phase |
*/ |
status = acpi_ds_create_buffer_field(op, walk_state); |
break; |
case AML_TYPE_NAMED_FIELD: |
/* |
* If we are executing a method, initialize the field |
*/ |
if (walk_state->method_node) { |
status = acpi_ds_init_field_objects(op, walk_state); |
} |
switch (op->common.aml_opcode) { |
case AML_INDEX_FIELD_OP: |
status = |
acpi_ds_create_index_field(op, |
(acpi_handle) arg-> |
common.node, walk_state); |
break; |
case AML_BANK_FIELD_OP: |
status = |
acpi_ds_create_bank_field(op, arg->common.node, |
walk_state); |
break; |
case AML_FIELD_OP: |
status = |
acpi_ds_create_field(op, arg->common.node, |
walk_state); |
break; |
default: |
/* All NAMED_FIELD opcodes must be handled above */ |
break; |
} |
break; |
case AML_TYPE_NAMED_SIMPLE: |
status = acpi_ds_create_operands(walk_state, arg); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
switch (op->common.aml_opcode) { |
case AML_PROCESSOR_OP: |
status = acpi_ex_create_processor(walk_state); |
break; |
case AML_POWER_RES_OP: |
status = acpi_ex_create_power_resource(walk_state); |
break; |
case AML_MUTEX_OP: |
status = acpi_ex_create_mutex(walk_state); |
break; |
case AML_EVENT_OP: |
status = acpi_ex_create_event(walk_state); |
break; |
case AML_ALIAS_OP: |
status = acpi_ex_create_alias(walk_state); |
break; |
default: |
/* Unknown opcode */ |
status = AE_OK; |
goto cleanup; |
} |
/* Delete operands */ |
for (i = 1; i < walk_state->num_operands; i++) { |
acpi_ut_remove_reference(walk_state->operands[i]); |
walk_state->operands[i] = NULL; |
} |
break; |
#endif /* ACPI_NO_METHOD_EXECUTION */ |
case AML_TYPE_NAMED_COMPLEX: |
switch (op->common.aml_opcode) { |
#ifndef ACPI_NO_METHOD_EXECUTION |
case AML_REGION_OP: |
case AML_DATA_REGION_OP: |
if (op->common.aml_opcode == AML_REGION_OP) { |
region_space = (acpi_adr_space_type) |
((op->common.value.arg)->common.value. |
integer); |
} else { |
region_space = ACPI_ADR_SPACE_DATA_TABLE; |
} |
/* |
* The op_region is not fully parsed at this time. The only valid |
* argument is the space_id. (We must save the address of the |
* AML of the address and length operands) |
* |
* If we have a valid region, initialize it. The namespace is |
* unlocked at this point. |
* |
* Need to unlock interpreter if it is locked (if we are running |
* a control method), in order to allow _REG methods to be run |
* during acpi_ev_initialize_region. |
*/ |
if (walk_state->method_node) { |
/* |
* Executing a method: initialize the region and unlock |
* the interpreter |
*/ |
status = |
acpi_ex_create_region(op->named.data, |
op->named.length, |
region_space, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_ex_exit_interpreter(); |
} |
status = |
acpi_ev_initialize_region |
(acpi_ns_get_attached_object(node), FALSE); |
if (walk_state->method_node) { |
acpi_ex_enter_interpreter(); |
} |
if (ACPI_FAILURE(status)) { |
/* |
* If AE_NOT_EXIST is returned, it is not fatal |
* because many regions get created before a handler |
* is installed for said region. |
*/ |
if (AE_NOT_EXIST == status) { |
status = AE_OK; |
} |
} |
break; |
case AML_NAME_OP: |
status = acpi_ds_create_node(walk_state, node, op); |
break; |
case AML_METHOD_OP: |
/* |
* method_op pkg_length name_string method_flags term_list |
* |
* Note: We must create the method node/object pair as soon as we |
* see the method declaration. This allows later pass1 parsing |
* of invocations of the method (need to know the number of |
* arguments.) |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"LOADING-Method: State=%p Op=%p NamedObj=%p\n", |
walk_state, op, op->named.node)); |
if (!acpi_ns_get_attached_object(op->named.node)) { |
walk_state->operands[0] = |
ACPI_CAST_PTR(void, op->named.node); |
walk_state->num_operands = 1; |
status = |
acpi_ds_create_operands(walk_state, |
op->common.value. |
arg); |
if (ACPI_SUCCESS(status)) { |
status = |
acpi_ex_create_method(op->named. |
data, |
op->named. |
length, |
walk_state); |
} |
walk_state->operands[0] = NULL; |
walk_state->num_operands = 0; |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
break; |
#endif /* ACPI_NO_METHOD_EXECUTION */ |
default: |
/* All NAMED_COMPLEX opcodes must be handled above */ |
break; |
} |
break; |
case AML_CLASS_INTERNAL: |
/* case AML_INT_NAMEPATH_OP: */ |
break; |
case AML_CLASS_METHOD_CALL: |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n", |
walk_state, op, node)); |
/* |
* Lookup the method name and save the Node |
*/ |
status = |
acpi_ns_lookup(walk_state->scope_info, |
arg->common.value.string, ACPI_TYPE_ANY, |
ACPI_IMODE_LOAD_PASS2, |
ACPI_NS_SEARCH_PARENT | |
ACPI_NS_DONT_OPEN_SCOPE, walk_state, |
&(new_node)); |
if (ACPI_SUCCESS(status)) { |
/* |
* Make sure that what we found is indeed a method |
* We didn't search for a method on purpose, to see if the name |
* would resolve |
*/ |
if (new_node->type != ACPI_TYPE_METHOD) { |
status = AE_AML_OPERAND_TYPE; |
} |
/* We could put the returned object (Node) on the object stack for |
* later, but for now, we will put it in the "op" object that the |
* parser uses, so we can get it again at the end of this scope |
*/ |
op->common.node = new_node; |
} else { |
ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
} |
break; |
default: |
break; |
} |
cleanup: |
/* Remove the Node pushed at the very beginning */ |
walk_state->operands[0] = NULL; |
walk_state->num_operands = 0; |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/dswscope.c |
---|
0,0 → 1,214 |
/****************************************************************************** |
* |
* Module Name: dswscope - Scope stack manipulation |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dswscope") |
/**************************************************************************** |
* |
* FUNCTION: acpi_ds_scope_stack_clear |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: None |
* |
* DESCRIPTION: Pop (and free) everything on the scope stack except the |
* root scope object (which remains at the stack top.) |
* |
***************************************************************************/ |
void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state) |
{ |
union acpi_generic_state *scope_info; |
ACPI_FUNCTION_NAME(ds_scope_stack_clear); |
while (walk_state->scope_info) { |
/* Pop a scope off the stack */ |
scope_info = walk_state->scope_info; |
walk_state->scope_info = scope_info->scope.next; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Popped object type (%s)\n", |
acpi_ut_get_type_name(scope_info->common. |
value))); |
acpi_ut_delete_generic_state(scope_info); |
} |
} |
/**************************************************************************** |
* |
* FUNCTION: acpi_ds_scope_stack_push |
* |
* PARAMETERS: node - Name to be made current |
* type - Type of frame being pushed |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Push the current scope on the scope stack, and make the |
* passed Node current. |
* |
***************************************************************************/ |
acpi_status |
acpi_ds_scope_stack_push(struct acpi_namespace_node *node, |
acpi_object_type type, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_generic_state *scope_info; |
union acpi_generic_state *old_scope_info; |
ACPI_FUNCTION_TRACE(ds_scope_stack_push); |
if (!node) { |
/* Invalid scope */ |
ACPI_ERROR((AE_INFO, "Null scope parameter")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Make sure object type is valid */ |
if (!acpi_ut_valid_object_type(type)) { |
ACPI_WARNING((AE_INFO, "Invalid object type: 0x%X", type)); |
} |
/* Allocate a new scope object */ |
scope_info = acpi_ut_create_generic_state(); |
if (!scope_info) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Init new scope object */ |
scope_info->common.descriptor_type = ACPI_DESC_TYPE_STATE_WSCOPE; |
scope_info->scope.node = node; |
scope_info->common.value = (u16) type; |
walk_state->scope_depth++; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[%.2d] Pushed scope ", |
(u32) walk_state->scope_depth)); |
old_scope_info = walk_state->scope_info; |
if (old_scope_info) { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, |
"[%4.4s] (%s)", |
acpi_ut_get_node_name(old_scope_info-> |
scope.node), |
acpi_ut_get_type_name(old_scope_info-> |
common.value))); |
} else { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (%s)", "ROOT")); |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, |
", New scope -> [%4.4s] (%s)\n", |
acpi_ut_get_node_name(scope_info->scope.node), |
acpi_ut_get_type_name(scope_info->common.value))); |
/* Push new scope object onto stack */ |
acpi_ut_push_generic_state(&walk_state->scope_info, scope_info); |
return_ACPI_STATUS(AE_OK); |
} |
/**************************************************************************** |
* |
* FUNCTION: acpi_ds_scope_stack_pop |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Pop the scope stack once. |
* |
***************************************************************************/ |
acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state) |
{ |
union acpi_generic_state *scope_info; |
union acpi_generic_state *new_scope_info; |
ACPI_FUNCTION_TRACE(ds_scope_stack_pop); |
/* |
* Pop scope info object off the stack. |
*/ |
scope_info = acpi_ut_pop_generic_state(&walk_state->scope_info); |
if (!scope_info) { |
return_ACPI_STATUS(AE_STACK_UNDERFLOW); |
} |
walk_state->scope_depth--; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[%.2d] Popped scope [%4.4s] (%s), New scope -> ", |
(u32) walk_state->scope_depth, |
acpi_ut_get_node_name(scope_info->scope.node), |
acpi_ut_get_type_name(scope_info->common.value))); |
new_scope_info = walk_state->scope_info; |
if (new_scope_info) { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, |
"[%4.4s] (%s)\n", |
acpi_ut_get_node_name(new_scope_info-> |
scope.node), |
acpi_ut_get_type_name(new_scope_info-> |
common.value))); |
} else { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (ROOT)\n")); |
} |
acpi_ut_delete_generic_state(scope_info); |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/dswstate.c |
---|
0,0 → 1,757 |
/****************************************************************************** |
* |
* Module Name: dswstate - Dispatcher parse tree walk management routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "acdispat.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_DISPATCHER |
ACPI_MODULE_NAME("dswstate") |
/* Local prototypes */ |
static acpi_status |
acpi_ds_result_stack_push(struct acpi_walk_state *walk_state); |
static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_result_pop |
* |
* PARAMETERS: object - Where to return the popped object |
* walk_state - Current Walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Pop an object off the top of this walk's result stack |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_result_pop(union acpi_operand_object **object, |
struct acpi_walk_state *walk_state) |
{ |
u32 index; |
union acpi_generic_state *state; |
acpi_status status; |
ACPI_FUNCTION_NAME(ds_result_pop); |
state = walk_state->results; |
/* Incorrect state of result stack */ |
if (state && !walk_state->result_count) { |
ACPI_ERROR((AE_INFO, "No results on result stack")); |
return (AE_AML_INTERNAL); |
} |
if (!state && walk_state->result_count) { |
ACPI_ERROR((AE_INFO, "No result state for result stack")); |
return (AE_AML_INTERNAL); |
} |
/* Empty result stack */ |
if (!state) { |
ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p", |
walk_state)); |
return (AE_AML_NO_RETURN_VALUE); |
} |
/* Return object of the top element and clean that top element result stack */ |
walk_state->result_count--; |
index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; |
*object = state->results.obj_desc[index]; |
if (!*object) { |
ACPI_ERROR((AE_INFO, |
"No result objects on result stack, State=%p", |
walk_state)); |
return (AE_AML_NO_RETURN_VALUE); |
} |
state->results.obj_desc[index] = NULL; |
if (index == 0) { |
status = acpi_ds_result_stack_pop(walk_state); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Obj=%p [%s] Index=%X State=%p Num=%X\n", *object, |
acpi_ut_get_object_type_name(*object), |
index, walk_state, walk_state->result_count)); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_result_push |
* |
* PARAMETERS: object - Where to return the popped object |
* walk_state - Current Walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Push an object onto the current result stack |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_result_push(union acpi_operand_object * object, |
struct acpi_walk_state * walk_state) |
{ |
union acpi_generic_state *state; |
acpi_status status; |
u32 index; |
ACPI_FUNCTION_NAME(ds_result_push); |
if (walk_state->result_count > walk_state->result_size) { |
ACPI_ERROR((AE_INFO, "Result stack is full")); |
return (AE_AML_INTERNAL); |
} else if (walk_state->result_count == walk_state->result_size) { |
/* Extend the result stack */ |
status = acpi_ds_result_stack_push(walk_state); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Failed to extend the result stack")); |
return (status); |
} |
} |
if (!(walk_state->result_count < walk_state->result_size)) { |
ACPI_ERROR((AE_INFO, "No free elements in result stack")); |
return (AE_AML_INTERNAL); |
} |
state = walk_state->results; |
if (!state) { |
ACPI_ERROR((AE_INFO, "No result stack frame during push")); |
return (AE_AML_INTERNAL); |
} |
if (!object) { |
ACPI_ERROR((AE_INFO, |
"Null Object! Obj=%p State=%p Num=%u", |
object, walk_state, walk_state->result_count)); |
return (AE_BAD_PARAMETER); |
} |
/* Assign the address of object to the top free element of result stack */ |
index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; |
state->results.obj_desc[index] = object; |
walk_state->result_count++; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n", |
object, |
acpi_ut_get_object_type_name((union |
acpi_operand_object *) |
object), walk_state, |
walk_state->result_count, |
walk_state->current_result)); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_result_stack_push |
* |
* PARAMETERS: walk_state - Current Walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Push an object onto the walk_state result stack |
* |
******************************************************************************/ |
static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_NAME(ds_result_stack_push); |
/* Check for stack overflow */ |
if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) > |
ACPI_RESULTS_OBJ_NUM_MAX) { |
ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%u", |
walk_state, walk_state->result_size)); |
return (AE_STACK_OVERFLOW); |
} |
state = acpi_ut_create_generic_state(); |
if (!state) { |
return (AE_NO_MEMORY); |
} |
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT; |
acpi_ut_push_generic_state(&walk_state->results, state); |
/* Increase the length of the result stack by the length of frame */ |
walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n", |
state, walk_state)); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_result_stack_pop |
* |
* PARAMETERS: walk_state - Current Walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Pop an object off of the walk_state result stack |
* |
******************************************************************************/ |
static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_NAME(ds_result_stack_pop); |
/* Check for stack underflow */ |
if (walk_state->results == NULL) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Result stack underflow - State=%p\n", |
walk_state)); |
return (AE_AML_NO_OPERAND); |
} |
if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) { |
ACPI_ERROR((AE_INFO, "Insufficient result stack size")); |
return (AE_AML_INTERNAL); |
} |
state = acpi_ut_pop_generic_state(&walk_state->results); |
acpi_ut_delete_generic_state(state); |
/* Decrease the length of result stack by the length of frame */ |
walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Result=%p RemainingResults=%X State=%p\n", |
state, walk_state->result_count, walk_state)); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_obj_stack_push |
* |
* PARAMETERS: object - Object to push |
* walk_state - Current Walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Push an object onto this walk's object/operand stack |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state) |
{ |
ACPI_FUNCTION_NAME(ds_obj_stack_push); |
/* Check for stack overflow */ |
if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) { |
ACPI_ERROR((AE_INFO, |
"Object stack overflow! Obj=%p State=%p #Ops=%u", |
object, walk_state, walk_state->num_operands)); |
return (AE_STACK_OVERFLOW); |
} |
/* Put the object onto the stack */ |
walk_state->operands[walk_state->operand_index] = object; |
walk_state->num_operands++; |
/* For the usual order of filling the operand stack */ |
walk_state->operand_index++; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", |
object, |
acpi_ut_get_object_type_name((union |
acpi_operand_object *) |
object), walk_state, |
walk_state->num_operands)); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_obj_stack_pop |
* |
* PARAMETERS: pop_count - Number of objects/entries to pop |
* walk_state - Current Walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT |
* deleted by this routine. |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state) |
{ |
u32 i; |
ACPI_FUNCTION_NAME(ds_obj_stack_pop); |
for (i = 0; i < pop_count; i++) { |
/* Check for stack underflow */ |
if (walk_state->num_operands == 0) { |
ACPI_ERROR((AE_INFO, |
"Object stack underflow! Count=%X State=%p #Ops=%u", |
pop_count, walk_state, |
walk_state->num_operands)); |
return (AE_STACK_UNDERFLOW); |
} |
/* Just set the stack entry to null */ |
walk_state->num_operands--; |
walk_state->operands[walk_state->num_operands] = NULL; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%u\n", |
pop_count, walk_state, walk_state->num_operands)); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_obj_stack_pop_and_delete |
* |
* PARAMETERS: pop_count - Number of objects/entries to pop |
* walk_state - Current Walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Pop this walk's object stack and delete each object that is |
* popped off. |
* |
******************************************************************************/ |
void |
acpi_ds_obj_stack_pop_and_delete(u32 pop_count, |
struct acpi_walk_state *walk_state) |
{ |
s32 i; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete); |
if (pop_count == 0) { |
return; |
} |
for (i = (s32) pop_count - 1; i >= 0; i--) { |
if (walk_state->num_operands == 0) { |
return; |
} |
/* Pop the stack and delete an object if present in this stack entry */ |
walk_state->num_operands--; |
obj_desc = walk_state->operands[i]; |
if (obj_desc) { |
acpi_ut_remove_reference(walk_state->operands[i]); |
walk_state->operands[i] = NULL; |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n", |
pop_count, walk_state, walk_state->num_operands)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_get_current_walk_state |
* |
* PARAMETERS: thread - Get current active state for this Thread |
* |
* RETURN: Pointer to the current walk state |
* |
* DESCRIPTION: Get the walk state that is at the head of the list (the "current" |
* walk state.) |
* |
******************************************************************************/ |
struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state |
*thread) |
{ |
ACPI_FUNCTION_NAME(ds_get_current_walk_state); |
if (!thread) { |
return (NULL); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current WalkState %p\n", |
thread->walk_state_list)); |
return (thread->walk_state_list); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_push_walk_state |
* |
* PARAMETERS: walk_state - State to push |
* thread - Thread state object |
* |
* RETURN: None |
* |
* DESCRIPTION: Place the Thread state at the head of the state list |
* |
******************************************************************************/ |
void |
acpi_ds_push_walk_state(struct acpi_walk_state *walk_state, |
struct acpi_thread_state *thread) |
{ |
ACPI_FUNCTION_TRACE(ds_push_walk_state); |
walk_state->next = thread->walk_state_list; |
thread->walk_state_list = walk_state; |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_pop_walk_state |
* |
* PARAMETERS: thread - Current thread state |
* |
* RETURN: A walk_state object popped from the thread's stack |
* |
* DESCRIPTION: Remove and return the walkstate object that is at the head of |
* the walk stack for the given walk list. NULL indicates that |
* the list is empty. |
* |
******************************************************************************/ |
struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) |
{ |
struct acpi_walk_state *walk_state; |
ACPI_FUNCTION_TRACE(ds_pop_walk_state); |
walk_state = thread->walk_state_list; |
if (walk_state) { |
/* Next walk state becomes the current walk state */ |
thread->walk_state_list = walk_state->next; |
/* |
* Don't clear the NEXT field, this serves as an indicator |
* that there is a parent WALK STATE |
* Do Not: walk_state->Next = NULL; |
*/ |
} |
return_PTR(walk_state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_create_walk_state |
* |
* PARAMETERS: owner_id - ID for object creation |
* origin - Starting point for this walk |
* method_desc - Method object |
* thread - Current thread state |
* |
* RETURN: Pointer to the new walk state. |
* |
* DESCRIPTION: Allocate and initialize a new walk state. The current walk |
* state is set to this new state. |
* |
******************************************************************************/ |
struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, |
union acpi_parse_object |
*origin, |
union acpi_operand_object |
*method_desc, |
struct acpi_thread_state |
*thread) |
{ |
struct acpi_walk_state *walk_state; |
ACPI_FUNCTION_TRACE(ds_create_walk_state); |
walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state)); |
if (!walk_state) { |
return_PTR(NULL); |
} |
walk_state->descriptor_type = ACPI_DESC_TYPE_WALK; |
walk_state->method_desc = method_desc; |
walk_state->owner_id = owner_id; |
walk_state->origin = origin; |
walk_state->thread = thread; |
walk_state->parser_state.start_op = origin; |
/* Init the method args/local */ |
#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) |
acpi_ds_method_data_init(walk_state); |
#endif |
/* Put the new state at the head of the walk list */ |
if (thread) { |
acpi_ds_push_walk_state(walk_state, thread); |
} |
return_PTR(walk_state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_init_aml_walk |
* |
* PARAMETERS: walk_state - New state to be initialized |
* op - Current parse op |
* method_node - Control method NS node, if any |
* aml_start - Start of AML |
* aml_length - Length of AML |
* info - Method info block (params, etc.) |
* pass_number - 1, 2, or 3 |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk |
* |
******************************************************************************/ |
acpi_status |
acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
struct acpi_namespace_node *method_node, |
u8 * aml_start, |
u32 aml_length, |
struct acpi_evaluate_info *info, u8 pass_number) |
{ |
acpi_status status; |
struct acpi_parse_state *parser_state = &walk_state->parser_state; |
union acpi_parse_object *extra_op; |
ACPI_FUNCTION_TRACE(ds_init_aml_walk); |
walk_state->parser_state.aml = |
walk_state->parser_state.aml_start = aml_start; |
walk_state->parser_state.aml_end = |
walk_state->parser_state.pkg_end = aml_start + aml_length; |
/* The next_op of the next_walk will be the beginning of the method */ |
walk_state->next_op = NULL; |
walk_state->pass_number = pass_number; |
if (info) { |
walk_state->params = info->parameters; |
walk_state->caller_return_desc = &info->return_object; |
} |
status = acpi_ps_init_scope(&walk_state->parser_state, op); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (method_node) { |
walk_state->parser_state.start_node = method_node; |
walk_state->walk_type = ACPI_WALK_METHOD; |
walk_state->method_node = method_node; |
walk_state->method_desc = |
acpi_ns_get_attached_object(method_node); |
/* Push start scope on scope stack and make it current */ |
status = |
acpi_ds_scope_stack_push(method_node, ACPI_TYPE_METHOD, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Init the method arguments */ |
status = acpi_ds_method_data_init_args(walk_state->params, |
ACPI_METHOD_NUM_ARGS, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} else { |
/* |
* Setup the current scope. |
* Find a Named Op that has a namespace node associated with it. |
* search upwards from this Op. Current scope is the first |
* Op with a namespace node. |
*/ |
extra_op = parser_state->start_op; |
while (extra_op && !extra_op->common.node) { |
extra_op = extra_op->common.parent; |
} |
if (!extra_op) { |
parser_state->start_node = NULL; |
} else { |
parser_state->start_node = extra_op->common.node; |
} |
if (parser_state->start_node) { |
/* Push start scope on scope stack and make it current */ |
status = |
acpi_ds_scope_stack_push(parser_state->start_node, |
parser_state->start_node-> |
type, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} |
status = acpi_ds_init_callbacks(walk_state, pass_number); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ds_delete_walk_state |
* |
* PARAMETERS: walk_state - State to delete |
* |
* RETURN: Status |
* |
* DESCRIPTION: Delete a walk state including all internal data structures |
* |
******************************************************************************/ |
void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state); |
if (!walk_state) { |
return_VOID; |
} |
if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) { |
ACPI_ERROR((AE_INFO, "%p is not a valid walk state", |
walk_state)); |
return_VOID; |
} |
/* There should not be any open scopes */ |
if (walk_state->parser_state.scope) { |
ACPI_ERROR((AE_INFO, "%p walk still has a scope list", |
walk_state)); |
acpi_ps_cleanup_scope(&walk_state->parser_state); |
} |
/* Always must free any linked control states */ |
while (walk_state->control_state) { |
state = walk_state->control_state; |
walk_state->control_state = state->common.next; |
acpi_ut_delete_generic_state(state); |
} |
/* Always must free any linked parse states */ |
while (walk_state->scope_info) { |
state = walk_state->scope_info; |
walk_state->scope_info = state->common.next; |
acpi_ut_delete_generic_state(state); |
} |
/* Always must free any stacked result states */ |
while (walk_state->results) { |
state = walk_state->results; |
walk_state->results = state->common.next; |
acpi_ut_delete_generic_state(state); |
} |
ACPI_FREE(walk_state); |
return_VOID; |
} |
/drivers/acpi/acpica/evevent.c |
---|
0,0 → 1,297 |
/****************************************************************************** |
* |
* Module Name: evevent - Fixed Event handling and dispatch |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evevent") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/* Local prototypes */ |
static acpi_status acpi_ev_fixed_event_initialize(void); |
static u32 acpi_ev_fixed_event_dispatch(u32 event); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_initialize_events |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE) |
* |
******************************************************************************/ |
acpi_status acpi_ev_initialize_events(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_initialize_events); |
/* If Hardware Reduced flag is set, there are no fixed events */ |
if (acpi_gbl_reduced_hardware) { |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Initialize the Fixed and General Purpose Events. This is done prior to |
* enabling SCIs to prevent interrupts from occurring before the handlers |
* are installed. |
*/ |
status = acpi_ev_fixed_event_initialize(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Unable to initialize fixed events")); |
return_ACPI_STATUS(status); |
} |
status = acpi_ev_gpe_initialize(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Unable to initialize general purpose events")); |
return_ACPI_STATUS(status); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_install_xrupt_handlers |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install interrupt handlers for the SCI and Global Lock |
* |
******************************************************************************/ |
acpi_status acpi_ev_install_xrupt_handlers(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers); |
/* If Hardware Reduced flag is set, there is no ACPI h/w */ |
if (acpi_gbl_reduced_hardware) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Install the SCI handler */ |
status = acpi_ev_install_sci_handler(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Unable to install System Control Interrupt handler")); |
return_ACPI_STATUS(status); |
} |
/* Install the handler for the Global Lock */ |
status = acpi_ev_init_global_lock_handler(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Unable to initialize Global Lock handler")); |
return_ACPI_STATUS(status); |
} |
acpi_gbl_events_initialized = TRUE; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_fixed_event_initialize |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install the fixed event handlers and disable all fixed events. |
* |
******************************************************************************/ |
static acpi_status acpi_ev_fixed_event_initialize(void) |
{ |
u32 i; |
acpi_status status; |
/* |
* Initialize the structure that keeps track of fixed event handlers and |
* enable the fixed events. |
*/ |
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
acpi_gbl_fixed_event_handlers[i].handler = NULL; |
acpi_gbl_fixed_event_handlers[i].context = NULL; |
/* Disable the fixed event */ |
if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { |
status = |
acpi_write_bit_register(acpi_gbl_fixed_event_info |
[i].enable_register_id, |
ACPI_DISABLE_EVENT); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_fixed_event_detect |
* |
* PARAMETERS: None |
* |
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
* |
* DESCRIPTION: Checks the PM status register for active fixed events |
* |
******************************************************************************/ |
u32 acpi_ev_fixed_event_detect(void) |
{ |
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; |
u32 fixed_status; |
u32 fixed_enable; |
u32 i; |
ACPI_FUNCTION_NAME(ev_fixed_event_detect); |
/* |
* Read the fixed feature status and enable registers, as all the cases |
* depend on their values. Ignore errors here. |
*/ |
(void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); |
(void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); |
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, |
"Fixed Event Block: Enable %08X Status %08X\n", |
fixed_enable, fixed_status)); |
/* |
* Check for all possible Fixed Events and dispatch those that are active |
*/ |
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
/* Both the status and enable bits must be on for this event */ |
if ((fixed_status & acpi_gbl_fixed_event_info[i]. |
status_bit_mask) |
&& (fixed_enable & acpi_gbl_fixed_event_info[i]. |
enable_bit_mask)) { |
/* |
* Found an active (signalled) event. Invoke global event |
* handler if present. |
*/ |
acpi_fixed_event_count[i]++; |
if (acpi_gbl_global_event_handler) { |
acpi_gbl_global_event_handler |
(ACPI_EVENT_TYPE_FIXED, NULL, i, |
acpi_gbl_global_event_handler_context); |
} |
int_status |= acpi_ev_fixed_event_dispatch(i); |
} |
} |
return (int_status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_fixed_event_dispatch |
* |
* PARAMETERS: event - Event type |
* |
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
* |
* DESCRIPTION: Clears the status bit for the requested event, calls the |
* handler that previously registered for the event. |
* NOTE: If there is no handler for the event, the event is |
* disabled to prevent further interrupts. |
* |
******************************************************************************/ |
static u32 acpi_ev_fixed_event_dispatch(u32 event) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Clear the status bit */ |
(void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. |
status_register_id, ACPI_CLEAR_STATUS); |
/* |
* Make sure that a handler exists. If not, report an error |
* and disable the event to prevent further interrupts. |
*/ |
if (!acpi_gbl_fixed_event_handlers[event].handler) { |
(void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. |
enable_register_id, |
ACPI_DISABLE_EVENT); |
ACPI_ERROR((AE_INFO, |
"No installed handler for fixed event - %s (%u), disabling", |
acpi_ut_get_event_name(event), event)); |
return (ACPI_INTERRUPT_NOT_HANDLED); |
} |
/* Invoke the Fixed Event handler */ |
return ((acpi_gbl_fixed_event_handlers[event]. |
handler) (acpi_gbl_fixed_event_handlers[event].context)); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evglock.c |
---|
0,0 → 1,344 |
/****************************************************************************** |
* |
* Module Name: evglock - Global Lock support |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evglock") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/* Local prototypes */ |
static u32 acpi_ev_global_lock_handler(void *context); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_init_global_lock_handler |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for the global lock release event |
* |
******************************************************************************/ |
acpi_status acpi_ev_init_global_lock_handler(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); |
/* If Hardware Reduced flag is set, there is no global lock */ |
if (acpi_gbl_reduced_hardware) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Attempt installation of the global lock handler */ |
status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, |
acpi_ev_global_lock_handler, |
NULL); |
/* |
* If the global lock does not exist on this platform, the attempt to |
* enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick). |
* Map to AE_OK, but mark global lock as not present. Any attempt to |
* actually use the global lock will be flagged with an error. |
*/ |
acpi_gbl_global_lock_present = FALSE; |
if (status == AE_NO_HARDWARE_RESPONSE) { |
ACPI_ERROR((AE_INFO, |
"No response from Global Lock hardware, disabling lock")); |
return_ACPI_STATUS(AE_OK); |
} |
status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_gbl_global_lock_pending = FALSE; |
acpi_gbl_global_lock_present = TRUE; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_remove_global_lock_handler |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove the handler for the Global Lock |
* |
******************************************************************************/ |
acpi_status acpi_ev_remove_global_lock_handler(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler); |
acpi_gbl_global_lock_present = FALSE; |
status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL, |
acpi_ev_global_lock_handler); |
acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_global_lock_handler |
* |
* PARAMETERS: context - From thread interface, not used |
* |
* RETURN: ACPI_INTERRUPT_HANDLED |
* |
* DESCRIPTION: Invoked directly from the SCI handler when a global lock |
* release interrupt occurs. If there is actually a pending |
* request for the lock, signal the waiting thread. |
* |
******************************************************************************/ |
static u32 acpi_ev_global_lock_handler(void *context) |
{ |
acpi_status status; |
acpi_cpu_flags flags; |
flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); |
/* |
* If a request for the global lock is not actually pending, |
* we are done. This handles "spurious" global lock interrupts |
* which are possible (and have been seen) with bad BIOSs. |
*/ |
if (!acpi_gbl_global_lock_pending) { |
goto cleanup_and_exit; |
} |
/* |
* Send a unit to the global lock semaphore. The actual acquisition |
* of the global lock will be performed by the waiting thread. |
*/ |
status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore")); |
} |
acpi_gbl_global_lock_pending = FALSE; |
cleanup_and_exit: |
acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); |
return (ACPI_INTERRUPT_HANDLED); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ev_acquire_global_lock |
* |
* PARAMETERS: timeout - Max time to wait for the lock, in millisec. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Attempt to gain ownership of the Global Lock. |
* |
* MUTEX: Interpreter must be locked |
* |
* Note: The original implementation allowed multiple threads to "acquire" the |
* Global Lock, and the OS would hold the lock until the last thread had |
* released it. However, this could potentially starve the BIOS out of the |
* lock, especially in the case where there is a tight handshake between the |
* Embedded Controller driver and the BIOS. Therefore, this implementation |
* allows only one thread to acquire the HW Global Lock at a time, and makes |
* the global lock appear as a standard mutex on the OS side. |
* |
*****************************************************************************/ |
acpi_status acpi_ev_acquire_global_lock(u16 timeout) |
{ |
acpi_cpu_flags flags; |
acpi_status status; |
u8 acquired = FALSE; |
ACPI_FUNCTION_TRACE(ev_acquire_global_lock); |
/* |
* Only one thread can acquire the GL at a time, the global_lock_mutex |
* enforces this. This interface releases the interpreter if we must wait. |
*/ |
status = |
acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex. |
os_mutex, timeout); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Update the global lock handle and check for wraparound. The handle is |
* only used for the external global lock interfaces, but it is updated |
* here to properly handle the case where a single thread may acquire the |
* lock via both the AML and the acpi_acquire_global_lock interfaces. The |
* handle is therefore updated on the first acquire from a given thread |
* regardless of where the acquisition request originated. |
*/ |
acpi_gbl_global_lock_handle++; |
if (acpi_gbl_global_lock_handle == 0) { |
acpi_gbl_global_lock_handle = 1; |
} |
/* |
* Make sure that a global lock actually exists. If not, just |
* treat the lock as a standard mutex. |
*/ |
if (!acpi_gbl_global_lock_present) { |
acpi_gbl_global_lock_acquired = TRUE; |
return_ACPI_STATUS(AE_OK); |
} |
flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); |
do { |
/* Attempt to acquire the actual hardware lock */ |
ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); |
if (acquired) { |
acpi_gbl_global_lock_acquired = TRUE; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Acquired hardware Global Lock\n")); |
break; |
} |
/* |
* Did not get the lock. The pending bit was set above, and |
* we must now wait until we receive the global lock |
* released interrupt. |
*/ |
acpi_gbl_global_lock_pending = TRUE; |
acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Waiting for hardware Global Lock\n")); |
/* |
* Wait for handshake with the global lock interrupt handler. |
* This interface releases the interpreter if we must wait. |
*/ |
status = |
acpi_ex_system_wait_semaphore |
(acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER); |
flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); |
} while (ACPI_SUCCESS(status)); |
acpi_gbl_global_lock_pending = FALSE; |
acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_release_global_lock |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Releases ownership of the Global Lock. |
* |
******************************************************************************/ |
acpi_status acpi_ev_release_global_lock(void) |
{ |
u8 pending = FALSE; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ev_release_global_lock); |
/* Lock must be already acquired */ |
if (!acpi_gbl_global_lock_acquired) { |
ACPI_WARNING((AE_INFO, |
"Cannot release the ACPI Global Lock, it has not been acquired")); |
return_ACPI_STATUS(AE_NOT_ACQUIRED); |
} |
if (acpi_gbl_global_lock_present) { |
/* Allow any thread to release the lock */ |
ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending); |
/* |
* If the pending bit was set, we must write GBL_RLS to the control |
* register |
*/ |
if (pending) { |
status = |
acpi_write_bit_register |
(ACPI_BITREG_GLOBAL_LOCK_RELEASE, |
ACPI_ENABLE_EVENT); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Released hardware Global Lock\n")); |
} |
acpi_gbl_global_lock_acquired = FALSE; |
/* Release the local GL mutex */ |
acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex); |
return_ACPI_STATUS(status); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evgpe.c |
---|
0,0 → 1,798 |
/****************************************************************************** |
* |
* Module Name: evgpe - General Purpose Event handling and dispatch |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evgpe") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/* Local prototypes */ |
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context); |
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_update_gpe_enable_mask |
* |
* PARAMETERS: gpe_event_info - GPE to update |
* |
* RETURN: Status |
* |
* DESCRIPTION: Updates GPE register enable mask based upon whether there are |
* runtime references to this GPE |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) |
{ |
struct acpi_gpe_register_info *gpe_register_info; |
u32 register_bit; |
ACPI_FUNCTION_TRACE(ev_update_gpe_enable_mask); |
gpe_register_info = gpe_event_info->register_info; |
if (!gpe_register_info) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
/* Clear the run bit up front */ |
ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit); |
/* Set the mask bit only if there are references to this GPE */ |
if (gpe_event_info->runtime_count) { |
ACPI_SET_BIT(gpe_register_info->enable_for_run, |
(u8)register_bit); |
} |
gpe_register_info->enable_mask = gpe_register_info->enable_for_run; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_enable_gpe |
* |
* PARAMETERS: gpe_event_info - GPE to enable |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clear a GPE of stale events and enable it. |
* |
******************************************************************************/ |
acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_enable_gpe); |
/* Clear the GPE (of stale events) */ |
status = acpi_hw_clear_gpe(gpe_event_info); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Enable the requested GPE */ |
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_add_gpe_reference |
* |
* PARAMETERS: gpe_event_info - Add a reference to this GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is |
* hardware-enabled. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ev_add_gpe_reference); |
if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) { |
return_ACPI_STATUS(AE_LIMIT); |
} |
gpe_event_info->runtime_count++; |
if (gpe_event_info->runtime_count == 1) { |
/* Enable on first reference */ |
status = acpi_ev_update_gpe_enable_mask(gpe_event_info); |
if (ACPI_SUCCESS(status)) { |
status = acpi_ev_enable_gpe(gpe_event_info); |
} |
if (ACPI_FAILURE(status)) { |
gpe_event_info->runtime_count--; |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_remove_gpe_reference |
* |
* PARAMETERS: gpe_event_info - Remove a reference to this GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a reference to a GPE. When the last reference is |
* removed, the GPE is hardware-disabled. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ev_remove_gpe_reference); |
if (!gpe_event_info->runtime_count) { |
return_ACPI_STATUS(AE_LIMIT); |
} |
gpe_event_info->runtime_count--; |
if (!gpe_event_info->runtime_count) { |
/* Disable on last reference */ |
status = acpi_ev_update_gpe_enable_mask(gpe_event_info); |
if (ACPI_SUCCESS(status)) { |
status = |
acpi_hw_low_set_gpe(gpe_event_info, |
ACPI_GPE_DISABLE); |
} |
if (ACPI_FAILURE(status)) { |
gpe_event_info->runtime_count++; |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_low_get_gpe_info |
* |
* PARAMETERS: gpe_number - Raw GPE number |
* gpe_block - A GPE info block |
* |
* RETURN: A GPE event_info struct. NULL if not a valid GPE (The gpe_number |
* is not within the specified GPE block) |
* |
* DESCRIPTION: Returns the event_info struct associated with this GPE. This is |
* the low-level implementation of ev_get_gpe_event_info. |
* |
******************************************************************************/ |
struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number, |
struct acpi_gpe_block_info |
*gpe_block) |
{ |
u32 gpe_index; |
/* |
* Validate that the gpe_number is within the specified gpe_block. |
* (Two steps) |
*/ |
if (!gpe_block || (gpe_number < gpe_block->block_base_number)) { |
return (NULL); |
} |
gpe_index = gpe_number - gpe_block->block_base_number; |
if (gpe_index >= gpe_block->gpe_count) { |
return (NULL); |
} |
return (&gpe_block->event_info[gpe_index]); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_get_gpe_event_info |
* |
* PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 |
* gpe_number - Raw GPE number |
* |
* RETURN: A GPE event_info struct. NULL if not a valid GPE |
* |
* DESCRIPTION: Returns the event_info struct associated with this GPE. |
* Validates the gpe_block and the gpe_number |
* |
* Should be called only when the GPE lists are semaphore locked |
* and not subject to change. |
* |
******************************************************************************/ |
struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, |
u32 gpe_number) |
{ |
union acpi_operand_object *obj_desc; |
struct acpi_gpe_event_info *gpe_info; |
u32 i; |
ACPI_FUNCTION_ENTRY(); |
/* A NULL gpe_device means use the FADT-defined GPE block(s) */ |
if (!gpe_device) { |
/* Examine GPE Block 0 and 1 (These blocks are permanent) */ |
for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) { |
gpe_info = acpi_ev_low_get_gpe_info(gpe_number, |
acpi_gbl_gpe_fadt_blocks |
[i]); |
if (gpe_info) { |
return (gpe_info); |
} |
} |
/* The gpe_number was not in the range of either FADT GPE block */ |
return (NULL); |
} |
/* A Non-NULL gpe_device means this is a GPE Block Device */ |
obj_desc = |
acpi_ns_get_attached_object((struct acpi_namespace_node *) |
gpe_device); |
if (!obj_desc || !obj_desc->device.gpe_block) { |
return (NULL); |
} |
return (acpi_ev_low_get_gpe_info |
(gpe_number, obj_desc->device.gpe_block)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_gpe_detect |
* |
* PARAMETERS: gpe_xrupt_list - Interrupt block for this interrupt. |
* Can have multiple GPE blocks attached. |
* |
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
* |
* DESCRIPTION: Detect if any GP events have occurred. This function is |
* executed at interrupt level. |
* |
******************************************************************************/ |
u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) |
{ |
acpi_status status; |
struct acpi_gpe_block_info *gpe_block; |
struct acpi_namespace_node *gpe_device; |
struct acpi_gpe_register_info *gpe_register_info; |
struct acpi_gpe_event_info *gpe_event_info; |
u32 gpe_number; |
struct acpi_gpe_handler_info *gpe_handler_info; |
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; |
u8 enabled_status_byte; |
u32 status_reg; |
u32 enable_reg; |
acpi_cpu_flags flags; |
u32 i; |
u32 j; |
ACPI_FUNCTION_NAME(ev_gpe_detect); |
/* Check for the case where there are no GPEs */ |
if (!gpe_xrupt_list) { |
return (int_status); |
} |
/* |
* We need to obtain the GPE lock for both the data structs and registers |
* Note: Not necessary to obtain the hardware lock, since the GPE |
* registers are owned by the gpe_lock. |
*/ |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Examine all GPE blocks attached to this interrupt level */ |
gpe_block = gpe_xrupt_list->gpe_block_list_head; |
while (gpe_block) { |
gpe_device = gpe_block->node; |
/* |
* Read all of the 8-bit GPE status and enable registers in this GPE |
* block, saving all of them. Find all currently active GP events. |
*/ |
for (i = 0; i < gpe_block->register_count; i++) { |
/* Get the next status/enable pair */ |
gpe_register_info = &gpe_block->register_info[i]; |
/* |
* Optimization: If there are no GPEs enabled within this |
* register, we can safely ignore the entire register. |
*/ |
if (!(gpe_register_info->enable_for_run | |
gpe_register_info->enable_for_wake)) { |
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, |
"Ignore disabled registers for GPE %02X-%02X: " |
"RunEnable=%02X, WakeEnable=%02X\n", |
gpe_register_info-> |
base_gpe_number, |
gpe_register_info-> |
base_gpe_number + |
(ACPI_GPE_REGISTER_WIDTH - 1), |
gpe_register_info-> |
enable_for_run, |
gpe_register_info-> |
enable_for_wake)); |
continue; |
} |
/* Read the Status Register */ |
status = |
acpi_hw_read(&status_reg, |
&gpe_register_info->status_address); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* Read the Enable Register */ |
status = |
acpi_hw_read(&enable_reg, |
&gpe_register_info->enable_address); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, |
"Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " |
"RunEnable=%02X, WakeEnable=%02X\n", |
gpe_register_info->base_gpe_number, |
gpe_register_info->base_gpe_number + |
(ACPI_GPE_REGISTER_WIDTH - 1), |
status_reg, enable_reg, |
gpe_register_info->enable_for_run, |
gpe_register_info->enable_for_wake)); |
/* Check if there is anything active at all in this register */ |
enabled_status_byte = (u8)(status_reg & enable_reg); |
if (!enabled_status_byte) { |
/* No active GPEs in this register, move on */ |
continue; |
} |
/* Now look at the individual GPEs in this byte register */ |
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { |
/* Examine one GPE bit */ |
gpe_event_info = |
&gpe_block-> |
event_info[((acpi_size) i * |
ACPI_GPE_REGISTER_WIDTH) + j]; |
gpe_number = |
j + gpe_register_info->base_gpe_number; |
if (enabled_status_byte & (1 << j)) { |
/* Invoke global event handler if present */ |
acpi_gpe_count++; |
if (acpi_gbl_global_event_handler) { |
acpi_gbl_global_event_handler |
(ACPI_EVENT_TYPE_GPE, |
gpe_device, gpe_number, |
acpi_gbl_global_event_handler_context); |
} |
/* Found an active GPE */ |
if (ACPI_GPE_DISPATCH_TYPE |
(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_RAW_HANDLER) { |
/* Dispatch the event to a raw handler */ |
gpe_handler_info = |
gpe_event_info->dispatch. |
handler; |
/* |
* There is no protection around the namespace node |
* and the GPE handler to ensure a safe destruction |
* because: |
* 1. The namespace node is expected to always |
* exist after loading a table. |
* 2. The GPE handler is expected to be flushed by |
* acpi_os_wait_events_complete() before the |
* destruction. |
*/ |
acpi_os_release_lock |
(acpi_gbl_gpe_lock, flags); |
int_status |= |
gpe_handler_info-> |
address(gpe_device, |
gpe_number, |
gpe_handler_info-> |
context); |
flags = |
acpi_os_acquire_lock |
(acpi_gbl_gpe_lock); |
} else { |
/* |
* Dispatch the event to a standard handler or |
* method. |
*/ |
int_status |= |
acpi_ev_gpe_dispatch |
(gpe_device, gpe_event_info, |
gpe_number); |
} |
} |
} |
} |
gpe_block = gpe_block->next; |
} |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return (int_status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_asynch_execute_gpe_method |
* |
* PARAMETERS: Context (gpe_event_info) - Info for this GPE |
* |
* RETURN: None |
* |
* DESCRIPTION: Perform the actual execution of a GPE control method. This |
* function is called from an invocation of acpi_os_execute and |
* therefore does NOT execute at interrupt level - so that |
* the control method itself is not executed in the context of |
* an interrupt handler. |
* |
******************************************************************************/ |
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) |
{ |
struct acpi_gpe_event_info *gpe_event_info = context; |
acpi_status status = AE_OK; |
struct acpi_evaluate_info *info; |
struct acpi_gpe_notify_info *notify; |
ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); |
/* Do the correct dispatch - normal method or implicit notify */ |
switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { |
case ACPI_GPE_DISPATCH_NOTIFY: |
/* |
* Implicit notify. |
* Dispatch a DEVICE_WAKE notify to the appropriate handler. |
* NOTE: the request is queued for execution after this method |
* completes. The notify handlers are NOT invoked synchronously |
* from this thread -- because handlers may in turn run other |
* control methods. |
* |
* June 2012: Expand implicit notify mechanism to support |
* notifies on multiple device objects. |
*/ |
notify = gpe_event_info->dispatch.notify_list; |
while (ACPI_SUCCESS(status) && notify) { |
status = |
acpi_ev_queue_notify_request(notify->device_node, |
ACPI_NOTIFY_DEVICE_WAKE); |
notify = notify->next; |
} |
break; |
case ACPI_GPE_DISPATCH_METHOD: |
/* Allocate the evaluation information block */ |
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
status = AE_NO_MEMORY; |
} else { |
/* |
* Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the |
* _Lxx/_Exx control method that corresponds to this GPE |
*/ |
info->prefix_node = |
gpe_event_info->dispatch.method_node; |
info->flags = ACPI_IGNORE_RETURN_VALUE; |
status = acpi_ns_evaluate(info); |
ACPI_FREE(info); |
} |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"while evaluating GPE method [%4.4s]", |
acpi_ut_get_node_name(gpe_event_info-> |
dispatch. |
method_node))); |
} |
break; |
default: |
goto error_exit; /* Should never happen */ |
} |
/* Defer enabling of GPE until all notify handlers are done */ |
status = acpi_os_execute(OSL_NOTIFY_HANDLER, |
acpi_ev_asynch_enable_gpe, gpe_event_info); |
if (ACPI_SUCCESS(status)) { |
return_VOID; |
} |
error_exit: |
acpi_ev_asynch_enable_gpe(gpe_event_info); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_asynch_enable_gpe |
* |
* PARAMETERS: Context (gpe_event_info) - Info for this GPE |
* Callback from acpi_os_execute |
* |
* RETURN: None |
* |
* DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to |
* complete (i.e., finish execution of Notify) |
* |
******************************************************************************/ |
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) |
{ |
struct acpi_gpe_event_info *gpe_event_info = context; |
acpi_cpu_flags flags; |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
(void)acpi_ev_finish_gpe(gpe_event_info); |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_finish_gpe |
* |
* PARAMETERS: gpe_event_info - Info for this GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution |
* of a GPE method or a synchronous or asynchronous GPE handler. |
* |
******************************************************************************/ |
acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info) |
{ |
acpi_status status; |
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == |
ACPI_GPE_LEVEL_TRIGGERED) { |
/* |
* GPE is level-triggered, we clear the GPE status bit after |
* handling the event. |
*/ |
status = acpi_hw_clear_gpe(gpe_event_info); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
/* |
* Enable this GPE, conditionally. This means that the GPE will |
* only be physically enabled if the enable_mask bit is set |
* in the event_info. |
*/ |
(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_gpe_dispatch |
* |
* PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 |
* gpe_event_info - Info for this GPE |
* gpe_number - Number relative to the parent GPE block |
* |
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
* |
* DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) |
* or method (e.g. _Lxx/_Exx) handler. |
* |
* This function executes at interrupt level. |
* |
******************************************************************************/ |
u32 |
acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, |
struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) |
{ |
acpi_status status; |
u32 return_value; |
ACPI_FUNCTION_TRACE(ev_gpe_dispatch); |
/* |
* Always disable the GPE so that it does not keep firing before |
* any asynchronous activity completes (either from the execution |
* of a GPE method or an asynchronous GPE handler.) |
* |
* If there is no handler or method to run, just disable the |
* GPE and leave it disabled permanently to prevent further such |
* pointless events from firing. |
*/ |
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Unable to disable GPE %02X", gpe_number)); |
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); |
} |
/* |
* If edge-triggered, clear the GPE status bit now. Note that |
* level-triggered events are cleared after the GPE is serviced. |
*/ |
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == |
ACPI_GPE_EDGE_TRIGGERED) { |
status = acpi_hw_clear_gpe(gpe_event_info); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Unable to clear GPE %02X", |
gpe_number)); |
(void)acpi_hw_low_set_gpe(gpe_event_info, |
ACPI_GPE_CONDITIONAL_ENABLE); |
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); |
} |
} |
/* |
* Dispatch the GPE to either an installed handler or the control |
* method associated with this GPE (_Lxx or _Exx). If a handler |
* exists, we invoke it and do not attempt to run the method. |
* If there is neither a handler nor a method, leave the GPE |
* disabled. |
*/ |
switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { |
case ACPI_GPE_DISPATCH_HANDLER: |
/* Invoke the installed handler (at interrupt level) */ |
return_value = |
gpe_event_info->dispatch.handler->address(gpe_device, |
gpe_number, |
gpe_event_info-> |
dispatch.handler-> |
context); |
/* If requested, clear (if level-triggered) and reenable the GPE */ |
if (return_value & ACPI_REENABLE_GPE) { |
(void)acpi_ev_finish_gpe(gpe_event_info); |
} |
break; |
case ACPI_GPE_DISPATCH_METHOD: |
case ACPI_GPE_DISPATCH_NOTIFY: |
/* |
* Execute the method associated with the GPE |
* NOTE: Level-triggered GPEs are cleared after the method completes. |
*/ |
status = acpi_os_execute(OSL_GPE_HANDLER, |
acpi_ev_asynch_execute_gpe_method, |
gpe_event_info); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Unable to queue handler for GPE %02X - event disabled", |
gpe_number)); |
} |
break; |
default: |
/* |
* No handler or method to run! |
* 03/2010: This case should no longer be possible. We will not allow |
* a GPE to be enabled if it has no handler or method. |
*/ |
ACPI_ERROR((AE_INFO, |
"No handler or method for GPE %02X, disabling event", |
gpe_number)); |
break; |
} |
return_UINT32(ACPI_INTERRUPT_HANDLED); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evgpeblk.c |
---|
0,0 → 1,513 |
/****************************************************************************** |
* |
* Module Name: evgpeblk - GPE block creation and initialization. |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evgpeblk") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/* Local prototypes */ |
static acpi_status |
acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, |
u32 interrupt_number); |
static acpi_status |
acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_install_gpe_block |
* |
* PARAMETERS: gpe_block - New GPE block |
* interrupt_number - Xrupt to be associated with this |
* GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install new GPE block with mutex support |
* |
******************************************************************************/ |
static acpi_status |
acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, |
u32 interrupt_number) |
{ |
struct acpi_gpe_block_info *next_gpe_block; |
struct acpi_gpe_xrupt_info *gpe_xrupt_block; |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(ev_install_gpe_block); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = |
acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* Install the new block at the end of the list with lock */ |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
if (gpe_xrupt_block->gpe_block_list_head) { |
next_gpe_block = gpe_xrupt_block->gpe_block_list_head; |
while (next_gpe_block->next) { |
next_gpe_block = next_gpe_block->next; |
} |
next_gpe_block->next = gpe_block; |
gpe_block->previous = next_gpe_block; |
} else { |
gpe_xrupt_block->gpe_block_list_head = gpe_block; |
} |
gpe_block->xrupt_block = gpe_xrupt_block; |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_delete_gpe_block |
* |
* PARAMETERS: gpe_block - Existing GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a GPE block |
* |
******************************************************************************/ |
acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) |
{ |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(ev_install_gpe_block); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Disable all GPEs in this block */ |
status = |
acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL); |
if (!gpe_block->previous && !gpe_block->next) { |
/* This is the last gpe_block on this interrupt */ |
status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
} else { |
/* Remove the block on this interrupt with lock */ |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
if (gpe_block->previous) { |
gpe_block->previous->next = gpe_block->next; |
} else { |
gpe_block->xrupt_block->gpe_block_list_head = |
gpe_block->next; |
} |
if (gpe_block->next) { |
gpe_block->next->previous = gpe_block->previous; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
} |
acpi_current_gpe_count -= gpe_block->gpe_count; |
/* Free the gpe_block */ |
ACPI_FREE(gpe_block->register_info); |
ACPI_FREE(gpe_block->event_info); |
ACPI_FREE(gpe_block); |
unlock_and_exit: |
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_create_gpe_info_blocks |
* |
* PARAMETERS: gpe_block - New GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create the register_info and event_info blocks for this GPE block |
* |
******************************************************************************/ |
static acpi_status |
acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) |
{ |
struct acpi_gpe_register_info *gpe_register_info = NULL; |
struct acpi_gpe_event_info *gpe_event_info = NULL; |
struct acpi_gpe_event_info *this_event; |
struct acpi_gpe_register_info *this_register; |
u32 i; |
u32 j; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks); |
/* Allocate the GPE register information block */ |
gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block-> |
register_count * |
sizeof(struct |
acpi_gpe_register_info)); |
if (!gpe_register_info) { |
ACPI_ERROR((AE_INFO, |
"Could not allocate the GpeRegisterInfo table")); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* |
* Allocate the GPE event_info block. There are eight distinct GPEs |
* per register. Initialization to zeros is sufficient. |
*/ |
gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->gpe_count * |
sizeof(struct |
acpi_gpe_event_info)); |
if (!gpe_event_info) { |
ACPI_ERROR((AE_INFO, |
"Could not allocate the GpeEventInfo table")); |
status = AE_NO_MEMORY; |
goto error_exit; |
} |
/* Save the new Info arrays in the GPE block */ |
gpe_block->register_info = gpe_register_info; |
gpe_block->event_info = gpe_event_info; |
/* |
* Initialize the GPE Register and Event structures. A goal of these |
* tables is to hide the fact that there are two separate GPE register |
* sets in a given GPE hardware block, the status registers occupy the |
* first half, and the enable registers occupy the second half. |
*/ |
this_register = gpe_register_info; |
this_event = gpe_event_info; |
for (i = 0; i < gpe_block->register_count; i++) { |
/* Init the register_info for this GPE register (8 GPEs) */ |
this_register->base_gpe_number = (u16) |
(gpe_block->block_base_number + |
(i * ACPI_GPE_REGISTER_WIDTH)); |
this_register->status_address.address = gpe_block->address + i; |
this_register->enable_address.address = |
gpe_block->address + i + gpe_block->register_count; |
this_register->status_address.space_id = gpe_block->space_id; |
this_register->enable_address.space_id = gpe_block->space_id; |
this_register->status_address.bit_width = |
ACPI_GPE_REGISTER_WIDTH; |
this_register->enable_address.bit_width = |
ACPI_GPE_REGISTER_WIDTH; |
this_register->status_address.bit_offset = 0; |
this_register->enable_address.bit_offset = 0; |
/* Init the event_info for each GPE within this register */ |
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { |
this_event->gpe_number = |
(u8) (this_register->base_gpe_number + j); |
this_event->register_info = this_register; |
this_event++; |
} |
/* Disable all GPEs within this register */ |
status = acpi_hw_write(0x00, &this_register->enable_address); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
/* Clear any pending GPE events within this register */ |
status = acpi_hw_write(0xFF, &this_register->status_address); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
this_register++; |
} |
return_ACPI_STATUS(AE_OK); |
error_exit: |
if (gpe_register_info) { |
ACPI_FREE(gpe_register_info); |
} |
if (gpe_event_info) { |
ACPI_FREE(gpe_event_info); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_create_gpe_block |
* |
* PARAMETERS: gpe_device - Handle to the parent GPE block |
* gpe_block_address - Address and space_ID |
* register_count - Number of GPE register pairs in the block |
* gpe_block_base_number - Starting GPE number for the block |
* interrupt_number - H/W interrupt for the block |
* return_gpe_block - Where the new block descriptor is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create and Install a block of GPE registers. All GPEs within |
* the block are disabled at exit. |
* Note: Assumes namespace is locked. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, |
u64 address, |
u8 space_id, |
u32 register_count, |
u16 gpe_block_base_number, |
u32 interrupt_number, |
struct acpi_gpe_block_info **return_gpe_block) |
{ |
acpi_status status; |
struct acpi_gpe_block_info *gpe_block; |
struct acpi_gpe_walk_info walk_info; |
ACPI_FUNCTION_TRACE(ev_create_gpe_block); |
if (!register_count) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Allocate a new GPE block */ |
gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info)); |
if (!gpe_block) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Initialize the new GPE block */ |
gpe_block->address = address; |
gpe_block->space_id = space_id; |
gpe_block->node = gpe_device; |
gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH); |
gpe_block->initialized = FALSE; |
gpe_block->register_count = register_count; |
gpe_block->block_base_number = gpe_block_base_number; |
/* |
* Create the register_info and event_info sub-structures |
* Note: disables and clears all GPEs in the block |
*/ |
status = acpi_ev_create_gpe_info_blocks(gpe_block); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(gpe_block); |
return_ACPI_STATUS(status); |
} |
/* Install the new block in the global lists */ |
status = acpi_ev_install_gpe_block(gpe_block, interrupt_number); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(gpe_block->register_info); |
ACPI_FREE(gpe_block->event_info); |
ACPI_FREE(gpe_block); |
return_ACPI_STATUS(status); |
} |
acpi_gbl_all_gpes_initialized = FALSE; |
/* Find all GPE methods (_Lxx or_Exx) for this block */ |
walk_info.gpe_block = gpe_block; |
walk_info.gpe_device = gpe_device; |
walk_info.execute_by_owner_id = FALSE; |
status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device, |
ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, |
acpi_ev_match_gpe_method, NULL, |
&walk_info, NULL); |
/* Return the new block */ |
if (return_gpe_block) { |
(*return_gpe_block) = gpe_block; |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
" Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n", |
(u32)gpe_block->block_base_number, |
(u32)(gpe_block->block_base_number + |
(gpe_block->gpe_count - 1)), |
gpe_device->name.ascii, gpe_block->register_count, |
interrupt_number, |
interrupt_number == |
acpi_gbl_FADT.sci_interrupt ? " (SCI)" : "")); |
/* Update global count of currently available GPEs */ |
acpi_current_gpe_count += gpe_block->gpe_count; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_initialize_gpe_block |
* |
* PARAMETERS: acpi_gpe_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have |
* associated methods. |
* Note: Assumes namespace is locked. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *ignored) |
{ |
acpi_status status; |
struct acpi_gpe_event_info *gpe_event_info; |
u32 gpe_enabled_count; |
u32 gpe_index; |
u32 i; |
u32 j; |
ACPI_FUNCTION_TRACE(ev_initialize_gpe_block); |
/* |
* Ignore a null GPE block (e.g., if no GPE block 1 exists), and |
* any GPE blocks that have been initialized already. |
*/ |
if (!gpe_block || gpe_block->initialized) { |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Enable all GPEs that have a corresponding method and have the |
* ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block |
* must be enabled via the acpi_enable_gpe() interface. |
*/ |
gpe_enabled_count = 0; |
for (i = 0; i < gpe_block->register_count; i++) { |
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { |
/* Get the info block for this particular GPE */ |
gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j; |
gpe_event_info = &gpe_block->event_info[gpe_index]; |
/* |
* Ignore GPEs that have no corresponding _Lxx/_Exx method |
* and GPEs that are used to wake the system |
*/ |
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_NONE) |
|| (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_HANDLER) |
|| (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_RAW_HANDLER) |
|| (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { |
continue; |
} |
status = acpi_ev_add_gpe_reference(gpe_event_info); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not enable GPE 0x%02X", |
gpe_index + |
gpe_block->block_base_number)); |
continue; |
} |
gpe_enabled_count++; |
} |
} |
if (gpe_enabled_count) { |
ACPI_INFO((AE_INFO, |
"Enabled %u GPEs in block %02X to %02X", |
gpe_enabled_count, (u32)gpe_block->block_base_number, |
(u32)(gpe_block->block_base_number + |
(gpe_block->gpe_count - 1)))); |
} |
gpe_block->initialized = TRUE; |
return_ACPI_STATUS(AE_OK); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evgpeinit.c |
---|
0,0 → 1,446 |
/****************************************************************************** |
* |
* Module Name: evgpeinit - System GPE initialization and update |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evgpeinit") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/* |
* Note: History of _PRW support in ACPICA |
* |
* Originally (2000 - 2010), the GPE initialization code performed a walk of |
* the entire namespace to execute the _PRW methods and detect all GPEs |
* capable of waking the system. |
* |
* As of 10/2010, the _PRW method execution has been removed since it is |
* actually unnecessary. The host OS must in fact execute all _PRW methods |
* in order to identify the device/power-resource dependencies. We now put |
* the onus on the host OS to identify the wake GPEs as part of this process |
* and to inform ACPICA of these GPEs via the acpi_setup_gpe_for_wake interface. This |
* not only reduces the complexity of the ACPICA initialization code, but in |
* some cases (on systems with very large namespaces) it should reduce the |
* kernel boot time as well. |
*/ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_gpe_initialize |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize the GPE data structures and the FADT GPE 0/1 blocks |
* |
******************************************************************************/ |
acpi_status acpi_ev_gpe_initialize(void) |
{ |
u32 register_count0 = 0; |
u32 register_count1 = 0; |
u32 gpe_number_max = 0; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_gpe_initialize); |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
"Initializing General Purpose Events (GPEs):\n")); |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Initialize the GPE Block(s) defined in the FADT |
* |
* Why the GPE register block lengths are divided by 2: From the ACPI |
* Spec, section "General-Purpose Event Registers", we have: |
* |
* "Each register block contains two registers of equal length |
* GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the |
* GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN |
* The length of the GPE1_STS and GPE1_EN registers is equal to |
* half the GPE1_LEN. If a generic register block is not supported |
* then its respective block pointer and block length values in the |
* FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need |
* to be the same size." |
*/ |
/* |
* Determine the maximum GPE number for this machine. |
* |
* Note: both GPE0 and GPE1 are optional, and either can exist without |
* the other. |
* |
* If EITHER the register length OR the block address are zero, then that |
* particular block is not supported. |
*/ |
if (acpi_gbl_FADT.gpe0_block_length && |
acpi_gbl_FADT.xgpe0_block.address) { |
/* GPE block 0 exists (has both length and address > 0) */ |
register_count0 = (u16)(acpi_gbl_FADT.gpe0_block_length / 2); |
gpe_number_max = |
(register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1; |
/* Install GPE Block 0 */ |
status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, |
acpi_gbl_FADT.xgpe0_block. |
address, |
acpi_gbl_FADT.xgpe0_block. |
space_id, register_count0, 0, |
acpi_gbl_FADT.sci_interrupt, |
&acpi_gbl_gpe_fadt_blocks[0]); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not create GPE Block 0")); |
} |
} |
if (acpi_gbl_FADT.gpe1_block_length && |
acpi_gbl_FADT.xgpe1_block.address) { |
/* GPE block 1 exists (has both length and address > 0) */ |
register_count1 = (u16)(acpi_gbl_FADT.gpe1_block_length / 2); |
/* Check for GPE0/GPE1 overlap (if both banks exist) */ |
if ((register_count0) && |
(gpe_number_max >= acpi_gbl_FADT.gpe1_base)) { |
ACPI_ERROR((AE_INFO, |
"GPE0 block (GPE 0 to %u) overlaps the GPE1 block " |
"(GPE %u to %u) - Ignoring GPE1", |
gpe_number_max, acpi_gbl_FADT.gpe1_base, |
acpi_gbl_FADT.gpe1_base + |
((register_count1 * |
ACPI_GPE_REGISTER_WIDTH) - 1))); |
/* Ignore GPE1 block by setting the register count to zero */ |
register_count1 = 0; |
} else { |
/* Install GPE Block 1 */ |
status = |
acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, |
acpi_gbl_FADT.xgpe1_block. |
address, |
acpi_gbl_FADT.xgpe1_block. |
space_id, register_count1, |
acpi_gbl_FADT.gpe1_base, |
acpi_gbl_FADT. |
sci_interrupt, |
&acpi_gbl_gpe_fadt_blocks |
[1]); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not create GPE Block 1")); |
} |
/* |
* GPE0 and GPE1 do not have to be contiguous in the GPE number |
* space. However, GPE0 always starts at GPE number zero. |
*/ |
gpe_number_max = acpi_gbl_FADT.gpe1_base + |
((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); |
} |
} |
/* Exit if there are no GPE registers */ |
if ((register_count0 + register_count1) == 0) { |
/* GPEs are not required by ACPI, this is OK */ |
ACPI_DEBUG_PRINT((ACPI_DB_INIT, |
"There are no GPE blocks defined in the FADT\n")); |
status = AE_OK; |
goto cleanup; |
} |
cleanup: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_update_gpes |
* |
* PARAMETERS: table_owner_id - ID of the newly-loaded ACPI table |
* |
* RETURN: None |
* |
* DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a |
* result of a Load() or load_table() operation. If new GPE |
* methods have been installed, register the new methods. |
* |
******************************************************************************/ |
void acpi_ev_update_gpes(acpi_owner_id table_owner_id) |
{ |
struct acpi_gpe_xrupt_info *gpe_xrupt_info; |
struct acpi_gpe_block_info *gpe_block; |
struct acpi_gpe_walk_info walk_info; |
acpi_status status = AE_OK; |
/* |
* Find any _Lxx/_Exx GPE methods that have just been loaded. |
* |
* Any GPEs that correspond to new _Lxx/_Exx methods are immediately |
* enabled. |
* |
* Examine the namespace underneath each gpe_device within the |
* gpe_block lists. |
*/ |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return; |
} |
walk_info.count = 0; |
walk_info.owner_id = table_owner_id; |
walk_info.execute_by_owner_id = TRUE; |
/* Walk the interrupt level descriptor list */ |
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; |
while (gpe_xrupt_info) { |
/* Walk all Gpe Blocks attached to this interrupt level */ |
gpe_block = gpe_xrupt_info->gpe_block_list_head; |
while (gpe_block) { |
walk_info.gpe_block = gpe_block; |
walk_info.gpe_device = gpe_block->node; |
status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, |
walk_info.gpe_device, |
ACPI_UINT32_MAX, |
ACPI_NS_WALK_NO_UNLOCK, |
acpi_ev_match_gpe_method, |
NULL, &walk_info, NULL); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"While decoding _Lxx/_Exx methods")); |
} |
gpe_block = gpe_block->next; |
} |
gpe_xrupt_info = gpe_xrupt_info->next; |
} |
if (walk_info.count) { |
ACPI_INFO((AE_INFO, "Enabled %u new GPEs", walk_info.count)); |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_match_gpe_method |
* |
* PARAMETERS: Callback from walk_namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a |
* control method under the _GPE portion of the namespace. |
* Extract the name and GPE type from the object, saving this |
* information for quick lookup during GPE dispatch. Allows a |
* per-owner_id evaluation if execute_by_owner_id is TRUE in the |
* walk_info parameter block. |
* |
* The name of each GPE control method is of the form: |
* "_Lxx" or "_Exx", where: |
* L - means that the GPE is level triggered |
* E - means that the GPE is edge triggered |
* xx - is the GPE number [in HEX] |
* |
* If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods |
* with that owner. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_match_gpe_method(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
struct acpi_namespace_node *method_node = |
ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
struct acpi_gpe_walk_info *walk_info = |
ACPI_CAST_PTR(struct acpi_gpe_walk_info, context); |
struct acpi_gpe_event_info *gpe_event_info; |
u32 gpe_number; |
char name[ACPI_NAME_SIZE + 1]; |
u8 type; |
ACPI_FUNCTION_TRACE(ev_match_gpe_method); |
/* Check if requested owner_id matches this owner_id */ |
if ((walk_info->execute_by_owner_id) && |
(method_node->owner_id != walk_info->owner_id)) { |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Match and decode the _Lxx and _Exx GPE method names |
* |
* 1) Extract the method name and null terminate it |
*/ |
ACPI_MOVE_32_TO_32(name, &method_node->name.integer); |
name[ACPI_NAME_SIZE] = 0; |
/* 2) Name must begin with an underscore */ |
if (name[0] != '_') { |
return_ACPI_STATUS(AE_OK); /* Ignore this method */ |
} |
/* |
* 3) Edge/Level determination is based on the 2nd character |
* of the method name |
*/ |
switch (name[1]) { |
case 'L': |
type = ACPI_GPE_LEVEL_TRIGGERED; |
break; |
case 'E': |
type = ACPI_GPE_EDGE_TRIGGERED; |
break; |
default: |
/* Unknown method type, just ignore it */ |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
"Ignoring unknown GPE method type: %s " |
"(name not of form _Lxx or _Exx)", name)); |
return_ACPI_STATUS(AE_OK); |
} |
/* 4) The last two characters of the name are the hex GPE Number */ |
gpe_number = strtoul(&name[2], NULL, 16); |
if (gpe_number == ACPI_UINT32_MAX) { |
/* Conversion failed; invalid method, just ignore it */ |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
"Could not extract GPE number from name: %s " |
"(name is not of form _Lxx or _Exx)", name)); |
return_ACPI_STATUS(AE_OK); |
} |
/* Ensure that we have a valid GPE number for this GPE block */ |
gpe_event_info = |
acpi_ev_low_get_gpe_info(gpe_number, walk_info->gpe_block); |
if (!gpe_event_info) { |
/* |
* This gpe_number is not valid for this GPE block, just ignore it. |
* However, it may be valid for a different GPE block, since GPE0 |
* and GPE1 methods both appear under \_GPE. |
*/ |
return_ACPI_STATUS(AE_OK); |
} |
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_HANDLER) || |
(ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_RAW_HANDLER)) { |
/* If there is already a handler, ignore this GPE method */ |
return_ACPI_STATUS(AE_OK); |
} |
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_METHOD) { |
/* |
* If there is already a method, ignore this method. But check |
* for a type mismatch (if both the _Lxx AND _Exx exist) |
*/ |
if (type != (gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) { |
ACPI_ERROR((AE_INFO, |
"For GPE 0x%.2X, found both _L%2.2X and _E%2.2X methods", |
gpe_number, gpe_number, gpe_number)); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* Disable the GPE in case it's been enabled already. */ |
(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); |
/* |
* Add the GPE information from above to the gpe_event_info block for |
* use during dispatch of this GPE. |
*/ |
gpe_event_info->flags &= ~(ACPI_GPE_DISPATCH_MASK); |
gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD); |
gpe_event_info->dispatch.method_node = method_node; |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
"Registered GPE method %s as GPE number 0x%.2X\n", |
name, gpe_number)); |
return_ACPI_STATUS(AE_OK); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evgpeutil.c |
---|
0,0 → 1,359 |
/****************************************************************************** |
* |
* Module Name: evgpeutil - GPE utilities |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evgpeutil") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_walk_gpe_list |
* |
* PARAMETERS: gpe_walk_callback - Routine called for each GPE block |
* context - Value passed to callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walk the GPE lists. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context) |
{ |
struct acpi_gpe_block_info *gpe_block; |
struct acpi_gpe_xrupt_info *gpe_xrupt_info; |
acpi_status status = AE_OK; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(ev_walk_gpe_list); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Walk the interrupt level descriptor list */ |
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; |
while (gpe_xrupt_info) { |
/* Walk all Gpe Blocks attached to this interrupt level */ |
gpe_block = gpe_xrupt_info->gpe_block_list_head; |
while (gpe_block) { |
/* One callback per GPE block */ |
status = |
gpe_walk_callback(gpe_xrupt_info, gpe_block, |
context); |
if (ACPI_FAILURE(status)) { |
if (status == AE_CTRL_END) { /* Callback abort */ |
status = AE_OK; |
} |
goto unlock_and_exit; |
} |
gpe_block = gpe_block->next; |
} |
gpe_xrupt_info = gpe_xrupt_info->next; |
} |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_get_gpe_device |
* |
* PARAMETERS: GPE_WALK_CALLBACK |
* |
* RETURN: Status |
* |
* DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE |
* block device. NULL if the GPE is one of the FADT-defined GPEs. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, void *context) |
{ |
struct acpi_gpe_device_info *info = context; |
/* Increment Index by the number of GPEs in this block */ |
info->next_block_base_index += gpe_block->gpe_count; |
if (info->index < info->next_block_base_index) { |
/* |
* The GPE index is within this block, get the node. Leave the node |
* NULL for the FADT-defined GPEs |
*/ |
if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) { |
info->gpe_device = gpe_block->node; |
} |
info->status = AE_OK; |
return (AE_CTRL_END); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_get_gpe_xrupt_block |
* |
* PARAMETERS: interrupt_number - Interrupt for a GPE block |
* gpe_xrupt_block - Where the block is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt |
* block per unique interrupt level used for GPEs. Should be |
* called only when the GPE lists are semaphore locked and not |
* subject to change. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_get_gpe_xrupt_block(u32 interrupt_number, |
struct acpi_gpe_xrupt_info ** gpe_xrupt_block) |
{ |
struct acpi_gpe_xrupt_info *next_gpe_xrupt; |
struct acpi_gpe_xrupt_info *gpe_xrupt; |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block); |
/* No need for lock since we are not changing any list elements here */ |
next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; |
while (next_gpe_xrupt) { |
if (next_gpe_xrupt->interrupt_number == interrupt_number) { |
*gpe_xrupt_block = next_gpe_xrupt; |
return_ACPI_STATUS(AE_OK); |
} |
next_gpe_xrupt = next_gpe_xrupt->next; |
} |
/* Not found, must allocate a new xrupt descriptor */ |
gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info)); |
if (!gpe_xrupt) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
gpe_xrupt->interrupt_number = interrupt_number; |
/* Install new interrupt descriptor with spin lock */ |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
if (acpi_gbl_gpe_xrupt_list_head) { |
next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; |
while (next_gpe_xrupt->next) { |
next_gpe_xrupt = next_gpe_xrupt->next; |
} |
next_gpe_xrupt->next = gpe_xrupt; |
gpe_xrupt->previous = next_gpe_xrupt; |
} else { |
acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
/* Install new interrupt handler if not SCI_INT */ |
if (interrupt_number != acpi_gbl_FADT.sci_interrupt) { |
status = acpi_os_install_interrupt_handler(interrupt_number, |
acpi_ev_gpe_xrupt_handler, |
gpe_xrupt); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not install GPE interrupt handler at level 0x%X", |
interrupt_number)); |
return_ACPI_STATUS(status); |
} |
} |
*gpe_xrupt_block = gpe_xrupt; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_delete_gpe_xrupt |
* |
* PARAMETERS: gpe_xrupt - A GPE interrupt info block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated |
* interrupt handler if not the SCI interrupt. |
* |
******************************************************************************/ |
acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) |
{ |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt); |
/* We never want to remove the SCI interrupt handler */ |
if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) { |
gpe_xrupt->gpe_block_list_head = NULL; |
return_ACPI_STATUS(AE_OK); |
} |
/* Disable this interrupt */ |
status = |
acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number, |
acpi_ev_gpe_xrupt_handler); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Unlink the interrupt block with lock */ |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
if (gpe_xrupt->previous) { |
gpe_xrupt->previous->next = gpe_xrupt->next; |
} else { |
/* No previous, update list head */ |
acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next; |
} |
if (gpe_xrupt->next) { |
gpe_xrupt->next->previous = gpe_xrupt->previous; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
/* Free the block */ |
ACPI_FREE(gpe_xrupt); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_delete_gpe_handlers |
* |
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info |
* gpe_block - Gpe Block info |
* |
* RETURN: Status |
* |
* DESCRIPTION: Delete all Handler objects found in the GPE data structs. |
* Used only prior to termination. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *context) |
{ |
struct acpi_gpe_event_info *gpe_event_info; |
struct acpi_gpe_notify_info *notify; |
struct acpi_gpe_notify_info *next; |
u32 i; |
u32 j; |
ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers); |
/* Examine each GPE Register within the block */ |
for (i = 0; i < gpe_block->register_count; i++) { |
/* Now look at the individual GPEs in this byte register */ |
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { |
gpe_event_info = &gpe_block->event_info[((acpi_size) i * |
ACPI_GPE_REGISTER_WIDTH) |
+ j]; |
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_HANDLER) || |
(ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_RAW_HANDLER)) { |
/* Delete an installed handler block */ |
ACPI_FREE(gpe_event_info->dispatch.handler); |
gpe_event_info->dispatch.handler = NULL; |
gpe_event_info->flags &= |
~ACPI_GPE_DISPATCH_MASK; |
} else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) |
== ACPI_GPE_DISPATCH_NOTIFY) { |
/* Delete the implicit notification device list */ |
notify = gpe_event_info->dispatch.notify_list; |
while (notify) { |
next = notify->next; |
ACPI_FREE(notify); |
notify = next; |
} |
gpe_event_info->dispatch.notify_list = NULL; |
gpe_event_info->flags &= |
~ACPI_GPE_DISPATCH_MASK; |
} |
} |
} |
return_ACPI_STATUS(AE_OK); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evhandler.c |
---|
0,0 → 1,536 |
/****************************************************************************** |
* |
* Module Name: evhandler - Support for Address Space handlers |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evhandler") |
/* Local prototypes */ |
static acpi_status |
acpi_ev_install_handler(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
/* These are the address spaces that will get default handlers */ |
u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { |
ACPI_ADR_SPACE_SYSTEM_MEMORY, |
ACPI_ADR_SPACE_SYSTEM_IO, |
ACPI_ADR_SPACE_PCI_CONFIG, |
ACPI_ADR_SPACE_DATA_TABLE |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_install_region_handlers |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Installs the core subsystem default address space handlers. |
* |
******************************************************************************/ |
acpi_status acpi_ev_install_region_handlers(void) |
{ |
acpi_status status; |
u32 i; |
ACPI_FUNCTION_TRACE(ev_install_region_handlers); |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* All address spaces (PCI Config, EC, SMBus) are scope dependent and |
* registration must occur for a specific device. |
* |
* In the case of the system memory and IO address spaces there is |
* currently no device associated with the address space. For these we |
* use the root. |
* |
* We install the default PCI config space handler at the root so that |
* this space is immediately available even though the we have not |
* enumerated all the PCI Root Buses yet. This is to conform to the ACPI |
* specification which states that the PCI config space must be always |
* available -- even though we are nowhere near ready to find the PCI root |
* buses at this point. |
* |
* NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler |
* has already been installed (via acpi_install_address_space_handler). |
* Similar for AE_SAME_HANDLER. |
*/ |
for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { |
status = acpi_ev_install_space_handler(acpi_gbl_root_node, |
acpi_gbl_default_address_spaces |
[i], |
ACPI_DEFAULT_HANDLER, |
NULL, NULL); |
switch (status) { |
case AE_OK: |
case AE_SAME_HANDLER: |
case AE_ALREADY_EXISTS: |
/* These exceptions are all OK */ |
status = AE_OK; |
break; |
default: |
goto unlock_and_exit; |
} |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_has_default_handler |
* |
* PARAMETERS: node - Namespace node for the device |
* space_id - The address space ID |
* |
* RETURN: TRUE if default handler is installed, FALSE otherwise |
* |
* DESCRIPTION: Check if the default handler is installed for the requested |
* space ID. |
* |
******************************************************************************/ |
u8 |
acpi_ev_has_default_handler(struct acpi_namespace_node *node, |
acpi_adr_space_type space_id) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_obj; |
/* Must have an existing internal object */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (obj_desc) { |
handler_obj = obj_desc->device.handler; |
/* Walk the linked list of handlers for this object */ |
while (handler_obj) { |
if (handler_obj->address_space.space_id == space_id) { |
if (handler_obj->address_space.handler_flags & |
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { |
return (TRUE); |
} |
} |
handler_obj = handler_obj->address_space.next; |
} |
} |
return (FALSE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_install_handler |
* |
* PARAMETERS: walk_namespace callback |
* |
* DESCRIPTION: This routine installs an address handler into objects that are |
* of type Region or Device. |
* |
* If the Object is a Device, and the device has a handler of |
* the same type then the search is terminated in that branch. |
* |
* This is because the existing handler is closer in proximity |
* to any more regions than the one we are trying to install. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ev_install_handler(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
union acpi_operand_object *handler_obj; |
union acpi_operand_object *next_handler_obj; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
acpi_status status; |
ACPI_FUNCTION_NAME(ev_install_handler); |
handler_obj = (union acpi_operand_object *)context; |
/* Parameter validation */ |
if (!handler_obj) { |
return (AE_OK); |
} |
/* Convert and validate the device handle */ |
node = acpi_ns_validate_handle(obj_handle); |
if (!node) { |
return (AE_BAD_PARAMETER); |
} |
/* |
* We only care about regions and objects that are allowed to have |
* address space handlers |
*/ |
if ((node->type != ACPI_TYPE_DEVICE) && |
(node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { |
return (AE_OK); |
} |
/* Check for an existing internal object */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
/* No object, just exit */ |
return (AE_OK); |
} |
/* Devices are handled different than regions */ |
if (obj_desc->common.type == ACPI_TYPE_DEVICE) { |
/* Check if this Device already has a handler for this address space */ |
next_handler_obj = obj_desc->device.handler; |
while (next_handler_obj) { |
/* Found a handler, is it for the same address space? */ |
if (next_handler_obj->address_space.space_id == |
handler_obj->address_space.space_id) { |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Found handler for region [%s] in device %p(%p) " |
"handler %p\n", |
acpi_ut_get_region_name |
(handler_obj->address_space. |
space_id), obj_desc, |
next_handler_obj, |
handler_obj)); |
/* |
* Since the object we found it on was a device, then it |
* means that someone has already installed a handler for |
* the branch of the namespace from this device on. Just |
* bail out telling the walk routine to not traverse this |
* branch. This preserves the scoping rule for handlers. |
*/ |
return (AE_CTRL_DEPTH); |
} |
/* Walk the linked list of handlers attached to this device */ |
next_handler_obj = next_handler_obj->address_space.next; |
} |
/* |
* As long as the device didn't have a handler for this space we |
* don't care about it. We just ignore it and proceed. |
*/ |
return (AE_OK); |
} |
/* Object is a Region */ |
if (obj_desc->region.space_id != handler_obj->address_space.space_id) { |
/* This region is for a different address space, just ignore it */ |
return (AE_OK); |
} |
/* |
* Now we have a region and it is for the handler's address space type. |
* |
* First disconnect region for any previous handler (if any) |
*/ |
acpi_ev_detach_region(obj_desc, FALSE); |
/* Connect the region to the new handler */ |
status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_install_space_handler |
* |
* PARAMETERS: node - Namespace node for the device |
* space_id - The address space ID |
* handler - Address of the handler |
* setup - Address of the setup function |
* context - Value passed to the handler on each access |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for all op_regions of a given space_id. |
* Assumes namespace is locked |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_install_space_handler(struct acpi_namespace_node * node, |
acpi_adr_space_type space_id, |
acpi_adr_space_handler handler, |
acpi_adr_space_setup setup, void *context) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_obj; |
acpi_status status; |
acpi_object_type type; |
u8 flags = 0; |
ACPI_FUNCTION_TRACE(ev_install_space_handler); |
/* |
* This registration is valid for only the types below and the root. This |
* is where the default handlers get placed. |
*/ |
if ((node->type != ACPI_TYPE_DEVICE) && |
(node->type != ACPI_TYPE_PROCESSOR) && |
(node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
if (handler == ACPI_DEFAULT_HANDLER) { |
flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; |
switch (space_id) { |
case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
handler = acpi_ex_system_memory_space_handler; |
setup = acpi_ev_system_memory_region_setup; |
break; |
case ACPI_ADR_SPACE_SYSTEM_IO: |
handler = acpi_ex_system_io_space_handler; |
setup = acpi_ev_io_space_region_setup; |
break; |
case ACPI_ADR_SPACE_PCI_CONFIG: |
handler = acpi_ex_pci_config_space_handler; |
setup = acpi_ev_pci_config_region_setup; |
break; |
case ACPI_ADR_SPACE_CMOS: |
handler = acpi_ex_cmos_space_handler; |
setup = acpi_ev_cmos_region_setup; |
break; |
case ACPI_ADR_SPACE_PCI_BAR_TARGET: |
handler = acpi_ex_pci_bar_space_handler; |
setup = acpi_ev_pci_bar_region_setup; |
break; |
case ACPI_ADR_SPACE_DATA_TABLE: |
handler = acpi_ex_data_table_space_handler; |
setup = NULL; |
break; |
default: |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
} |
/* If the caller hasn't specified a setup routine, use the default */ |
if (!setup) { |
setup = acpi_ev_default_region_setup; |
} |
/* Check for an existing internal object */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (obj_desc) { |
/* |
* The attached device object already exists. Make sure the handler |
* is not already installed. |
*/ |
handler_obj = obj_desc->device.handler; |
/* Walk the handler list for this device */ |
while (handler_obj) { |
/* Same space_id indicates a handler already installed */ |
if (handler_obj->address_space.space_id == space_id) { |
if (handler_obj->address_space.handler == |
handler) { |
/* |
* It is (relatively) OK to attempt to install the SAME |
* handler twice. This can easily happen with the |
* PCI_Config space. |
*/ |
status = AE_SAME_HANDLER; |
goto unlock_and_exit; |
} else { |
/* A handler is already installed */ |
status = AE_ALREADY_EXISTS; |
} |
goto unlock_and_exit; |
} |
/* Walk the linked list of handlers */ |
handler_obj = handler_obj->address_space.next; |
} |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Creating object on Device %p while installing handler\n", |
node)); |
/* obj_desc does not exist, create one */ |
if (node->type == ACPI_TYPE_ANY) { |
type = ACPI_TYPE_DEVICE; |
} else { |
type = node->type; |
} |
obj_desc = acpi_ut_create_internal_object(type); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto unlock_and_exit; |
} |
/* Init new descriptor */ |
obj_desc->common.type = (u8)type; |
/* Attach the new object to the Node */ |
status = acpi_ns_attach_object(node, obj_desc, type); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", |
acpi_ut_get_region_name(space_id), space_id, |
acpi_ut_get_node_name(node), node, obj_desc)); |
/* |
* Install the handler |
* |
* At this point there is no existing handler. Just allocate the object |
* for the handler and link it into the list. |
*/ |
handler_obj = |
acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER); |
if (!handler_obj) { |
status = AE_NO_MEMORY; |
goto unlock_and_exit; |
} |
/* Init handler obj */ |
handler_obj->address_space.space_id = (u8)space_id; |
handler_obj->address_space.handler_flags = flags; |
handler_obj->address_space.region_list = NULL; |
handler_obj->address_space.node = node; |
handler_obj->address_space.handler = handler; |
handler_obj->address_space.context = context; |
handler_obj->address_space.setup = setup; |
/* Install at head of Device.address_space list */ |
handler_obj->address_space.next = obj_desc->device.handler; |
/* |
* The Device object is the first reference on the handler_obj. |
* Each region that uses the handler adds a reference. |
*/ |
obj_desc->device.handler = handler_obj; |
/* |
* Walk the namespace finding all of the regions this |
* handler will manage. |
* |
* Start at the device and search the branch toward |
* the leaf nodes until either the leaf is encountered or |
* a device is detected that has an address handler of the |
* same type. |
* |
* In either case, back up and search down the remainder |
* of the branch |
*/ |
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, |
ACPI_NS_WALK_UNLOCK, |
acpi_ev_install_handler, NULL, |
handler_obj, NULL); |
unlock_and_exit: |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/evmisc.c |
---|
0,0 → 1,299 |
/****************************************************************************** |
* |
* Module Name: evmisc - Miscellaneous event manager support functions |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evmisc") |
/* Local prototypes */ |
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_is_notify_object |
* |
* PARAMETERS: node - Node to check |
* |
* RETURN: TRUE if notifies allowed on this object |
* |
* DESCRIPTION: Check type of node for a object that supports notifies. |
* |
* TBD: This could be replaced by a flag bit in the node. |
* |
******************************************************************************/ |
u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node) |
{ |
switch (node->type) { |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_THERMAL: |
/* |
* These are the ONLY objects that can receive ACPI notifications |
*/ |
return (TRUE); |
default: |
return (FALSE); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_queue_notify_request |
* |
* PARAMETERS: node - NS node for the notified object |
* notify_value - Value from the Notify() request |
* |
* RETURN: Status |
* |
* DESCRIPTION: Dispatch a device notification event to a previously |
* installed handler. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_queue_notify_request(struct acpi_namespace_node * node, |
u32 notify_value) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_list_head = NULL; |
union acpi_generic_state *info; |
u8 handler_list_id = 0; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_NAME(ev_queue_notify_request); |
/* Are Notifies allowed on this object? */ |
if (!acpi_ev_is_notify_object(node)) { |
return (AE_TYPE); |
} |
/* Get the correct notify list type (System or Device) */ |
if (notify_value <= ACPI_MAX_SYS_NOTIFY) { |
handler_list_id = ACPI_SYSTEM_HANDLER_LIST; |
} else { |
handler_list_id = ACPI_DEVICE_HANDLER_LIST; |
} |
/* Get the notify object attached to the namespace Node */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (obj_desc) { |
/* We have an attached object, Get the correct handler list */ |
handler_list_head = |
obj_desc->common_notify.notify_list[handler_list_id]; |
} |
/* |
* If there is no notify handler (Global or Local) |
* for this object, just ignore the notify |
*/ |
if (!acpi_gbl_global_notify[handler_list_id].handler |
&& !handler_list_head) { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"No notify handler for Notify, ignoring (%4.4s, %X) node %p\n", |
acpi_ut_get_node_name(node), notify_value, |
node)); |
return (AE_OK); |
} |
/* Setup notify info and schedule the notify dispatcher */ |
info = acpi_ut_create_generic_state(); |
if (!info) { |
return (AE_NO_MEMORY); |
} |
info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY; |
info->notify.node = node; |
info->notify.value = (u16)notify_value; |
info->notify.handler_list_id = handler_list_id; |
info->notify.handler_list_head = handler_list_head; |
info->notify.global = &acpi_gbl_global_notify[handler_list_id]; |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n", |
acpi_ut_get_node_name(node), |
acpi_ut_get_type_name(node->type), notify_value, |
acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY), |
node)); |
status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, |
info); |
if (ACPI_FAILURE(status)) { |
acpi_ut_delete_generic_state(info); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_notify_dispatch |
* |
* PARAMETERS: context - To be passed to the notify handler |
* |
* RETURN: None. |
* |
* DESCRIPTION: Dispatch a device notification event to a previously |
* installed handler. |
* |
******************************************************************************/ |
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) |
{ |
union acpi_generic_state *info = (union acpi_generic_state *)context; |
union acpi_operand_object *handler_obj; |
ACPI_FUNCTION_ENTRY(); |
/* Invoke a global notify handler if installed */ |
if (info->notify.global->handler) { |
info->notify.global->handler(info->notify.node, |
info->notify.value, |
info->notify.global->context); |
} |
/* Now invoke the local notify handler(s) if any are installed */ |
handler_obj = info->notify.handler_list_head; |
while (handler_obj) { |
handler_obj->notify.handler(info->notify.node, |
info->notify.value, |
handler_obj->notify.context); |
handler_obj = |
handler_obj->notify.next[info->notify.handler_list_id]; |
} |
/* All done with the info object */ |
acpi_ut_delete_generic_state(info); |
} |
#if (!ACPI_REDUCED_HARDWARE) |
/****************************************************************************** |
* |
* FUNCTION: acpi_ev_terminate |
* |
* PARAMETERS: none |
* |
* RETURN: none |
* |
* DESCRIPTION: Disable events and free memory allocated for table storage. |
* |
******************************************************************************/ |
void acpi_ev_terminate(void) |
{ |
u32 i; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_terminate); |
if (acpi_gbl_events_initialized) { |
/* |
* Disable all event-related functionality. In all cases, on error, |
* print a message but obviously we don't abort. |
*/ |
/* Disable all fixed events */ |
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
status = acpi_disable_event(i, 0); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not disable fixed event %u", |
(u32) i)); |
} |
} |
/* Disable all GPEs in all GPE blocks */ |
status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); |
status = acpi_ev_remove_global_lock_handler(); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not remove Global Lock handler")); |
} |
acpi_gbl_events_initialized = FALSE; |
} |
/* Remove SCI handlers */ |
status = acpi_ev_remove_all_sci_handlers(); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, "Could not remove SCI handler")); |
} |
/* Deallocate all handler objects installed within GPE info structs */ |
status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL); |
/* Return to original mode if necessary */ |
if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) { |
status = acpi_disable(); |
if (ACPI_FAILURE(status)) { |
ACPI_WARNING((AE_INFO, "AcpiDisable failed")); |
} |
} |
return_VOID; |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evregion.c |
---|
0,0 → 1,809 |
/****************************************************************************** |
* |
* Module Name: evregion - Operation Region support |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evregion") |
extern u8 acpi_gbl_default_address_spaces[]; |
/* Local prototypes */ |
static void |
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node); |
static acpi_status |
acpi_ev_reg_run(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_initialize_op_regions |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute _REG methods for all Operation Regions that have |
* an installed default region handler. |
* |
******************************************************************************/ |
acpi_status acpi_ev_initialize_op_regions(void) |
{ |
acpi_status status; |
u32 i; |
ACPI_FUNCTION_TRACE(ev_initialize_op_regions); |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Run the _REG methods for op_regions in each default address space */ |
for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { |
/* |
* Make sure the installed handler is the DEFAULT handler. If not the |
* default, the _REG methods will have already been run (when the |
* handler was installed) |
*/ |
if (acpi_ev_has_default_handler(acpi_gbl_root_node, |
acpi_gbl_default_address_spaces |
[i])) { |
status = |
acpi_ev_execute_reg_methods(acpi_gbl_root_node, |
acpi_gbl_default_address_spaces |
[i]); |
} |
} |
acpi_gbl_reg_methods_executed = TRUE; |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_address_space_dispatch |
* |
* PARAMETERS: region_obj - Internal region object |
* field_obj - Corresponding field. Can be NULL. |
* function - Read or Write operation |
* region_offset - Where in the region to read or write |
* bit_width - Field width in bits (8, 16, 32, or 64) |
* value - Pointer to in or out value, must be |
* a full 64-bit integer |
* |
* RETURN: Status |
* |
* DESCRIPTION: Dispatch an address space or operation region access to |
* a previously installed handler. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, |
union acpi_operand_object *field_obj, |
u32 function, |
u32 region_offset, u32 bit_width, u64 *value) |
{ |
acpi_status status; |
acpi_adr_space_handler handler; |
acpi_adr_space_setup region_setup; |
union acpi_operand_object *handler_desc; |
union acpi_operand_object *region_obj2; |
void *region_context = NULL; |
struct acpi_connection_info *context; |
acpi_physical_address address; |
ACPI_FUNCTION_TRACE(ev_address_space_dispatch); |
region_obj2 = acpi_ns_get_secondary_object(region_obj); |
if (!region_obj2) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Ensure that there is a handler associated with this region */ |
handler_desc = region_obj->region.handler; |
if (!handler_desc) { |
ACPI_ERROR((AE_INFO, |
"No handler for Region [%4.4s] (%p) [%s]", |
acpi_ut_get_node_name(region_obj->region.node), |
region_obj, |
acpi_ut_get_region_name(region_obj->region. |
space_id))); |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
context = handler_desc->address_space.context; |
/* |
* It may be the case that the region has never been initialized. |
* Some types of regions require special init code |
*/ |
if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { |
/* This region has not been initialized yet, do it */ |
region_setup = handler_desc->address_space.setup; |
if (!region_setup) { |
/* No initialization routine, exit with error */ |
ACPI_ERROR((AE_INFO, |
"No init routine for region(%p) [%s]", |
region_obj, |
acpi_ut_get_region_name(region_obj->region. |
space_id))); |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* |
* We must exit the interpreter because the region setup will |
* potentially execute control methods (for example, the _REG method |
* for this region) |
*/ |
acpi_ex_exit_interpreter(); |
status = region_setup(region_obj, ACPI_REGION_ACTIVATE, |
context, ®ion_context); |
/* Re-enter the interpreter */ |
acpi_ex_enter_interpreter(); |
/* Check for failure of the Region Setup */ |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"During region initialization: [%s]", |
acpi_ut_get_region_name(region_obj-> |
region. |
space_id))); |
return_ACPI_STATUS(status); |
} |
/* Region initialization may have been completed by region_setup */ |
if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { |
region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; |
/* |
* Save the returned context for use in all accesses to |
* the handler for this particular region |
*/ |
if (!(region_obj2->extra.region_context)) { |
region_obj2->extra.region_context = |
region_context; |
} |
} |
} |
/* We have everything we need, we can invoke the address space handler */ |
handler = handler_desc->address_space.handler; |
address = (region_obj->region.address + region_offset); |
/* |
* Special handling for generic_serial_bus and general_purpose_io: |
* There are three extra parameters that must be passed to the |
* handler via the context: |
* 1) Connection buffer, a resource template from Connection() op |
* 2) Length of the above buffer |
* 3) Actual access length from the access_as() op |
* |
* In addition, for general_purpose_io, the Address and bit_width fields |
* are defined as follows: |
* 1) Address is the pin number index of the field (bit offset from |
* the previous Connection) |
* 2) bit_width is the actual bit length of the field (number of pins) |
*/ |
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) && |
context && field_obj) { |
/* Get the Connection (resource_template) buffer */ |
context->connection = field_obj->field.resource_buffer; |
context->length = field_obj->field.resource_length; |
context->access_length = field_obj->field.access_length; |
} |
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) && |
context && field_obj) { |
/* Get the Connection (resource_template) buffer */ |
context->connection = field_obj->field.resource_buffer; |
context->length = field_obj->field.resource_length; |
context->access_length = field_obj->field.access_length; |
address = field_obj->field.pin_number_index; |
bit_width = field_obj->field.bit_length; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n", |
®ion_obj->region.handler->address_space, handler, |
ACPI_FORMAT_UINT64(address), |
acpi_ut_get_region_name(region_obj->region. |
space_id))); |
if (!(handler_desc->address_space.handler_flags & |
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { |
/* |
* For handlers other than the default (supplied) handlers, we must |
* exit the interpreter because the handler *might* block -- we don't |
* know what it will do, so we can't hold the lock on the intepreter. |
*/ |
acpi_ex_exit_interpreter(); |
} |
/* Call the handler */ |
status = handler(function, address, bit_width, value, context, |
region_obj2->extra.region_context); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]", |
acpi_ut_get_region_name(region_obj->region. |
space_id))); |
} |
if (!(handler_desc->address_space.handler_flags & |
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { |
/* |
* We just returned from a non-default handler, we must re-enter the |
* interpreter |
*/ |
acpi_ex_enter_interpreter(); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_detach_region |
* |
* PARAMETERS: region_obj - Region Object |
* acpi_ns_is_locked - Namespace Region Already Locked? |
* |
* RETURN: None |
* |
* DESCRIPTION: Break the association between the handler and the region |
* this is a two way association. |
* |
******************************************************************************/ |
void |
acpi_ev_detach_region(union acpi_operand_object *region_obj, |
u8 acpi_ns_is_locked) |
{ |
union acpi_operand_object *handler_obj; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *start_desc; |
union acpi_operand_object **last_obj_ptr; |
acpi_adr_space_setup region_setup; |
void **region_context; |
union acpi_operand_object *region_obj2; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_detach_region); |
region_obj2 = acpi_ns_get_secondary_object(region_obj); |
if (!region_obj2) { |
return_VOID; |
} |
region_context = ®ion_obj2->extra.region_context; |
/* Get the address handler from the region object */ |
handler_obj = region_obj->region.handler; |
if (!handler_obj) { |
/* This region has no handler, all done */ |
return_VOID; |
} |
/* Find this region in the handler's list */ |
obj_desc = handler_obj->address_space.region_list; |
start_desc = obj_desc; |
last_obj_ptr = &handler_obj->address_space.region_list; |
while (obj_desc) { |
/* Is this the correct Region? */ |
if (obj_desc == region_obj) { |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Removing Region %p from address handler %p\n", |
region_obj, handler_obj)); |
/* This is it, remove it from the handler's list */ |
*last_obj_ptr = obj_desc->region.next; |
obj_desc->region.next = NULL; /* Must clear field */ |
if (acpi_ns_is_locked) { |
status = |
acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_VOID; |
} |
} |
/* Now stop region accesses by executing the _REG method */ |
status = |
acpi_ev_execute_reg_method(region_obj, |
ACPI_REG_DISCONNECT); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"from region _REG, [%s]", |
acpi_ut_get_region_name |
(region_obj->region.space_id))); |
} |
if (acpi_ns_is_locked) { |
status = |
acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_VOID; |
} |
} |
/* |
* If the region has been activated, call the setup handler with |
* the deactivate notification |
*/ |
if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { |
region_setup = handler_obj->address_space.setup; |
status = |
region_setup(region_obj, |
ACPI_REGION_DEACTIVATE, |
handler_obj->address_space. |
context, region_context); |
/* |
* region_context should have been released by the deactivate |
* operation. We don't need access to it anymore here. |
*/ |
if (region_context) { |
*region_context = NULL; |
} |
/* Init routine may fail, Just ignore errors */ |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"from region handler - deactivate, [%s]", |
acpi_ut_get_region_name |
(region_obj->region. |
space_id))); |
} |
region_obj->region.flags &= |
~(AOPOBJ_SETUP_COMPLETE); |
} |
/* |
* Remove handler reference in the region |
* |
* NOTE: this doesn't mean that the region goes away, the region |
* is just inaccessible as indicated to the _REG method |
* |
* If the region is on the handler's list, this must be the |
* region's handler |
*/ |
region_obj->region.handler = NULL; |
acpi_ut_remove_reference(handler_obj); |
return_VOID; |
} |
/* Walk the linked list of handlers */ |
last_obj_ptr = &obj_desc->region.next; |
obj_desc = obj_desc->region.next; |
/* Prevent infinite loop if list is corrupted */ |
if (obj_desc == start_desc) { |
ACPI_ERROR((AE_INFO, |
"Circular handler list in region object %p", |
region_obj)); |
return_VOID; |
} |
} |
/* If we get here, the region was not in the handler's region list */ |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Cannot remove region %p from address handler %p\n", |
region_obj, handler_obj)); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_attach_region |
* |
* PARAMETERS: handler_obj - Handler Object |
* region_obj - Region Object |
* acpi_ns_is_locked - Namespace Region Already Locked? |
* |
* RETURN: None |
* |
* DESCRIPTION: Create the association between the handler and the region |
* this is a two way association. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_attach_region(union acpi_operand_object *handler_obj, |
union acpi_operand_object *region_obj, |
u8 acpi_ns_is_locked) |
{ |
ACPI_FUNCTION_TRACE(ev_attach_region); |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Adding Region [%4.4s] %p to address handler %p [%s]\n", |
acpi_ut_get_node_name(region_obj->region.node), |
region_obj, handler_obj, |
acpi_ut_get_region_name(region_obj->region. |
space_id))); |
/* Link this region to the front of the handler's list */ |
region_obj->region.next = handler_obj->address_space.region_list; |
handler_obj->address_space.region_list = region_obj; |
/* Install the region's handler */ |
if (region_obj->region.handler) { |
return_ACPI_STATUS(AE_ALREADY_EXISTS); |
} |
region_obj->region.handler = handler_obj; |
acpi_ut_add_reference(handler_obj); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_execute_reg_method |
* |
* PARAMETERS: region_obj - Region object |
* function - Passed to _REG: On (1) or Off (0) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute _REG method for a region |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) |
{ |
struct acpi_evaluate_info *info; |
union acpi_operand_object *args[3]; |
union acpi_operand_object *region_obj2; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_execute_reg_method); |
region_obj2 = acpi_ns_get_secondary_object(region_obj); |
if (!region_obj2) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
if (region_obj2->extra.method_REG == NULL) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Allocate and initialize the evaluation information block */ |
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
info->prefix_node = region_obj2->extra.method_REG; |
info->relative_pathname = NULL; |
info->parameters = args; |
info->flags = ACPI_IGNORE_RETURN_VALUE; |
/* |
* The _REG method has two arguments: |
* |
* arg0 - Integer: |
* Operation region space ID Same value as region_obj->Region.space_id |
* |
* arg1 - Integer: |
* connection status 1 for connecting the handler, 0 for disconnecting |
* the handler (Passed as a parameter) |
*/ |
args[0] = |
acpi_ut_create_integer_object((u64)region_obj->region.space_id); |
if (!args[0]) { |
status = AE_NO_MEMORY; |
goto cleanup1; |
} |
args[1] = acpi_ut_create_integer_object((u64)function); |
if (!args[1]) { |
status = AE_NO_MEMORY; |
goto cleanup2; |
} |
args[2] = NULL; /* Terminate list */ |
/* Execute the method, no return value */ |
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
(ACPI_TYPE_METHOD, info->prefix_node, NULL)); |
status = acpi_ns_evaluate(info); |
acpi_ut_remove_reference(args[1]); |
cleanup2: |
acpi_ut_remove_reference(args[0]); |
cleanup1: |
ACPI_FREE(info); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_execute_reg_methods |
* |
* PARAMETERS: node - Namespace node for the device |
* space_id - The address space ID |
* |
* RETURN: Status |
* |
* DESCRIPTION: Run all _REG methods for the input Space ID; |
* Note: assumes namespace is locked, or system init time. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, |
acpi_adr_space_type space_id) |
{ |
acpi_status status; |
struct acpi_reg_walk_info info; |
ACPI_FUNCTION_TRACE(ev_execute_reg_methods); |
info.space_id = space_id; |
info.reg_run_count = 0; |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, |
" Running _REG methods for SpaceId %s\n", |
acpi_ut_get_region_name(info.space_id))); |
/* |
* Run all _REG methods for all Operation Regions for this space ID. This |
* is a separate walk in order to handle any interdependencies between |
* regions and _REG methods. (i.e. handlers must be installed for all |
* regions of this Space ID before we can run any _REG methods) |
*/ |
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, |
ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, |
NULL, &info, NULL); |
/* Special case for EC: handle "orphan" _REG methods with no region */ |
if (space_id == ACPI_ADR_SPACE_EC) { |
acpi_ev_orphan_ec_reg_method(node); |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, |
" Executed %u _REG methods for SpaceId %s\n", |
info.reg_run_count, |
acpi_ut_get_region_name(info.space_id))); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_reg_run |
* |
* PARAMETERS: walk_namespace callback |
* |
* DESCRIPTION: Run _REG method for region objects of the requested spaceID |
* |
******************************************************************************/ |
static acpi_status |
acpi_ev_reg_run(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
acpi_status status; |
struct acpi_reg_walk_info *info; |
info = ACPI_CAST_PTR(struct acpi_reg_walk_info, context); |
/* Convert and validate the device handle */ |
node = acpi_ns_validate_handle(obj_handle); |
if (!node) { |
return (AE_BAD_PARAMETER); |
} |
/* |
* We only care about regions.and objects that are allowed to have address |
* space handlers |
*/ |
if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { |
return (AE_OK); |
} |
/* Check for an existing internal object */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
/* No object, just exit */ |
return (AE_OK); |
} |
/* Object is a Region */ |
if (obj_desc->region.space_id != info->space_id) { |
/* This region is for a different address space, just ignore it */ |
return (AE_OK); |
} |
info->reg_run_count++; |
status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_orphan_ec_reg_method |
* |
* PARAMETERS: ec_device_node - Namespace node for an EC device |
* |
* RETURN: None |
* |
* DESCRIPTION: Execute an "orphan" _REG method that appears under the EC |
* device. This is a _REG method that has no corresponding region |
* within the EC device scope. The orphan _REG method appears to |
* have been enabled by the description of the ECDT in the ACPI |
* specification: "The availability of the region space can be |
* detected by providing a _REG method object underneath the |
* Embedded Controller device." |
* |
* To quickly access the EC device, we use the ec_device_node used |
* during EC handler installation. Otherwise, we would need to |
* perform a time consuming namespace walk, executing _HID |
* methods to find the EC device. |
* |
* MUTEX: Assumes the namespace is locked |
* |
******************************************************************************/ |
static void |
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node) |
{ |
acpi_handle reg_method; |
struct acpi_namespace_node *next_node; |
acpi_status status; |
struct acpi_object_list args; |
union acpi_object objects[2]; |
ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method); |
if (!ec_device_node) { |
return_VOID; |
} |
/* Namespace is currently locked, must release */ |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
/* Get a handle to a _REG method immediately under the EC device */ |
status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, ®_method); |
if (ACPI_FAILURE(status)) { |
goto exit; /* There is no _REG method present */ |
} |
/* |
* Execute the _REG method only if there is no Operation Region in |
* this scope with the Embedded Controller space ID. Otherwise, it |
* will already have been executed. Note, this allows for Regions |
* with other space IDs to be present; but the code below will then |
* execute the _REG method with the embedded_control space_ID argument. |
*/ |
next_node = acpi_ns_get_next_node(ec_device_node, NULL); |
while (next_node) { |
if ((next_node->type == ACPI_TYPE_REGION) && |
(next_node->object) && |
(next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) { |
goto exit; /* Do not execute the _REG */ |
} |
next_node = acpi_ns_get_next_node(ec_device_node, next_node); |
} |
/* Evaluate the _REG(embedded_control,Connect) method */ |
args.count = 2; |
args.pointer = objects; |
objects[0].type = ACPI_TYPE_INTEGER; |
objects[0].integer.value = ACPI_ADR_SPACE_EC; |
objects[1].type = ACPI_TYPE_INTEGER; |
objects[1].integer.value = ACPI_REG_CONNECT; |
status = acpi_evaluate_object(reg_method, NULL, &args, NULL); |
exit: |
/* We ignore all errors from above, don't care */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
return_VOID; |
} |
/drivers/acpi/acpica/evrgnini.c |
---|
0,0 → 1,675 |
/****************************************************************************** |
* |
* Module Name: evrgnini- ACPI address_space (op_region) init |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evrgnini") |
/* Local prototypes */ |
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_system_memory_region_setup |
* |
* PARAMETERS: handle - Region we are interested in |
* function - Start or stop |
* handler_context - Address space handler context |
* region_context - Region specific context |
* |
* RETURN: Status |
* |
* DESCRIPTION: Setup a system_memory operation region |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_system_memory_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context) |
{ |
union acpi_operand_object *region_desc = |
(union acpi_operand_object *)handle; |
struct acpi_mem_space_context *local_region_context; |
ACPI_FUNCTION_TRACE(ev_system_memory_region_setup); |
if (function == ACPI_REGION_DEACTIVATE) { |
if (*region_context) { |
local_region_context = |
(struct acpi_mem_space_context *)*region_context; |
/* Delete a cached mapping if present */ |
if (local_region_context->mapped_length) { |
acpi_os_unmap_memory(local_region_context-> |
mapped_logical_address, |
local_region_context-> |
mapped_length); |
} |
ACPI_FREE(local_region_context); |
*region_context = NULL; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* Create a new context */ |
local_region_context = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context)); |
if (!(local_region_context)) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Save the region length and address for use in the handler */ |
local_region_context->length = region_desc->region.length; |
local_region_context->address = region_desc->region.address; |
*region_context = local_region_context; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_io_space_region_setup |
* |
* PARAMETERS: handle - Region we are interested in |
* function - Start or stop |
* handler_context - Address space handler context |
* region_context - Region specific context |
* |
* RETURN: Status |
* |
* DESCRIPTION: Setup a IO operation region |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_io_space_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context) |
{ |
ACPI_FUNCTION_TRACE(ev_io_space_region_setup); |
if (function == ACPI_REGION_DEACTIVATE) { |
*region_context = NULL; |
} else { |
*region_context = handler_context; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_pci_config_region_setup |
* |
* PARAMETERS: handle - Region we are interested in |
* function - Start or stop |
* handler_context - Address space handler context |
* region_context - Region specific context |
* |
* RETURN: Status |
* |
* DESCRIPTION: Setup a PCI_Config operation region |
* |
* MUTEX: Assumes namespace is not locked |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_pci_config_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context) |
{ |
acpi_status status = AE_OK; |
u64 pci_value; |
struct acpi_pci_id *pci_id = *region_context; |
union acpi_operand_object *handler_obj; |
struct acpi_namespace_node *parent_node; |
struct acpi_namespace_node *pci_root_node; |
struct acpi_namespace_node *pci_device_node; |
union acpi_operand_object *region_obj = |
(union acpi_operand_object *)handle; |
ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); |
handler_obj = region_obj->region.handler; |
if (!handler_obj) { |
/* |
* No installed handler. This shouldn't happen because the dispatch |
* routine checks before we get here, but we check again just in case. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Attempting to init a region %p, with no handler\n", |
region_obj)); |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
*region_context = NULL; |
if (function == ACPI_REGION_DEACTIVATE) { |
if (pci_id) { |
ACPI_FREE(pci_id); |
} |
return_ACPI_STATUS(status); |
} |
parent_node = region_obj->region.node->parent; |
/* |
* Get the _SEG and _BBN values from the device upon which the handler |
* is installed. |
* |
* We need to get the _SEG and _BBN objects relative to the PCI BUS device. |
* This is the device the handler has been registered to handle. |
*/ |
/* |
* If the address_space.Node is still pointing to the root, we need |
* to scan upward for a PCI Root bridge and re-associate the op_region |
* handlers with that device. |
*/ |
if (handler_obj->address_space.node == acpi_gbl_root_node) { |
/* Start search from the parent object */ |
pci_root_node = parent_node; |
while (pci_root_node != acpi_gbl_root_node) { |
/* Get the _HID/_CID in order to detect a root_bridge */ |
if (acpi_ev_is_pci_root_bridge(pci_root_node)) { |
/* Install a handler for this PCI root bridge */ |
status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); |
if (ACPI_FAILURE(status)) { |
if (status == AE_SAME_HANDLER) { |
/* |
* It is OK if the handler is already installed on the |
* root bridge. Still need to return a context object |
* for the new PCI_Config operation region, however. |
*/ |
status = AE_OK; |
} else { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not install PciConfig handler " |
"for Root Bridge %4.4s", |
acpi_ut_get_node_name |
(pci_root_node))); |
} |
} |
break; |
} |
pci_root_node = pci_root_node->parent; |
} |
/* PCI root bridge not found, use namespace root node */ |
} else { |
pci_root_node = handler_obj->address_space.node; |
} |
/* |
* If this region is now initialized, we are done. |
* (install_address_space_handler could have initialized it) |
*/ |
if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Region is still not initialized. Create a new context */ |
pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); |
if (!pci_id) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* |
* For PCI_Config space access, we need the segment, bus, device and |
* function numbers. Acquire them here. |
* |
* Find the parent device object. (This allows the operation region to be |
* within a subscope under the device, such as a control method.) |
*/ |
pci_device_node = region_obj->region.node; |
while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) { |
pci_device_node = pci_device_node->parent; |
} |
if (!pci_device_node) { |
ACPI_FREE(pci_id); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* |
* Get the PCI device and function numbers from the _ADR object |
* contained in the parent's scope. |
*/ |
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, |
pci_device_node, &pci_value); |
/* |
* The default is zero, and since the allocation above zeroed the data, |
* just do nothing on failure. |
*/ |
if (ACPI_SUCCESS(status)) { |
pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); |
pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value)); |
} |
/* The PCI segment number comes from the _SEG method */ |
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG, |
pci_root_node, &pci_value); |
if (ACPI_SUCCESS(status)) { |
pci_id->segment = ACPI_LOWORD(pci_value); |
} |
/* The PCI bus number comes from the _BBN method */ |
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN, |
pci_root_node, &pci_value); |
if (ACPI_SUCCESS(status)) { |
pci_id->bus = ACPI_LOWORD(pci_value); |
} |
/* Complete/update the PCI ID for this device */ |
status = |
acpi_hw_derive_pci_id(pci_id, pci_root_node, |
region_obj->region.node); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(pci_id); |
return_ACPI_STATUS(status); |
} |
*region_context = pci_id; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_is_pci_root_bridge |
* |
* PARAMETERS: node - Device node being examined |
* |
* RETURN: TRUE if device is a PCI/PCI-Express Root Bridge |
* |
* DESCRIPTION: Determine if the input device represents a PCI Root Bridge by |
* examining the _HID and _CID for the device. |
* |
******************************************************************************/ |
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) |
{ |
acpi_status status; |
struct acpi_pnp_device_id *hid; |
struct acpi_pnp_device_id_list *cid; |
u32 i; |
u8 match; |
/* Get the _HID and check for a PCI Root Bridge */ |
status = acpi_ut_execute_HID(node, &hid); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
match = acpi_ut_is_pci_root_bridge(hid->string); |
ACPI_FREE(hid); |
if (match) { |
return (TRUE); |
} |
/* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ |
status = acpi_ut_execute_CID(node, &cid); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
/* Check all _CIDs in the returned list */ |
for (i = 0; i < cid->count; i++) { |
if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) { |
ACPI_FREE(cid); |
return (TRUE); |
} |
} |
ACPI_FREE(cid); |
return (FALSE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_pci_bar_region_setup |
* |
* PARAMETERS: handle - Region we are interested in |
* function - Start or stop |
* handler_context - Address space handler context |
* region_context - Region specific context |
* |
* RETURN: Status |
* |
* DESCRIPTION: Setup a pci_BAR operation region |
* |
* MUTEX: Assumes namespace is not locked |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_pci_bar_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context) |
{ |
ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_cmos_region_setup |
* |
* PARAMETERS: handle - Region we are interested in |
* function - Start or stop |
* handler_context - Address space handler context |
* region_context - Region specific context |
* |
* RETURN: Status |
* |
* DESCRIPTION: Setup a CMOS operation region |
* |
* MUTEX: Assumes namespace is not locked |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_cmos_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context) |
{ |
ACPI_FUNCTION_TRACE(ev_cmos_region_setup); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_default_region_setup |
* |
* PARAMETERS: handle - Region we are interested in |
* function - Start or stop |
* handler_context - Address space handler context |
* region_context - Region specific context |
* |
* RETURN: Status |
* |
* DESCRIPTION: Default region initialization |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_default_region_setup(acpi_handle handle, |
u32 function, |
void *handler_context, void **region_context) |
{ |
ACPI_FUNCTION_TRACE(ev_default_region_setup); |
if (function == ACPI_REGION_DEACTIVATE) { |
*region_context = NULL; |
} else { |
*region_context = handler_context; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_initialize_region |
* |
* PARAMETERS: region_obj - Region we are initializing |
* acpi_ns_locked - Is namespace locked? |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initializes the region, finds any _REG methods and saves them |
* for execution at a later time |
* |
* Get the appropriate address space handler for a newly |
* created region. |
* |
* This also performs address space specific initialization. For |
* example, PCI regions must have an _ADR object that contains |
* a PCI address in the scope of the definition. This address is |
* required to perform an access to PCI config space. |
* |
* MUTEX: Interpreter should be unlocked, because we may run the _REG |
* method for this region. |
* |
******************************************************************************/ |
acpi_status |
acpi_ev_initialize_region(union acpi_operand_object *region_obj, |
u8 acpi_ns_locked) |
{ |
union acpi_operand_object *handler_obj; |
union acpi_operand_object *obj_desc; |
acpi_adr_space_type space_id; |
struct acpi_namespace_node *node; |
acpi_status status; |
struct acpi_namespace_node *method_node; |
acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; |
union acpi_operand_object *region_obj2; |
ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); |
if (!region_obj) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { |
return_ACPI_STATUS(AE_OK); |
} |
region_obj2 = acpi_ns_get_secondary_object(region_obj); |
if (!region_obj2) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
node = region_obj->region.node->parent; |
space_id = region_obj->region.space_id; |
/* Setup defaults */ |
region_obj->region.handler = NULL; |
region_obj2->extra.method_REG = NULL; |
region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); |
region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; |
/* Find any "_REG" method associated with this region definition */ |
status = |
acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, |
&method_node); |
if (ACPI_SUCCESS(status)) { |
/* |
* The _REG method is optional and there can be only one per region |
* definition. This will be executed when the handler is attached |
* or removed |
*/ |
region_obj2->extra.method_REG = method_node; |
} |
/* |
* The following loop depends upon the root Node having no parent |
* ie: acpi_gbl_root_node->parent_entry being set to NULL |
*/ |
while (node) { |
/* Check to see if a handler exists */ |
handler_obj = NULL; |
obj_desc = acpi_ns_get_attached_object(node); |
if (obj_desc) { |
/* Can only be a handler if the object exists */ |
switch (node->type) { |
case ACPI_TYPE_DEVICE: |
handler_obj = obj_desc->device.handler; |
break; |
case ACPI_TYPE_PROCESSOR: |
handler_obj = obj_desc->processor.handler; |
break; |
case ACPI_TYPE_THERMAL: |
handler_obj = obj_desc->thermal_zone.handler; |
break; |
case ACPI_TYPE_METHOD: |
/* |
* If we are executing module level code, the original |
* Node's object was replaced by this Method object and we |
* saved the handler in the method object. |
* |
* See acpi_ns_exec_module_code |
*/ |
if (obj_desc->method. |
info_flags & ACPI_METHOD_MODULE_LEVEL) { |
handler_obj = |
obj_desc->method.dispatch.handler; |
} |
break; |
default: |
/* Ignore other objects */ |
break; |
} |
while (handler_obj) { |
/* Is this handler of the correct type? */ |
if (handler_obj->address_space.space_id == |
space_id) { |
/* Found correct handler */ |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Found handler %p for region %p in obj %p\n", |
handler_obj, |
region_obj, |
obj_desc)); |
status = |
acpi_ev_attach_region(handler_obj, |
region_obj, |
acpi_ns_locked); |
/* |
* Tell all users that this region is usable by |
* running the _REG method |
*/ |
if (acpi_ns_locked) { |
status = |
acpi_ut_release_mutex |
(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS |
(status); |
} |
} |
status = |
acpi_ev_execute_reg_method |
(region_obj, ACPI_REG_CONNECT); |
if (acpi_ns_locked) { |
status = |
acpi_ut_acquire_mutex |
(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS |
(status); |
} |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* Try next handler in the list */ |
handler_obj = handler_obj->address_space.next; |
} |
} |
/* This node does not have the handler we need; Pop up one level */ |
node = node->parent; |
} |
/* If we get here, there is no handler for this region */ |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"No handler for RegionType %s(%X) (RegionObj %p)\n", |
acpi_ut_get_region_name(space_id), space_id, |
region_obj)); |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/drivers/acpi/acpica/evsci.c |
---|
0,0 → 1,250 |
/******************************************************************************* |
* |
* Module Name: evsci - System Control Interrupt configuration and |
* legacy to ACPI mode state transition functions |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evsci") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/* Local prototypes */ |
static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_sci_dispatch |
* |
* PARAMETERS: None |
* |
* RETURN: Status code indicates whether interrupt was handled. |
* |
* DESCRIPTION: Dispatch the SCI to all host-installed SCI handlers. |
* |
******************************************************************************/ |
u32 acpi_ev_sci_dispatch(void) |
{ |
struct acpi_sci_handler_info *sci_handler; |
acpi_cpu_flags flags; |
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; |
ACPI_FUNCTION_NAME(ev_sci_dispatch); |
/* Are there any host-installed SCI handlers? */ |
if (!acpi_gbl_sci_handler_list) { |
return (int_status); |
} |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Invoke all host-installed SCI handlers */ |
sci_handler = acpi_gbl_sci_handler_list; |
while (sci_handler) { |
/* Invoke the installed handler (at interrupt level) */ |
int_status |= sci_handler->address(sci_handler->context); |
sci_handler = sci_handler->next; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return (int_status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_sci_xrupt_handler |
* |
* PARAMETERS: context - Calling Context |
* |
* RETURN: Status code indicates whether interrupt was handled. |
* |
* DESCRIPTION: Interrupt handler that will figure out what function or |
* control method to call to deal with a SCI. |
* |
******************************************************************************/ |
static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context) |
{ |
struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; |
u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; |
ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler); |
/* |
* We are guaranteed by the ACPICA initialization/shutdown code that |
* if this interrupt handler is installed, ACPI is enabled. |
*/ |
/* |
* Fixed Events: |
* Check for and dispatch any Fixed Events that have occurred |
*/ |
interrupt_handled |= acpi_ev_fixed_event_detect(); |
/* |
* General Purpose Events: |
* Check for and dispatch any GPEs that have occurred |
*/ |
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list); |
/* Invoke all host-installed SCI handlers */ |
interrupt_handled |= acpi_ev_sci_dispatch(); |
acpi_sci_count++; |
return_UINT32(interrupt_handled); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_gpe_xrupt_handler |
* |
* PARAMETERS: context - Calling Context |
* |
* RETURN: Status code indicates whether interrupt was handled. |
* |
* DESCRIPTION: Handler for GPE Block Device interrupts |
* |
******************************************************************************/ |
u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context) |
{ |
struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; |
u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; |
ACPI_FUNCTION_TRACE(ev_gpe_xrupt_handler); |
/* |
* We are guaranteed by the ACPICA initialization/shutdown code that |
* if this interrupt handler is installed, ACPI is enabled. |
*/ |
/* GPEs: Check for and dispatch any GPEs that have occurred */ |
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list); |
return_UINT32(interrupt_handled); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ev_install_sci_handler |
* |
* PARAMETERS: none |
* |
* RETURN: Status |
* |
* DESCRIPTION: Installs SCI handler. |
* |
******************************************************************************/ |
u32 acpi_ev_install_sci_handler(void) |
{ |
u32 status = AE_OK; |
ACPI_FUNCTION_TRACE(ev_install_sci_handler); |
status = |
acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, |
acpi_ev_sci_xrupt_handler, |
acpi_gbl_gpe_xrupt_list_head); |
return_ACPI_STATUS(status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ev_remove_all_sci_handlers |
* |
* PARAMETERS: none |
* |
* RETURN: AE_OK if handler uninstalled, AE_ERROR if handler was not |
* installed to begin with |
* |
* DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be |
* taken. Remove all host-installed SCI handlers. |
* |
* Note: It doesn't seem important to disable all events or set the event |
* enable registers to their original values. The OS should disable |
* the SCI interrupt level when the handler is removed, so no more |
* events will come in. |
* |
******************************************************************************/ |
acpi_status acpi_ev_remove_all_sci_handlers(void) |
{ |
struct acpi_sci_handler_info *sci_handler; |
acpi_cpu_flags flags; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ev_remove_all_sci_handlers); |
/* Just let the OS remove the handler and disable the level */ |
status = |
acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, |
acpi_ev_sci_xrupt_handler); |
if (!acpi_gbl_sci_handler_list) { |
return (status); |
} |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Free all host-installed SCI handlers */ |
while (acpi_gbl_sci_handler_list) { |
sci_handler = acpi_gbl_sci_handler_list; |
acpi_gbl_sci_handler_list = sci_handler->next; |
ACPI_FREE(sci_handler); |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evxface.c |
---|
0,0 → 1,1105 |
/****************************************************************************** |
* |
* Module Name: evxface - External interfaces for ACPI events |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acevents.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evxface") |
#if (!ACPI_REDUCED_HARDWARE) |
/* Local prototypes */ |
static acpi_status |
acpi_ev_install_gpe_handler(acpi_handle gpe_device, |
u32 gpe_number, |
u32 type, |
u8 is_raw_handler, |
acpi_gpe_handler address, void *context); |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_notify_handler |
* |
* PARAMETERS: device - The device for which notifies will be handled |
* handler_type - The type of handler: |
* ACPI_SYSTEM_NOTIFY: System Handler (00-7F) |
* ACPI_DEVICE_NOTIFY: Device Handler (80-FF) |
* ACPI_ALL_NOTIFY: Both System and Device |
* handler - Address of the handler |
* context - Value passed to the handler on each GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for notifications on an ACPI Device, |
* thermal_zone, or Processor object. |
* |
* NOTES: The Root namespace object may have only one handler for each |
* type of notify (System/Device). Device/Thermal/Processor objects |
* may have one device notify handler, and multiple system notify |
* handlers. |
* |
******************************************************************************/ |
acpi_status |
acpi_install_notify_handler(acpi_handle device, |
u32 handler_type, |
acpi_notify_handler handler, void *context) |
{ |
struct acpi_namespace_node *node = |
ACPI_CAST_PTR(struct acpi_namespace_node, device); |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_obj; |
acpi_status status; |
u32 i; |
ACPI_FUNCTION_TRACE(acpi_install_notify_handler); |
/* Parameter validation */ |
if ((!device) || (!handler) || (!handler_type) || |
(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Root Object: |
* Registering a notify handler on the root object indicates that the |
* caller wishes to receive notifications for all objects. Note that |
* only one global handler can be registered per notify type. |
* Ensure that a handler is not already installed. |
*/ |
if (device == ACPI_ROOT_OBJECT) { |
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { |
if (handler_type & (i + 1)) { |
if (acpi_gbl_global_notify[i].handler) { |
status = AE_ALREADY_EXISTS; |
goto unlock_and_exit; |
} |
acpi_gbl_global_notify[i].handler = handler; |
acpi_gbl_global_notify[i].context = context; |
} |
} |
goto unlock_and_exit; /* Global notify handler installed, all done */ |
} |
/* |
* All Other Objects: |
* Caller will only receive notifications specific to the target |
* object. Note that only certain object types are allowed to |
* receive notifications. |
*/ |
/* Are Notifies allowed on this object? */ |
if (!acpi_ev_is_notify_object(node)) { |
status = AE_TYPE; |
goto unlock_and_exit; |
} |
/* Check for an existing internal object, might not exist */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
/* Create a new object */ |
obj_desc = acpi_ut_create_internal_object(node->type); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto unlock_and_exit; |
} |
/* Attach new object to the Node, remove local reference */ |
status = acpi_ns_attach_object(device, obj_desc, node->type); |
acpi_ut_remove_reference(obj_desc); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
} |
/* Ensure that the handler is not already installed in the lists */ |
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { |
if (handler_type & (i + 1)) { |
handler_obj = obj_desc->common_notify.notify_list[i]; |
while (handler_obj) { |
if (handler_obj->notify.handler == handler) { |
status = AE_ALREADY_EXISTS; |
goto unlock_and_exit; |
} |
handler_obj = handler_obj->notify.next[i]; |
} |
} |
} |
/* Create and populate a new notify handler object */ |
handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY); |
if (!handler_obj) { |
status = AE_NO_MEMORY; |
goto unlock_and_exit; |
} |
handler_obj->notify.node = node; |
handler_obj->notify.handler_type = handler_type; |
handler_obj->notify.handler = handler; |
handler_obj->notify.context = context; |
/* Install the handler at the list head(s) */ |
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { |
if (handler_type & (i + 1)) { |
handler_obj->notify.next[i] = |
obj_desc->common_notify.notify_list[i]; |
obj_desc->common_notify.notify_list[i] = handler_obj; |
} |
} |
/* Add an extra reference if handler was installed in both lists */ |
if (handler_type == ACPI_ALL_NOTIFY) { |
acpi_ut_add_reference(handler_obj); |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_notify_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_remove_notify_handler |
* |
* PARAMETERS: device - The device for which the handler is installed |
* handler_type - The type of handler: |
* ACPI_SYSTEM_NOTIFY: System Handler (00-7F) |
* ACPI_DEVICE_NOTIFY: Device Handler (80-FF) |
* ACPI_ALL_NOTIFY: Both System and Device |
* handler - Address of the handler |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a handler for notifies on an ACPI device |
* |
******************************************************************************/ |
acpi_status |
acpi_remove_notify_handler(acpi_handle device, |
u32 handler_type, acpi_notify_handler handler) |
{ |
struct acpi_namespace_node *node = |
ACPI_CAST_PTR(struct acpi_namespace_node, device); |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_obj; |
union acpi_operand_object *previous_handler_obj; |
acpi_status status = AE_OK; |
u32 i; |
ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); |
/* Parameter validation */ |
if ((!device) || (!handler) || (!handler_type) || |
(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Root Object. Global handlers are removed here */ |
if (device == ACPI_ROOT_OBJECT) { |
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { |
if (handler_type & (i + 1)) { |
status = |
acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (!acpi_gbl_global_notify[i].handler || |
(acpi_gbl_global_notify[i].handler != |
handler)) { |
status = AE_NOT_EXIST; |
goto unlock_and_exit; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Removing global notify handler\n")); |
acpi_gbl_global_notify[i].handler = NULL; |
acpi_gbl_global_notify[i].context = NULL; |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
/* Make sure all deferred notify tasks are completed */ |
acpi_os_wait_events_complete(); |
} |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* All other objects: Are Notifies allowed on this object? */ |
if (!acpi_ev_is_notify_object(node)) { |
return_ACPI_STATUS(AE_TYPE); |
} |
/* Must have an existing internal object */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Internal object exists. Find the handler and remove it */ |
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { |
if (handler_type & (i + 1)) { |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
handler_obj = obj_desc->common_notify.notify_list[i]; |
previous_handler_obj = NULL; |
/* Attempt to find the handler in the handler list */ |
while (handler_obj && |
(handler_obj->notify.handler != handler)) { |
previous_handler_obj = handler_obj; |
handler_obj = handler_obj->notify.next[i]; |
} |
if (!handler_obj) { |
status = AE_NOT_EXIST; |
goto unlock_and_exit; |
} |
/* Remove the handler object from the list */ |
if (previous_handler_obj) { /* Handler is not at the list head */ |
previous_handler_obj->notify.next[i] = |
handler_obj->notify.next[i]; |
} else { /* Handler is at the list head */ |
obj_desc->common_notify.notify_list[i] = |
handler_obj->notify.next[i]; |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
/* Make sure all deferred notify tasks are completed */ |
acpi_os_wait_events_complete(); |
acpi_ut_remove_reference(handler_obj); |
} |
} |
return_ACPI_STATUS(status); |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_exception_handler |
* |
* PARAMETERS: handler - Pointer to the handler function for the |
* event |
* |
* RETURN: Status |
* |
* DESCRIPTION: Saves the pointer to the handler function |
* |
******************************************************************************/ |
#ifdef ACPI_FUTURE_USAGE |
acpi_status acpi_install_exception_handler(acpi_exception_handler handler) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_exception_handler); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Don't allow two handlers. */ |
if (acpi_gbl_exception_handler) { |
status = AE_ALREADY_EXISTS; |
goto cleanup; |
} |
/* Install the handler */ |
acpi_gbl_exception_handler = handler; |
cleanup: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_exception_handler) |
#endif |
#if (!ACPI_REDUCED_HARDWARE) |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_sci_handler |
* |
* PARAMETERS: address - Address of the handler |
* context - Value passed to the handler on each SCI |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for a System Control Interrupt. |
* |
******************************************************************************/ |
acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context) |
{ |
struct acpi_sci_handler_info *new_sci_handler; |
struct acpi_sci_handler_info *sci_handler; |
acpi_cpu_flags flags; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_sci_handler); |
if (!address) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Allocate and init a handler object */ |
new_sci_handler = ACPI_ALLOCATE(sizeof(struct acpi_sci_handler_info)); |
if (!new_sci_handler) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
new_sci_handler->address = address; |
new_sci_handler->context = context; |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Lock list during installation */ |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
sci_handler = acpi_gbl_sci_handler_list; |
/* Ensure handler does not already exist */ |
while (sci_handler) { |
if (address == sci_handler->address) { |
status = AE_ALREADY_EXISTS; |
goto unlock_and_exit; |
} |
sci_handler = sci_handler->next; |
} |
/* Install the new handler into the global list (at head) */ |
new_sci_handler->next = acpi_gbl_sci_handler_list; |
acpi_gbl_sci_handler_list = new_sci_handler; |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
exit: |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(new_sci_handler); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_sci_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_remove_sci_handler |
* |
* PARAMETERS: address - Address of the handler |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a handler for a System Control Interrupt. |
* |
******************************************************************************/ |
acpi_status acpi_remove_sci_handler(acpi_sci_handler address) |
{ |
struct acpi_sci_handler_info *prev_sci_handler; |
struct acpi_sci_handler_info *next_sci_handler; |
acpi_cpu_flags flags; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_remove_sci_handler); |
if (!address) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Remove the SCI handler with lock */ |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
prev_sci_handler = NULL; |
next_sci_handler = acpi_gbl_sci_handler_list; |
while (next_sci_handler) { |
if (next_sci_handler->address == address) { |
/* Unlink and free the SCI handler info block */ |
if (prev_sci_handler) { |
prev_sci_handler->next = next_sci_handler->next; |
} else { |
acpi_gbl_sci_handler_list = |
next_sci_handler->next; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
ACPI_FREE(next_sci_handler); |
goto unlock_and_exit; |
} |
prev_sci_handler = next_sci_handler; |
next_sci_handler = next_sci_handler->next; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
status = AE_NOT_EXIST; |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_global_event_handler |
* |
* PARAMETERS: handler - Pointer to the global event handler function |
* context - Value passed to the handler on each event |
* |
* RETURN: Status |
* |
* DESCRIPTION: Saves the pointer to the handler function. The global handler |
* is invoked upon each incoming GPE and Fixed Event. It is |
* invoked at interrupt level at the time of the event dispatch. |
* Can be used to update event counters, etc. |
* |
******************************************************************************/ |
acpi_status |
acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_global_event_handler); |
/* Parameter validation */ |
if (!handler) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Don't allow two handlers. */ |
if (acpi_gbl_global_event_handler) { |
status = AE_ALREADY_EXISTS; |
goto cleanup; |
} |
acpi_gbl_global_event_handler = handler; |
acpi_gbl_global_event_handler_context = context; |
cleanup: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_fixed_event_handler |
* |
* PARAMETERS: event - Event type to enable. |
* handler - Pointer to the handler function for the |
* event |
* context - Value passed to the handler on each GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Saves the pointer to the handler function and then enables the |
* event. |
* |
******************************************************************************/ |
acpi_status |
acpi_install_fixed_event_handler(u32 event, |
acpi_event_handler handler, void *context) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler); |
/* Parameter validation */ |
if (event > ACPI_EVENT_MAX) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Do not allow multiple handlers */ |
if (acpi_gbl_fixed_event_handlers[event].handler) { |
status = AE_ALREADY_EXISTS; |
goto cleanup; |
} |
/* Install the handler before enabling the event */ |
acpi_gbl_fixed_event_handlers[event].handler = handler; |
acpi_gbl_fixed_event_handlers[event].context = context; |
status = acpi_clear_event(event); |
if (ACPI_SUCCESS(status)) |
status = acpi_enable_event(event, 0); |
if (ACPI_FAILURE(status)) { |
ACPI_WARNING((AE_INFO, |
"Could not enable fixed event - %s (%u)", |
acpi_ut_get_event_name(event), event)); |
/* Remove the handler */ |
acpi_gbl_fixed_event_handlers[event].handler = NULL; |
acpi_gbl_fixed_event_handlers[event].context = NULL; |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Enabled fixed event %s (%X), Handler=%p\n", |
acpi_ut_get_event_name(event), event, |
handler)); |
} |
cleanup: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_remove_fixed_event_handler |
* |
* PARAMETERS: event - Event type to disable. |
* handler - Address of the handler |
* |
* RETURN: Status |
* |
* DESCRIPTION: Disables the event and unregisters the event handler. |
* |
******************************************************************************/ |
acpi_status |
acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler); |
/* Parameter validation */ |
if (event > ACPI_EVENT_MAX) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Disable the event before removing the handler */ |
status = acpi_disable_event(event, 0); |
/* Always Remove the handler */ |
acpi_gbl_fixed_event_handlers[event].handler = NULL; |
acpi_gbl_fixed_event_handlers[event].context = NULL; |
if (ACPI_FAILURE(status)) { |
ACPI_WARNING((AE_INFO, |
"Could not disable fixed event - %s (%u)", |
acpi_ut_get_event_name(event), event)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Disabled fixed event - %s (%X)\n", |
acpi_ut_get_event_name(event), event)); |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ev_install_gpe_handler |
* |
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT |
* defined GPEs) |
* gpe_number - The GPE number within the GPE block |
* type - Whether this GPE should be treated as an |
* edge- or level-triggered interrupt. |
* is_raw_handler - Whether this GPE should be handled using |
* the special GPE handler mode. |
* address - Address of the handler |
* context - Value passed to the handler on each GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Internal function to install a handler for a General Purpose |
* Event. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ev_install_gpe_handler(acpi_handle gpe_device, |
u32 gpe_number, |
u32 type, |
u8 is_raw_handler, |
acpi_gpe_handler address, void *context) |
{ |
struct acpi_gpe_event_info *gpe_event_info; |
struct acpi_gpe_handler_info *handler; |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(ev_install_gpe_handler); |
/* Parameter validation */ |
if ((!address) || (type & ~ACPI_GPE_XRUPT_TYPE_MASK)) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Allocate and init handler object (before lock) */ |
handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info)); |
if (!handler) { |
status = AE_NO_MEMORY; |
goto unlock_and_exit; |
} |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto free_and_exit; |
} |
/* Make sure that there isn't a handler there already */ |
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_HANDLER) || |
(ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_RAW_HANDLER)) { |
status = AE_ALREADY_EXISTS; |
goto free_and_exit; |
} |
handler->address = address; |
handler->context = context; |
handler->method_node = gpe_event_info->dispatch.method_node; |
handler->original_flags = (u8)(gpe_event_info->flags & |
(ACPI_GPE_XRUPT_TYPE_MASK | |
ACPI_GPE_DISPATCH_MASK)); |
/* |
* If the GPE is associated with a method, it may have been enabled |
* automatically during initialization, in which case it has to be |
* disabled now to avoid spurious execution of the handler. |
*/ |
if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == |
ACPI_GPE_DISPATCH_METHOD) || |
(ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == |
ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) { |
handler->originally_enabled = TRUE; |
(void)acpi_ev_remove_gpe_reference(gpe_event_info); |
/* Sanity check of original type against new type */ |
if (type != |
(u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) { |
ACPI_WARNING((AE_INFO, |
"GPE type mismatch (level/edge)")); |
} |
} |
/* Install the handler */ |
gpe_event_info->dispatch.handler = handler; |
/* Setup up dispatch flags to indicate handler (vs. method/notify) */ |
gpe_event_info->flags &= |
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); |
gpe_event_info->flags |= |
(u8)(type | |
(is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER : |
ACPI_GPE_DISPATCH_HANDLER)); |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
free_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
ACPI_FREE(handler); |
goto unlock_and_exit; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_gpe_handler |
* |
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT |
* defined GPEs) |
* gpe_number - The GPE number within the GPE block |
* type - Whether this GPE should be treated as an |
* edge- or level-triggered interrupt. |
* address - Address of the handler |
* context - Value passed to the handler on each GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for a General Purpose Event. |
* |
******************************************************************************/ |
acpi_status |
acpi_install_gpe_handler(acpi_handle gpe_device, |
u32 gpe_number, |
u32 type, acpi_gpe_handler address, void *context) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); |
status = |
acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, FALSE, |
address, context); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_gpe_raw_handler |
* |
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT |
* defined GPEs) |
* gpe_number - The GPE number within the GPE block |
* type - Whether this GPE should be treated as an |
* edge- or level-triggered interrupt. |
* address - Address of the handler |
* context - Value passed to the handler on each GPE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for a General Purpose Event. |
* |
******************************************************************************/ |
acpi_status |
acpi_install_gpe_raw_handler(acpi_handle gpe_device, |
u32 gpe_number, |
u32 type, acpi_gpe_handler address, void *context) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler); |
status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, TRUE, |
address, context); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_remove_gpe_handler |
* |
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT |
* defined GPEs) |
* gpe_number - The event to remove a handler |
* address - Address of the handler |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a handler for a General Purpose acpi_event. |
* |
******************************************************************************/ |
acpi_status |
acpi_remove_gpe_handler(acpi_handle gpe_device, |
u32 gpe_number, acpi_gpe_handler address) |
{ |
struct acpi_gpe_event_info *gpe_event_info; |
struct acpi_gpe_handler_info *handler; |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler); |
/* Parameter validation */ |
if (!address) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Make sure that a handler is indeed installed */ |
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != |
ACPI_GPE_DISPATCH_HANDLER) && |
(ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != |
ACPI_GPE_DISPATCH_RAW_HANDLER)) { |
status = AE_NOT_EXIST; |
goto unlock_and_exit; |
} |
/* Make sure that the installed handler is the same */ |
if (gpe_event_info->dispatch.handler->address != address) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Remove the handler */ |
handler = gpe_event_info->dispatch.handler; |
gpe_event_info->dispatch.handler = NULL; |
/* Restore Method node (if any), set dispatch flags */ |
gpe_event_info->dispatch.method_node = handler->method_node; |
gpe_event_info->flags &= |
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); |
gpe_event_info->flags |= handler->original_flags; |
/* |
* If the GPE was previously associated with a method and it was |
* enabled, it should be enabled at this point to restore the |
* post-initialization configuration. |
*/ |
if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == |
ACPI_GPE_DISPATCH_METHOD) || |
(ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == |
ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) { |
(void)acpi_ev_add_gpe_reference(gpe_event_info); |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
/* Make sure all deferred GPE tasks are completed */ |
acpi_os_wait_events_complete(); |
/* Now we can free the handler object */ |
ACPI_FREE(handler); |
return_ACPI_STATUS(status); |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_acquire_global_lock |
* |
* PARAMETERS: timeout - How long the caller is willing to wait |
* handle - Where the handle to the lock is returned |
* (if acquired) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Acquire the ACPI Global Lock |
* |
* Note: Allows callers with the same thread ID to acquire the global lock |
* multiple times. In other words, externally, the behavior of the global lock |
* is identical to an AML mutex. On the first acquire, a new handle is |
* returned. On any subsequent calls to acquire by the same thread, the same |
* handle is returned. |
* |
******************************************************************************/ |
acpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle) |
{ |
acpi_status status; |
if (!handle) { |
return (AE_BAD_PARAMETER); |
} |
/* Must lock interpreter to prevent race conditions */ |
acpi_ex_enter_interpreter(); |
status = acpi_ex_acquire_mutex_object(timeout, |
acpi_gbl_global_lock_mutex, |
acpi_os_get_thread_id()); |
if (ACPI_SUCCESS(status)) { |
/* Return the global lock handle (updated in acpi_ev_acquire_global_lock) */ |
*handle = acpi_gbl_global_lock_handle; |
} |
acpi_ex_exit_interpreter(); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_acquire_global_lock) |
/******************************************************************************* |
* |
* FUNCTION: acpi_release_global_lock |
* |
* PARAMETERS: handle - Returned from acpi_acquire_global_lock |
* |
* RETURN: Status |
* |
* DESCRIPTION: Release the ACPI Global Lock. The handle must be valid. |
* |
******************************************************************************/ |
acpi_status acpi_release_global_lock(u32 handle) |
{ |
acpi_status status; |
if (!handle || (handle != acpi_gbl_global_lock_handle)) { |
return (AE_NOT_ACQUIRED); |
} |
status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_release_global_lock) |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evxfevnt.c |
---|
0,0 → 1,381 |
/****************************************************************************** |
* |
* Module Name: evxfevnt - External Interfaces, ACPI event disable/enable |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evxfevnt") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_enable |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Transfers the system into ACPI mode. |
* |
******************************************************************************/ |
acpi_status acpi_enable(void) |
{ |
acpi_status status; |
int retry; |
ACPI_FUNCTION_TRACE(acpi_enable); |
/* ACPI tables must be present */ |
if (acpi_gbl_fadt_index == ACPI_INVALID_TABLE_INDEX) { |
return_ACPI_STATUS(AE_NO_ACPI_TABLES); |
} |
/* If the Hardware Reduced flag is set, machine is always in acpi mode */ |
if (acpi_gbl_reduced_hardware) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Check current mode */ |
if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) { |
ACPI_DEBUG_PRINT((ACPI_DB_INIT, |
"System is already in ACPI mode\n")); |
return_ACPI_STATUS(AE_OK); |
} |
/* Transition to ACPI mode */ |
status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not transition to ACPI mode")); |
return_ACPI_STATUS(status); |
} |
/* Sanity check that transition succeeded */ |
for (retry = 0; retry < 30000; ++retry) { |
if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) { |
if (retry != 0) |
ACPI_WARNING((AE_INFO, |
"Platform took > %d00 usec to enter ACPI mode", retry)); |
return_ACPI_STATUS(AE_OK); |
} |
acpi_os_stall(100); /* 100 usec */ |
} |
ACPI_ERROR((AE_INFO, "Hardware did not enter ACPI mode")); |
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); |
} |
ACPI_EXPORT_SYMBOL(acpi_enable) |
/******************************************************************************* |
* |
* FUNCTION: acpi_disable |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode. |
* |
******************************************************************************/ |
acpi_status acpi_disable(void) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(acpi_disable); |
/* If the Hardware Reduced flag is set, machine is always in acpi mode */ |
if (acpi_gbl_reduced_hardware) { |
return_ACPI_STATUS(AE_OK); |
} |
if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) { |
ACPI_DEBUG_PRINT((ACPI_DB_INIT, |
"System is already in legacy (non-ACPI) mode\n")); |
} else { |
/* Transition to LEGACY mode */ |
status = acpi_hw_set_mode(ACPI_SYS_MODE_LEGACY); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not exit ACPI mode to legacy mode")); |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI mode disabled\n")); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_disable) |
/******************************************************************************* |
* |
* FUNCTION: acpi_enable_event |
* |
* PARAMETERS: event - The fixed eventto be enabled |
* flags - Reserved |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable an ACPI event (fixed) |
* |
******************************************************************************/ |
acpi_status acpi_enable_event(u32 event, u32 flags) |
{ |
acpi_status status = AE_OK; |
u32 value; |
ACPI_FUNCTION_TRACE(acpi_enable_event); |
/* Decode the Fixed Event */ |
if (event > ACPI_EVENT_MAX) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* Enable the requested fixed event (by writing a one to the enable |
* register bit) |
*/ |
status = |
acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. |
enable_register_id, ACPI_ENABLE_EVENT); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Make sure that the hardware responded */ |
status = |
acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. |
enable_register_id, &value); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (value != 1) { |
ACPI_ERROR((AE_INFO, |
"Could not enable %s event", |
acpi_ut_get_event_name(event))); |
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_enable_event) |
/******************************************************************************* |
* |
* FUNCTION: acpi_disable_event |
* |
* PARAMETERS: event - The fixed event to be disabled |
* flags - Reserved |
* |
* RETURN: Status |
* |
* DESCRIPTION: Disable an ACPI event (fixed) |
* |
******************************************************************************/ |
acpi_status acpi_disable_event(u32 event, u32 flags) |
{ |
acpi_status status = AE_OK; |
u32 value; |
ACPI_FUNCTION_TRACE(acpi_disable_event); |
/* Decode the Fixed Event */ |
if (event > ACPI_EVENT_MAX) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* Disable the requested fixed event (by writing a zero to the enable |
* register bit) |
*/ |
status = |
acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. |
enable_register_id, ACPI_DISABLE_EVENT); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = |
acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. |
enable_register_id, &value); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (value != 0) { |
ACPI_ERROR((AE_INFO, |
"Could not disable %s events", |
acpi_ut_get_event_name(event))); |
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_disable_event) |
/******************************************************************************* |
* |
* FUNCTION: acpi_clear_event |
* |
* PARAMETERS: event - The fixed event to be cleared |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clear an ACPI event (fixed) |
* |
******************************************************************************/ |
acpi_status acpi_clear_event(u32 event) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(acpi_clear_event); |
/* Decode the Fixed Event */ |
if (event > ACPI_EVENT_MAX) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* Clear the requested fixed event (By writing a one to the status |
* register bit) |
*/ |
status = |
acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. |
status_register_id, ACPI_CLEAR_STATUS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_clear_event) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_event_status |
* |
* PARAMETERS: event - The fixed event |
* event_status - Where the current status of the event will |
* be returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Obtains and returns the current status of the event |
* |
******************************************************************************/ |
acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) |
{ |
acpi_status status; |
acpi_event_status local_event_status = 0; |
u32 in_byte; |
ACPI_FUNCTION_TRACE(acpi_get_event_status); |
if (!event_status) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Decode the Fixed Event */ |
if (event > ACPI_EVENT_MAX) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Fixed event currently can be dispatched? */ |
if (acpi_gbl_fixed_event_handlers[event].handler) { |
local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER; |
} |
/* Fixed event currently enabled? */ |
status = |
acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. |
enable_register_id, &in_byte); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (in_byte) { |
local_event_status |= |
(ACPI_EVENT_FLAG_ENABLED | ACPI_EVENT_FLAG_ENABLE_SET); |
} |
/* Fixed event currently active? */ |
status = |
acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. |
status_register_id, &in_byte); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (in_byte) { |
local_event_status |= ACPI_EVENT_FLAG_STATUS_SET; |
} |
(*event_status) = local_event_status; |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_event_status) |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evxfgpe.c |
---|
0,0 → 1,952 |
/****************************************************************************** |
* |
* Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evxfgpe") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_update_all_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Complete GPE initialization and enable all GPEs that have |
* associated _Lxx or _Exx methods and are not pointed to by any |
* device _PRW methods (this indicates that these GPEs are |
* generally intended for system or device wakeup. Such GPEs |
* have to be enabled directly when the devices whose _PRW |
* methods point to them are set up for wakeup signaling.) |
* |
* NOTE: Should be called after any GPEs are added to the system. Primarily, |
* after the system _PRW methods have been run, but also after a GPE Block |
* Device has been added or if any new GPE methods have been added via a |
* dynamic table load. |
* |
******************************************************************************/ |
acpi_status acpi_update_all_gpes(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_update_all_gpes); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (acpi_gbl_all_gpes_initialized) { |
goto unlock_and_exit; |
} |
status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL); |
if (ACPI_SUCCESS(status)) { |
acpi_gbl_all_gpes_initialized = TRUE; |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_update_all_gpes) |
/******************************************************************************* |
* |
* FUNCTION: acpi_enable_gpe |
* |
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is |
* hardware-enabled. |
* |
******************************************************************************/ |
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) |
{ |
acpi_status status = AE_BAD_PARAMETER; |
struct acpi_gpe_event_info *gpe_event_info; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_enable_gpe); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* |
* Ensure that we have a valid GPE number and that there is some way |
* of handling the GPE (handler or a GPE method). In other words, we |
* won't allow a valid GPE to be enabled if there is no way to handle it. |
*/ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (gpe_event_info) { |
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != |
ACPI_GPE_DISPATCH_NONE) { |
status = acpi_ev_add_gpe_reference(gpe_event_info); |
} else { |
status = AE_NO_HANDLER; |
} |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_enable_gpe) |
/******************************************************************************* |
* |
* FUNCTION: acpi_disable_gpe |
* |
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a reference to a GPE. When the last reference is |
* removed, only then is the GPE disabled (for runtime GPEs), or |
* the GPE mask bit disabled (for wake GPEs) |
* |
******************************************************************************/ |
acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) |
{ |
acpi_status status = AE_BAD_PARAMETER; |
struct acpi_gpe_event_info *gpe_event_info; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_disable_gpe); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (gpe_event_info) { |
status = acpi_ev_remove_gpe_reference(gpe_event_info) ; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_disable_gpe) |
/******************************************************************************* |
* |
* FUNCTION: acpi_set_gpe |
* |
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable or disable an individual GPE. This function bypasses |
* the reference count mechanism used in the acpi_enable_gpe(), |
* acpi_disable_gpe() interfaces. |
* This API is typically used by the GPE raw handler mode driver |
* to switch between the polling mode and the interrupt mode after |
* the driver has enabled the GPE. |
* The APIs should be invoked in this order: |
* acpi_enable_gpe() <- Ensure the reference count > 0 |
* acpi_set_gpe(ACPI_GPE_DISABLE) <- Enter polling mode |
* acpi_set_gpe(ACPI_GPE_ENABLE) <- Leave polling mode |
* acpi_disable_gpe() <- Decrease the reference count |
* |
* Note: If a GPE is shared by 2 silicon components, then both the drivers |
* should support GPE polling mode or disabling the GPE for long period |
* for one driver may break the other. So use it with care since all |
* firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode. |
* |
******************************************************************************/ |
acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) |
{ |
struct acpi_gpe_event_info *gpe_event_info; |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_set_gpe); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Perform the action */ |
switch (action) { |
case ACPI_GPE_ENABLE: |
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); |
break; |
case ACPI_GPE_DISABLE: |
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); |
break; |
default: |
status = AE_BAD_PARAMETER; |
break; |
} |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_set_gpe) |
/******************************************************************************* |
* |
* FUNCTION: acpi_mark_gpe_for_wake |
* |
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Mark a GPE as having the ability to wake the system. Simply |
* sets the ACPI_GPE_CAN_WAKE flag. |
* |
* Some potential callers of acpi_setup_gpe_for_wake may know in advance that |
* there won't be any notify handlers installed for device wake notifications |
* from the given GPE (one example is a button GPE in Linux). For these cases, |
* acpi_mark_gpe_for_wake should be used instead of acpi_setup_gpe_for_wake. |
* This will set the ACPI_GPE_CAN_WAKE flag for the GPE without trying to |
* setup implicit wake notification for it (since there's no handler method). |
* |
******************************************************************************/ |
acpi_status acpi_mark_gpe_for_wake(acpi_handle gpe_device, u32 gpe_number) |
{ |
struct acpi_gpe_event_info *gpe_event_info; |
acpi_status status = AE_BAD_PARAMETER; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_mark_gpe_for_wake); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (gpe_event_info) { |
/* Mark the GPE as a possible wake event */ |
gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; |
status = AE_OK; |
} |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_mark_gpe_for_wake) |
/******************************************************************************* |
* |
* FUNCTION: acpi_setup_gpe_for_wake |
* |
* PARAMETERS: wake_device - Device associated with the GPE (via _PRW) |
* gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Mark a GPE as having the ability to wake the system. This |
* interface is intended to be used as the host executes the |
* _PRW methods (Power Resources for Wake) in the system tables. |
* Each _PRW appears under a Device Object (The wake_device), and |
* contains the info for the wake GPE associated with the |
* wake_device. |
* |
******************************************************************************/ |
acpi_status |
acpi_setup_gpe_for_wake(acpi_handle wake_device, |
acpi_handle gpe_device, u32 gpe_number) |
{ |
acpi_status status; |
struct acpi_gpe_event_info *gpe_event_info; |
struct acpi_namespace_node *device_node; |
struct acpi_gpe_notify_info *notify; |
struct acpi_gpe_notify_info *new_notify; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); |
/* Parameter Validation */ |
if (!wake_device) { |
/* |
* By forcing wake_device to be valid, we automatically enable the |
* implicit notify feature on all hosts. |
*/ |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Handle root object case */ |
if (wake_device == ACPI_ROOT_OBJECT) { |
device_node = acpi_gbl_root_node; |
} else { |
device_node = |
ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); |
} |
/* Validate wake_device is of type Device */ |
if (device_node->type != ACPI_TYPE_DEVICE) { |
return_ACPI_STATUS (AE_BAD_PARAMETER); |
} |
/* |
* Allocate a new notify object up front, in case it is needed. |
* Memory allocation while holding a spinlock is a big no-no |
* on some hosts. |
*/ |
new_notify = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_notify_info)); |
if (!new_notify) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* |
* If there is no method or handler for this GPE, then the |
* wake_device will be notified whenever this GPE fires. This is |
* known as an "implicit notify". Note: The GPE is assumed to be |
* level-triggered (for windows compatibility). |
*/ |
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_NONE) { |
/* |
* This is the first device for implicit notify on this GPE. |
* Just set the flags here, and enter the NOTIFY block below. |
*/ |
gpe_event_info->flags = |
(ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED); |
} |
/* |
* If we already have an implicit notify on this GPE, add |
* this device to the notify list. |
*/ |
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == |
ACPI_GPE_DISPATCH_NOTIFY) { |
/* Ensure that the device is not already in the list */ |
notify = gpe_event_info->dispatch.notify_list; |
while (notify) { |
if (notify->device_node == device_node) { |
status = AE_ALREADY_EXISTS; |
goto unlock_and_exit; |
} |
notify = notify->next; |
} |
/* Add this device to the notify list for this GPE */ |
new_notify->device_node = device_node; |
new_notify->next = gpe_event_info->dispatch.notify_list; |
gpe_event_info->dispatch.notify_list = new_notify; |
new_notify = NULL; |
} |
/* Mark the GPE as a possible wake event */ |
gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; |
status = AE_OK; |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
/* Delete the notify object if it was not used above */ |
if (new_notify) { |
ACPI_FREE(new_notify); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) |
/******************************************************************************* |
* |
* FUNCTION: acpi_set_gpe_wake_mask |
* |
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* action - Enable or Disable |
* |
* RETURN: Status |
* |
* DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must |
* already be marked as a WAKE GPE. |
* |
******************************************************************************/ |
acpi_status |
acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action) |
{ |
acpi_status status = AE_OK; |
struct acpi_gpe_event_info *gpe_event_info; |
struct acpi_gpe_register_info *gpe_register_info; |
acpi_cpu_flags flags; |
u32 register_bit; |
ACPI_FUNCTION_TRACE(acpi_set_gpe_wake_mask); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* |
* Ensure that we have a valid GPE number and that this GPE is in |
* fact a wake GPE |
*/ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { |
status = AE_TYPE; |
goto unlock_and_exit; |
} |
gpe_register_info = gpe_event_info->register_info; |
if (!gpe_register_info) { |
status = AE_NOT_EXIST; |
goto unlock_and_exit; |
} |
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
/* Perform the action */ |
switch (action) { |
case ACPI_GPE_ENABLE: |
ACPI_SET_BIT(gpe_register_info->enable_for_wake, |
(u8)register_bit); |
break; |
case ACPI_GPE_DISABLE: |
ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, |
(u8)register_bit); |
break; |
default: |
ACPI_ERROR((AE_INFO, "%u, Invalid action", action)); |
status = AE_BAD_PARAMETER; |
break; |
} |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_set_gpe_wake_mask) |
/******************************************************************************* |
* |
* FUNCTION: acpi_clear_gpe |
* |
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clear an ACPI event (general purpose) |
* |
******************************************************************************/ |
acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number) |
{ |
acpi_status status = AE_OK; |
struct acpi_gpe_event_info *gpe_event_info; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_clear_gpe); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
status = acpi_hw_clear_gpe(gpe_event_info); |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_clear_gpe) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_gpe_status |
* |
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
* gpe_number - GPE level within the GPE block |
* event_status - Where the current status of the event |
* will be returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get the current status of a GPE (signalled/not_signalled) |
* |
******************************************************************************/ |
acpi_status |
acpi_get_gpe_status(acpi_handle gpe_device, |
u32 gpe_number, acpi_event_status *event_status) |
{ |
acpi_status status = AE_OK; |
struct acpi_gpe_event_info *gpe_event_info; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_get_gpe_status); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Obtain status on the requested GPE number */ |
status = acpi_hw_get_gpe_status(gpe_event_info, event_status); |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) |
/******************************************************************************* |
* |
* FUNCTION: acpi_finish_gpe |
* |
* PARAMETERS: gpe_device - Namespace node for the GPE Block |
* (NULL for FADT defined GPEs) |
* gpe_number - GPE level within the GPE block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE |
* processing. Intended for use by asynchronous host-installed |
* GPE handlers. The GPE is only reenabled if the enable_for_run bit |
* is set in the GPE info. |
* |
******************************************************************************/ |
acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number) |
{ |
struct acpi_gpe_event_info *gpe_event_info; |
acpi_status status; |
acpi_cpu_flags flags; |
ACPI_FUNCTION_TRACE(acpi_finish_gpe); |
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
/* Ensure that we have a valid GPE number */ |
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
if (!gpe_event_info) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
status = acpi_ev_finish_gpe(gpe_event_info); |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_finish_gpe) |
/****************************************************************************** |
* |
* FUNCTION: acpi_disable_all_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Disable and clear all GPEs in all GPE blocks |
* |
******************************************************************************/ |
acpi_status acpi_disable_all_gpes(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_disable_all_gpes); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_hw_disable_all_gpes(); |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_disable_all_gpes) |
/****************************************************************************** |
* |
* FUNCTION: acpi_enable_all_runtime_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks |
* |
******************************************************************************/ |
acpi_status acpi_enable_all_runtime_gpes(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_hw_enable_all_runtime_gpes(); |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes) |
/****************************************************************************** |
* |
* FUNCTION: acpi_enable_all_wakeup_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable all "wakeup" GPEs and disable all of the other GPEs, in |
* all GPE blocks. |
* |
******************************************************************************/ |
acpi_status acpi_enable_all_wakeup_gpes(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_enable_all_wakeup_gpes); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_hw_enable_all_wakeup_gpes(); |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes) |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_gpe_block |
* |
* PARAMETERS: gpe_device - Handle to the parent GPE Block Device |
* gpe_block_address - Address and space_ID |
* register_count - Number of GPE register pairs in the block |
* interrupt_number - H/W interrupt for the block |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not |
* enabled here. |
* |
******************************************************************************/ |
acpi_status |
acpi_install_gpe_block(acpi_handle gpe_device, |
struct acpi_generic_address *gpe_block_address, |
u32 register_count, u32 interrupt_number) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
struct acpi_gpe_block_info *gpe_block; |
ACPI_FUNCTION_TRACE(acpi_install_gpe_block); |
if ((!gpe_device) || (!gpe_block_address) || (!register_count)) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
node = acpi_ns_validate_handle(gpe_device); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Validate the parent device */ |
if (node->type != ACPI_TYPE_DEVICE) { |
status = AE_TYPE; |
goto unlock_and_exit; |
} |
if (node->object) { |
status = AE_ALREADY_EXISTS; |
goto unlock_and_exit; |
} |
/* |
* For user-installed GPE Block Devices, the gpe_block_base_number |
* is always zero |
*/ |
status = acpi_ev_create_gpe_block(node, gpe_block_address->address, |
gpe_block_address->space_id, |
register_count, 0, interrupt_number, |
&gpe_block); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* Install block in the device_object attached to the node */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
/* |
* No object, create a new one (Device nodes do not always have |
* an attached object) |
*/ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto unlock_and_exit; |
} |
status = |
acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
} |
/* Now install the GPE block in the device_object */ |
obj_desc->device.gpe_block = gpe_block; |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_gpe_block) |
/******************************************************************************* |
* |
* FUNCTION: acpi_remove_gpe_block |
* |
* PARAMETERS: gpe_device - Handle to the parent GPE Block Device |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a previously installed block of GPE registers |
* |
******************************************************************************/ |
acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(acpi_remove_gpe_block); |
if (!gpe_device) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
node = acpi_ns_validate_handle(gpe_device); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Validate the parent device */ |
if (node->type != ACPI_TYPE_DEVICE) { |
status = AE_TYPE; |
goto unlock_and_exit; |
} |
/* Get the device_object attached to the node */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc || !obj_desc->device.gpe_block) { |
return_ACPI_STATUS(AE_NULL_OBJECT); |
} |
/* Delete the GPE block (but not the device_object) */ |
status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block); |
if (ACPI_SUCCESS(status)) { |
obj_desc->device.gpe_block = NULL; |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_gpe_device |
* |
* PARAMETERS: index - System GPE index (0-current_gpe_count) |
* gpe_device - Where the parent GPE Device is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Obtain the GPE device associated with the input index. A NULL |
* gpe device indicates that the gpe number is contained in one of |
* the FADT-defined gpe blocks. Otherwise, the GPE block device. |
* |
******************************************************************************/ |
acpi_status acpi_get_gpe_device(u32 index, acpi_handle * gpe_device) |
{ |
struct acpi_gpe_device_info info; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_get_gpe_device); |
if (!gpe_device) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (index >= acpi_current_gpe_count) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Setup and walk the GPE list */ |
info.index = index; |
info.status = AE_NOT_EXIST; |
info.gpe_device = NULL; |
info.next_block_base_index = 0; |
status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
*gpe_device = ACPI_CAST_PTR(acpi_handle, info.gpe_device); |
return_ACPI_STATUS(info.status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/evxfregn.c |
---|
0,0 → 1,295 |
/****************************************************************************** |
* |
* Module Name: evxfregn - External Interfaces, ACPI Operation Regions and |
* Address Spaces. |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_EVENTS |
ACPI_MODULE_NAME("evxfregn") |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_address_space_handler |
* |
* PARAMETERS: device - Handle for the device |
* space_id - The address space ID |
* handler - Address of the handler |
* setup - Address of the setup function |
* context - Value passed to the handler on each access |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for all op_regions of a given space_id. |
* |
* NOTE: This function should only be called after acpi_enable_subsystem has |
* been called. This is because any _REG methods associated with the Space ID |
* are executed here, and these methods can only be safely executed after |
* the default handlers have been installed and the hardware has been |
* initialized (via acpi_enable_subsystem.) |
* |
******************************************************************************/ |
acpi_status |
acpi_install_address_space_handler(acpi_handle device, |
acpi_adr_space_type space_id, |
acpi_adr_space_handler handler, |
acpi_adr_space_setup setup, void *context) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_address_space_handler); |
/* Parameter validation */ |
if (!device) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Convert and validate the device handle */ |
node = acpi_ns_validate_handle(device); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Install the handler for all Regions for this Space ID */ |
status = |
acpi_ev_install_space_handler(node, space_id, handler, setup, |
context); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* |
* For the default space_IDs, (the IDs for which there are default region handlers |
* installed) Only execute the _REG methods if the global initialization _REG |
* methods have already been run (via acpi_initialize_objects). In other words, |
* we will defer the execution of the _REG methods for these space_IDs until |
* execution of acpi_initialize_objects. This is done because we need the handlers |
* for the default spaces (mem/io/pci/table) to be installed before we can run |
* any control methods (or _REG methods). There is known BIOS code that depends |
* on this. |
* |
* For all other space_IDs, we can safely execute the _REG methods immediately. |
* This means that for IDs like embedded_controller, this function should be called |
* only after acpi_enable_subsystem has been called. |
*/ |
switch (space_id) { |
case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
case ACPI_ADR_SPACE_SYSTEM_IO: |
case ACPI_ADR_SPACE_PCI_CONFIG: |
case ACPI_ADR_SPACE_DATA_TABLE: |
if (!acpi_gbl_reg_methods_executed) { |
/* We will defer execution of the _REG methods for this space */ |
goto unlock_and_exit; |
} |
break; |
default: |
break; |
} |
/* Run all _REG methods for this address space */ |
status = acpi_ev_execute_reg_methods(node, space_id); |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_remove_address_space_handler |
* |
* PARAMETERS: device - Handle for the device |
* space_id - The address space ID |
* handler - Address of the handler |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a previously installed handler. |
* |
******************************************************************************/ |
acpi_status |
acpi_remove_address_space_handler(acpi_handle device, |
acpi_adr_space_type space_id, |
acpi_adr_space_handler handler) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *handler_obj; |
union acpi_operand_object *region_obj; |
union acpi_operand_object **last_obj_ptr; |
struct acpi_namespace_node *node; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler); |
/* Parameter validation */ |
if (!device) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Convert and validate the device handle */ |
node = acpi_ns_validate_handle(device); |
if (!node || |
((node->type != ACPI_TYPE_DEVICE) && |
(node->type != ACPI_TYPE_PROCESSOR) && |
(node->type != ACPI_TYPE_THERMAL) && |
(node != acpi_gbl_root_node))) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Make sure the internal object exists */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
status = AE_NOT_EXIST; |
goto unlock_and_exit; |
} |
/* Find the address handler the user requested */ |
handler_obj = obj_desc->device.handler; |
last_obj_ptr = &obj_desc->device.handler; |
while (handler_obj) { |
/* We have a handler, see if user requested this one */ |
if (handler_obj->address_space.space_id == space_id) { |
/* Handler must be the same as the installed handler */ |
if (handler_obj->address_space.handler != handler) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Matched space_id, first dereference this in the Regions */ |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Removing address handler %p(%p) for region %s " |
"on Device %p(%p)\n", |
handler_obj, handler, |
acpi_ut_get_region_name(space_id), |
node, obj_desc)); |
region_obj = handler_obj->address_space.region_list; |
/* Walk the handler's region list */ |
while (region_obj) { |
/* |
* First disassociate the handler from the region. |
* |
* NOTE: this doesn't mean that the region goes away |
* The region is just inaccessible as indicated to |
* the _REG method |
*/ |
acpi_ev_detach_region(region_obj, TRUE); |
/* |
* Walk the list: Just grab the head because the |
* detach_region removed the previous head. |
*/ |
region_obj = |
handler_obj->address_space.region_list; |
} |
/* Remove this Handler object from the list */ |
*last_obj_ptr = handler_obj->address_space.next; |
/* Now we can delete the handler object */ |
acpi_ut_remove_reference(handler_obj); |
goto unlock_and_exit; |
} |
/* Walk the linked list of handlers */ |
last_obj_ptr = &handler_obj->address_space.next; |
handler_obj = handler_obj->address_space.next; |
} |
/* The handler does not exist */ |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n", |
handler, acpi_ut_get_region_name(space_id), space_id, |
node, obj_desc)); |
status = AE_NOT_EXIST; |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler) |
/drivers/acpi/acpica/exconfig.c |
---|
0,0 → 1,626 |
/****************************************************************************** |
* |
* Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "actables.h" |
#include "acdispat.h" |
#include "acevents.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exconfig") |
/* Local prototypes */ |
static acpi_status |
acpi_ex_add_table(u32 table_index, |
struct acpi_namespace_node *parent_node, |
union acpi_operand_object **ddb_handle); |
static acpi_status |
acpi_ex_region_read(union acpi_operand_object *obj_desc, |
u32 length, u8 *buffer); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_add_table |
* |
* PARAMETERS: table - Pointer to raw table |
* parent_node - Where to load the table (scope) |
* ddb_handle - Where to return the table handle. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Common function to Install and Load an ACPI table with a |
* returned table handle. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_add_table(u32 table_index, |
struct acpi_namespace_node *parent_node, |
union acpi_operand_object **ddb_handle) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
acpi_owner_id owner_id; |
ACPI_FUNCTION_TRACE(ex_add_table); |
/* Create an object to be the table handle */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Init the table handle */ |
obj_desc->common.flags |= AOPOBJ_DATA_VALID; |
obj_desc->reference.class = ACPI_REFCLASS_TABLE; |
*ddb_handle = obj_desc; |
/* Install the new table into the local data structures */ |
obj_desc->reference.value = table_index; |
/* Add the table to the namespace */ |
status = acpi_ns_load_table(table_index, parent_node); |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(obj_desc); |
*ddb_handle = NULL; |
return_ACPI_STATUS(status); |
} |
/* Execute any module-level code that was found in the table */ |
acpi_ex_exit_interpreter(); |
acpi_ns_exec_module_code_list(); |
acpi_ex_enter_interpreter(); |
/* |
* Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is |
* responsible for discovering any new wake GPEs by running _PRW methods |
* that may have been loaded by this table. |
*/ |
status = acpi_tb_get_owner_id(table_index, &owner_id); |
if (ACPI_SUCCESS(status)) { |
acpi_ev_update_gpes(owner_id); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_load_table_op |
* |
* PARAMETERS: walk_state - Current state with operands |
* return_desc - Where to store the return object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load an ACPI table from the RSDT/XSDT |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_load_table_op(struct acpi_walk_state *walk_state, |
union acpi_operand_object **return_desc) |
{ |
acpi_status status; |
union acpi_operand_object **operand = &walk_state->operands[0]; |
struct acpi_namespace_node *parent_node; |
struct acpi_namespace_node *start_node; |
struct acpi_namespace_node *parameter_node = NULL; |
union acpi_operand_object *ddb_handle; |
struct acpi_table_header *table; |
u32 table_index; |
ACPI_FUNCTION_TRACE(ex_load_table_op); |
/* Find the ACPI table in the RSDT/XSDT */ |
status = acpi_tb_find_table(operand[0]->string.pointer, |
operand[1]->string.pointer, |
operand[2]->string.pointer, &table_index); |
if (ACPI_FAILURE(status)) { |
if (status != AE_NOT_FOUND) { |
return_ACPI_STATUS(status); |
} |
/* Table not found, return an Integer=0 and AE_OK */ |
ddb_handle = acpi_ut_create_integer_object((u64) 0); |
if (!ddb_handle) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
*return_desc = ddb_handle; |
return_ACPI_STATUS(AE_OK); |
} |
/* Default nodes */ |
start_node = walk_state->scope_info->scope.node; |
parent_node = acpi_gbl_root_node; |
/* root_path (optional parameter) */ |
if (operand[3]->string.length > 0) { |
/* |
* Find the node referenced by the root_path_string. This is the |
* location within the namespace where the table will be loaded. |
*/ |
status = |
acpi_ns_get_node(start_node, operand[3]->string.pointer, |
ACPI_NS_SEARCH_PARENT, &parent_node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* parameter_path (optional parameter) */ |
if (operand[4]->string.length > 0) { |
if ((operand[4]->string.pointer[0] != AML_ROOT_PREFIX) && |
(operand[4]->string.pointer[0] != AML_PARENT_PREFIX)) { |
/* |
* Path is not absolute, so it will be relative to the node |
* referenced by the root_path_string (or the NS root if omitted) |
*/ |
start_node = parent_node; |
} |
/* Find the node referenced by the parameter_path_string */ |
status = |
acpi_ns_get_node(start_node, operand[4]->string.pointer, |
ACPI_NS_SEARCH_PARENT, ¶meter_node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* Load the table into the namespace */ |
status = acpi_ex_add_table(table_index, parent_node, &ddb_handle); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Parameter Data (optional) */ |
if (parameter_node) { |
/* Store the parameter data into the optional parameter object */ |
status = acpi_ex_store(operand[5], |
ACPI_CAST_PTR(union acpi_operand_object, |
parameter_node), |
walk_state); |
if (ACPI_FAILURE(status)) { |
(void)acpi_ex_unload_table(ddb_handle); |
acpi_ut_remove_reference(ddb_handle); |
return_ACPI_STATUS(status); |
} |
} |
status = acpi_get_table_by_index(table_index, &table); |
if (ACPI_SUCCESS(status)) { |
ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); |
acpi_tb_print_table_header(0, table); |
} |
/* Invoke table handler if present */ |
if (acpi_gbl_table_handler) { |
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, |
acpi_gbl_table_handler_context); |
} |
*return_desc = ddb_handle; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_region_read |
* |
* PARAMETERS: obj_desc - Region descriptor |
* length - Number of bytes to read |
* buffer - Pointer to where to put the data |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read data from an operation region. The read starts from the |
* beginning of the region. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) |
{ |
acpi_status status; |
u64 value; |
u32 region_offset = 0; |
u32 i; |
/* Bytewise reads */ |
for (i = 0; i < length; i++) { |
status = |
acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ, |
region_offset, 8, &value); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
*buffer = (u8)value; |
buffer++; |
region_offset++; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_load_op |
* |
* PARAMETERS: obj_desc - Region or Buffer/Field where the table will be |
* obtained |
* target - Where a handle to the table will be stored |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load an ACPI table from a field or operation region |
* |
* NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer |
* objects before this code is reached. |
* |
* If source is an operation region, it must refer to system_memory, as |
* per the ACPI specification. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_load_op(union acpi_operand_object *obj_desc, |
union acpi_operand_object *target, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object *ddb_handle; |
struct acpi_table_header *table_header; |
struct acpi_table_header *table; |
u32 table_index; |
acpi_status status; |
u32 length; |
ACPI_FUNCTION_TRACE(ex_load_op); |
/* Source Object can be either an op_region or a Buffer/Field */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_REGION: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Load table from Region %p\n", obj_desc)); |
/* Region must be system_memory (from ACPI spec) */ |
if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* |
* If the Region Address and Length have not been previously evaluated, |
* evaluate them now and save the results. |
*/ |
if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { |
status = acpi_ds_get_region_arguments(obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* Get the table header first so we can get the table length */ |
table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); |
if (!table_header) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
status = |
acpi_ex_region_read(obj_desc, |
sizeof(struct acpi_table_header), |
ACPI_CAST_PTR(u8, table_header)); |
length = table_header->length; |
ACPI_FREE(table_header); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Must have at least an ACPI table header */ |
if (length < sizeof(struct acpi_table_header)) { |
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); |
} |
/* |
* The original implementation simply mapped the table, with no copy. |
* However, the memory region is not guaranteed to remain stable and |
* we must copy the table to a local buffer. For example, the memory |
* region is corrupted after suspend on some machines. Dynamically |
* loaded tables are usually small, so this overhead is minimal. |
* |
* The latest implementation (5/2009) does not use a mapping at all. |
* We use the low-level operation region interface to read the table |
* instead of the obvious optimization of using a direct mapping. |
* This maintains a consistent use of operation regions across the |
* entire subsystem. This is important if additional processing must |
* be performed in the (possibly user-installed) operation region |
* handler. For example, acpi_exec and ASLTS depend on this. |
*/ |
/* Allocate a buffer for the table */ |
table = ACPI_ALLOCATE(length); |
if (!table) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Read the entire table */ |
status = acpi_ex_region_read(obj_desc, length, |
ACPI_CAST_PTR(u8, table)); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(table); |
return_ACPI_STATUS(status); |
} |
break; |
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Load table from Buffer or Field %p\n", |
obj_desc)); |
/* Must have at least an ACPI table header */ |
if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) { |
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); |
} |
/* Get the actual table length from the table header */ |
table_header = |
ACPI_CAST_PTR(struct acpi_table_header, |
obj_desc->buffer.pointer); |
length = table_header->length; |
/* Table cannot extend beyond the buffer */ |
if (length > obj_desc->buffer.length) { |
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); |
} |
if (length < sizeof(struct acpi_table_header)) { |
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); |
} |
/* |
* Copy the table from the buffer because the buffer could be modified |
* or even deleted in the future |
*/ |
table = ACPI_ALLOCATE(length); |
if (!table) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
memcpy(table, table_header, length); |
break; |
default: |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* Install the new table into the local data structures */ |
ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), |
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, |
TRUE, TRUE, &table_index); |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
if (ACPI_FAILURE(status)) { |
/* Delete allocated table buffer */ |
ACPI_FREE(table); |
return_ACPI_STATUS(status); |
} |
/* |
* Note: Now table is "INSTALLED", it must be validated before |
* loading. |
*/ |
status = |
acpi_tb_validate_table(&acpi_gbl_root_table_list. |
tables[table_index]); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Add the table to the namespace. |
* |
* Note: Load the table objects relative to the root of the namespace. |
* This appears to go against the ACPI specification, but we do it for |
* compatibility with other ACPI implementations. |
*/ |
status = |
acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle); |
if (ACPI_FAILURE(status)) { |
/* On error, table_ptr was deallocated above */ |
return_ACPI_STATUS(status); |
} |
/* Store the ddb_handle into the Target operand */ |
status = acpi_ex_store(ddb_handle, target, walk_state); |
if (ACPI_FAILURE(status)) { |
(void)acpi_ex_unload_table(ddb_handle); |
/* table_ptr was deallocated above */ |
acpi_ut_remove_reference(ddb_handle); |
return_ACPI_STATUS(status); |
} |
/* Remove the reference by added by acpi_ex_store above */ |
acpi_ut_remove_reference(ddb_handle); |
/* Invoke table handler if present */ |
if (acpi_gbl_table_handler) { |
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, |
acpi_gbl_table_handler_context); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_unload_table |
* |
* PARAMETERS: ddb_handle - Handle to a previously loaded table |
* |
* RETURN: Status |
* |
* DESCRIPTION: Unload an ACPI table |
* |
******************************************************************************/ |
acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *table_desc = ddb_handle; |
u32 table_index; |
struct acpi_table_header *table; |
ACPI_FUNCTION_TRACE(ex_unload_table); |
/* |
* Temporarily emit a warning so that the ASL for the machine can be |
* hopefully obtained. This is to say that the Unload() operator is |
* extremely rare if not completely unused. |
*/ |
ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table")); |
/* |
* Validate the handle |
* Although the handle is partially validated in acpi_ex_reconfiguration() |
* when it calls acpi_ex_resolve_operands(), the handle is more completely |
* validated here. |
* |
* Handle must be a valid operand object of type reference. Also, the |
* ddb_handle must still be marked valid (table has not been previously |
* unloaded) |
*/ |
if ((!ddb_handle) || |
(ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || |
(ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) || |
(!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) { |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* Get the table index from the ddb_handle */ |
table_index = table_desc->reference.value; |
/* Ensure the table is still loaded */ |
if (!acpi_tb_is_table_loaded(table_index)) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Invoke table handler if present */ |
if (acpi_gbl_table_handler) { |
status = acpi_get_table_by_index(table_index, &table); |
if (ACPI_SUCCESS(status)) { |
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD, |
table, |
acpi_gbl_table_handler_context); |
} |
} |
/* Delete the portion of the namespace owned by this table */ |
status = acpi_tb_delete_namespace_by_owner(table_index); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
(void)acpi_tb_release_owner_id(table_index); |
acpi_tb_set_table_loaded_flag(table_index, FALSE); |
/* |
* Invalidate the handle. We do this because the handle may be stored |
* in a named object and may not be actually deleted until much later. |
*/ |
ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID; |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/exconvrt.c |
---|
0,0 → 1,694 |
/****************************************************************************** |
* |
* Module Name: exconvrt - Object conversion routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exconvrt") |
/* Local prototypes */ |
static u32 |
acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_convert_to_integer |
* |
* PARAMETERS: obj_desc - Object to be converted. Must be an |
* Integer, Buffer, or String |
* result_desc - Where the new Integer object is returned |
* flags - Used for string conversion |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an ACPI Object to an integer. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, |
union acpi_operand_object **result_desc, u32 flags) |
{ |
union acpi_operand_object *return_desc; |
u8 *pointer; |
u64 result; |
u32 i; |
u32 count; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ex_convert_to_integer, obj_desc); |
switch (obj_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
/* No conversion necessary */ |
*result_desc = obj_desc; |
return_ACPI_STATUS(AE_OK); |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_STRING: |
/* Note: Takes advantage of common buffer/string fields */ |
pointer = obj_desc->buffer.pointer; |
count = obj_desc->buffer.length; |
break; |
default: |
return_ACPI_STATUS(AE_TYPE); |
} |
/* |
* Convert the buffer/string to an integer. Note that both buffers and |
* strings are treated as raw data - we don't convert ascii to hex for |
* strings. |
* |
* There are two terminating conditions for the loop: |
* 1) The size of an integer has been reached, or |
* 2) The end of the buffer or string has been reached |
*/ |
result = 0; |
/* String conversion is different than Buffer conversion */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_STRING: |
/* |
* Convert string to an integer - for most cases, the string must be |
* hexadecimal as per the ACPI specification. The only exception (as |
* of ACPI 3.0) is that the to_integer() operator allows both decimal |
* and hexadecimal strings (hex prefixed with "0x"). |
*/ |
status = acpi_ut_strtoul64((char *)pointer, flags, &result); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
break; |
case ACPI_TYPE_BUFFER: |
/* Check for zero-length buffer */ |
if (!count) { |
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); |
} |
/* Transfer no more than an integer's worth of data */ |
if (count > acpi_gbl_integer_byte_width) { |
count = acpi_gbl_integer_byte_width; |
} |
/* |
* Convert buffer to an integer - we simply grab enough raw data |
* from the buffer to fill an integer |
*/ |
for (i = 0; i < count; i++) { |
/* |
* Get next byte and shift it into the Result. |
* Little endian is used, meaning that the first byte of the buffer |
* is the LSB of the integer |
*/ |
result |= (((u64) pointer[i]) << (i * 8)); |
} |
break; |
default: |
/* No other types can get here */ |
break; |
} |
/* Create a new integer */ |
return_desc = acpi_ut_create_integer_object(result); |
if (!return_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(result))); |
/* Save the Result */ |
(void)acpi_ex_truncate_for32bit_table(return_desc); |
*result_desc = return_desc; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_convert_to_buffer |
* |
* PARAMETERS: obj_desc - Object to be converted. Must be an |
* Integer, Buffer, or String |
* result_desc - Where the new buffer object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an ACPI Object to a Buffer |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, |
union acpi_operand_object **result_desc) |
{ |
union acpi_operand_object *return_desc; |
u8 *new_buf; |
ACPI_FUNCTION_TRACE_PTR(ex_convert_to_buffer, obj_desc); |
switch (obj_desc->common.type) { |
case ACPI_TYPE_BUFFER: |
/* No conversion necessary */ |
*result_desc = obj_desc; |
return_ACPI_STATUS(AE_OK); |
case ACPI_TYPE_INTEGER: |
/* |
* Create a new Buffer object. |
* Need enough space for one integer |
*/ |
return_desc = |
acpi_ut_create_buffer_object(acpi_gbl_integer_byte_width); |
if (!return_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Copy the integer to the buffer, LSB first */ |
new_buf = return_desc->buffer.pointer; |
memcpy(new_buf, |
&obj_desc->integer.value, acpi_gbl_integer_byte_width); |
break; |
case ACPI_TYPE_STRING: |
/* |
* Create a new Buffer object |
* Size will be the string length |
* |
* NOTE: Add one to the string length to include the null terminator. |
* The ACPI spec is unclear on this subject, but there is existing |
* ASL/AML code that depends on the null being transferred to the new |
* buffer. |
*/ |
return_desc = acpi_ut_create_buffer_object((acpi_size) |
obj_desc->string. |
length + 1); |
if (!return_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Copy the string to the buffer */ |
new_buf = return_desc->buffer.pointer; |
strncpy((char *)new_buf, (char *)obj_desc->string.pointer, |
obj_desc->string.length); |
break; |
default: |
return_ACPI_STATUS(AE_TYPE); |
} |
/* Mark buffer initialized */ |
return_desc->common.flags |= AOPOBJ_DATA_VALID; |
*result_desc = return_desc; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_convert_to_ascii |
* |
* PARAMETERS: integer - Value to be converted |
* base - ACPI_STRING_DECIMAL or ACPI_STRING_HEX |
* string - Where the string is returned |
* data_width - Size of data item to be converted, in bytes |
* |
* RETURN: Actual string length |
* |
* DESCRIPTION: Convert an ACPI Integer to a hex or decimal string |
* |
******************************************************************************/ |
static u32 |
acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width) |
{ |
u64 digit; |
u32 i; |
u32 j; |
u32 k = 0; |
u32 hex_length; |
u32 decimal_length; |
u32 remainder; |
u8 supress_zeros; |
ACPI_FUNCTION_ENTRY(); |
switch (base) { |
case 10: |
/* Setup max length for the decimal number */ |
switch (data_width) { |
case 1: |
decimal_length = ACPI_MAX8_DECIMAL_DIGITS; |
break; |
case 4: |
decimal_length = ACPI_MAX32_DECIMAL_DIGITS; |
break; |
case 8: |
default: |
decimal_length = ACPI_MAX64_DECIMAL_DIGITS; |
break; |
} |
supress_zeros = TRUE; /* No leading zeros */ |
remainder = 0; |
for (i = decimal_length; i > 0; i--) { |
/* Divide by nth factor of 10 */ |
digit = integer; |
for (j = 0; j < i; j++) { |
(void)acpi_ut_short_divide(digit, 10, &digit, |
&remainder); |
} |
/* Handle leading zeros */ |
if (remainder != 0) { |
supress_zeros = FALSE; |
} |
if (!supress_zeros) { |
string[k] = (u8) (ACPI_ASCII_ZERO + remainder); |
k++; |
} |
} |
break; |
case 16: |
/* hex_length: 2 ascii hex chars per data byte */ |
hex_length = ACPI_MUL_2(data_width); |
for (i = 0, j = (hex_length - 1); i < hex_length; i++, j--) { |
/* Get one hex digit, most significant digits first */ |
string[k] = |
(u8) acpi_ut_hex_to_ascii_char(integer, |
ACPI_MUL_4(j)); |
k++; |
} |
break; |
default: |
return (0); |
} |
/* |
* Since leading zeros are suppressed, we must check for the case where |
* the integer equals 0 |
* |
* Finally, null terminate the string and return the length |
*/ |
if (!k) { |
string[0] = ACPI_ASCII_ZERO; |
k = 1; |
} |
string[k] = 0; |
return ((u32) k); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_convert_to_string |
* |
* PARAMETERS: obj_desc - Object to be converted. Must be an |
* Integer, Buffer, or String |
* result_desc - Where the string object is returned |
* type - String flags (base and conversion type) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an ACPI Object to a string |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_convert_to_string(union acpi_operand_object * obj_desc, |
union acpi_operand_object ** result_desc, u32 type) |
{ |
union acpi_operand_object *return_desc; |
u8 *new_buf; |
u32 i; |
u32 string_length = 0; |
u16 base = 16; |
u8 separator = ','; |
ACPI_FUNCTION_TRACE_PTR(ex_convert_to_string, obj_desc); |
switch (obj_desc->common.type) { |
case ACPI_TYPE_STRING: |
/* No conversion necessary */ |
*result_desc = obj_desc; |
return_ACPI_STATUS(AE_OK); |
case ACPI_TYPE_INTEGER: |
switch (type) { |
case ACPI_EXPLICIT_CONVERT_DECIMAL: |
/* Make room for maximum decimal number */ |
string_length = ACPI_MAX_DECIMAL_DIGITS; |
base = 10; |
break; |
default: |
/* Two hex string characters for each integer byte */ |
string_length = ACPI_MUL_2(acpi_gbl_integer_byte_width); |
break; |
} |
/* |
* Create a new String |
* Need enough space for one ASCII integer (plus null terminator) |
*/ |
return_desc = |
acpi_ut_create_string_object((acpi_size) string_length); |
if (!return_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
new_buf = return_desc->buffer.pointer; |
/* Convert integer to string */ |
string_length = |
acpi_ex_convert_to_ascii(obj_desc->integer.value, base, |
new_buf, |
acpi_gbl_integer_byte_width); |
/* Null terminate at the correct place */ |
return_desc->string.length = string_length; |
new_buf[string_length] = 0; |
break; |
case ACPI_TYPE_BUFFER: |
/* Setup string length, base, and separator */ |
switch (type) { |
case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string */ |
/* |
* From ACPI: "If Data is a buffer, it is converted to a string of |
* decimal values separated by commas." |
*/ |
base = 10; |
/* |
* Calculate the final string length. Individual string values |
* are variable length (include separator for each) |
*/ |
for (i = 0; i < obj_desc->buffer.length; i++) { |
if (obj_desc->buffer.pointer[i] >= 100) { |
string_length += 4; |
} else if (obj_desc->buffer.pointer[i] >= 10) { |
string_length += 3; |
} else { |
string_length += 2; |
} |
} |
break; |
case ACPI_IMPLICIT_CONVERT_HEX: |
/* |
* From the ACPI spec: |
*"The entire contents of the buffer are converted to a string of |
* two-character hexadecimal numbers, each separated by a space." |
*/ |
separator = ' '; |
string_length = (obj_desc->buffer.length * 3); |
break; |
case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string */ |
/* |
* From ACPI: "If Data is a buffer, it is converted to a string of |
* hexadecimal values separated by commas." |
*/ |
string_length = (obj_desc->buffer.length * 3); |
break; |
default: |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* Create a new string object and string buffer |
* (-1 because of extra separator included in string_length from above) |
* Allow creation of zero-length strings from zero-length buffers. |
*/ |
if (string_length) { |
string_length--; |
} |
return_desc = |
acpi_ut_create_string_object((acpi_size) string_length); |
if (!return_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
new_buf = return_desc->buffer.pointer; |
/* |
* Convert buffer bytes to hex or decimal values |
* (separated by commas or spaces) |
*/ |
for (i = 0; i < obj_desc->buffer.length; i++) { |
new_buf += acpi_ex_convert_to_ascii((u64) obj_desc-> |
buffer.pointer[i], |
base, new_buf, 1); |
*new_buf++ = separator; /* each separated by a comma or space */ |
} |
/* |
* Null terminate the string |
* (overwrites final comma/space from above) |
*/ |
if (obj_desc->buffer.length) { |
new_buf--; |
} |
*new_buf = 0; |
break; |
default: |
return_ACPI_STATUS(AE_TYPE); |
} |
*result_desc = return_desc; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_convert_to_target_type |
* |
* PARAMETERS: destination_type - Current type of the destination |
* source_desc - Source object to be converted. |
* result_desc - Where the converted object is returned |
* walk_state - Current method state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Implements "implicit conversion" rules for storing an object. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_convert_to_target_type(acpi_object_type destination_type, |
union acpi_operand_object *source_desc, |
union acpi_operand_object **result_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_convert_to_target_type); |
/* Default behavior */ |
*result_desc = source_desc; |
/* |
* If required by the target, |
* perform implicit conversion on the source before we store it. |
*/ |
switch (GET_CURRENT_ARG_TYPE(walk_state->op_info->runtime_args)) { |
case ARGI_SIMPLE_TARGET: |
case ARGI_FIXED_TARGET: |
case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ |
switch (destination_type) { |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
/* |
* Named field can always handle conversions |
*/ |
break; |
default: |
/* No conversion allowed for these types */ |
if (destination_type != source_desc->common.type) { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Explicit operator, will store (%s) over existing type (%s)\n", |
acpi_ut_get_object_type_name |
(source_desc), |
acpi_ut_get_type_name |
(destination_type))); |
status = AE_TYPE; |
} |
} |
break; |
case ARGI_TARGETREF: |
case ARGI_STORE_TARGET: |
switch (destination_type) { |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
/* |
* These types require an Integer operand. We can convert |
* a Buffer or a String to an Integer if necessary. |
*/ |
status = |
acpi_ex_convert_to_integer(source_desc, result_desc, |
16); |
break; |
case ACPI_TYPE_STRING: |
/* |
* The operand must be a String. We can convert an |
* Integer or Buffer if necessary |
*/ |
status = |
acpi_ex_convert_to_string(source_desc, result_desc, |
ACPI_IMPLICIT_CONVERT_HEX); |
break; |
case ACPI_TYPE_BUFFER: |
/* |
* The operand must be a Buffer. We can convert an |
* Integer or String if necessary |
*/ |
status = |
acpi_ex_convert_to_buffer(source_desc, result_desc); |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Bad destination type during conversion: 0x%X", |
destination_type)); |
status = AE_AML_INTERNAL; |
break; |
} |
break; |
case ARGI_REFERENCE: |
/* |
* create_xxxx_field cases - we are storing the field object into the name |
*/ |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown Target type ID 0x%X AmlOpcode 0x%X DestType %s", |
GET_CURRENT_ARG_TYPE(walk_state->op_info-> |
runtime_args), |
walk_state->opcode, |
acpi_ut_get_type_name(destination_type))); |
status = AE_AML_INTERNAL; |
} |
/* |
* Source-to-Target conversion semantics: |
* |
* If conversion to the target type cannot be performed, then simply |
* overwrite the target with the new object and type. |
*/ |
if (status == AE_TYPE) { |
status = AE_OK; |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/excreate.c |
---|
0,0 → 1,529 |
/****************************************************************************** |
* |
* Module Name: excreate - Named object creation |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("excreate") |
#ifndef ACPI_NO_METHOD_EXECUTION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_create_alias |
* |
* PARAMETERS: walk_state - Current state, contains operands |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new named alias |
* |
******************************************************************************/ |
acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) |
{ |
struct acpi_namespace_node *target_node; |
struct acpi_namespace_node *alias_node; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_create_alias); |
/* Get the source/alias operands (both namespace nodes) */ |
alias_node = (struct acpi_namespace_node *)walk_state->operands[0]; |
target_node = (struct acpi_namespace_node *)walk_state->operands[1]; |
if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) || |
(target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
/* |
* Dereference an existing alias so that we don't create a chain |
* of aliases. With this code, we guarantee that an alias is |
* always exactly one level of indirection away from the |
* actual aliased name. |
*/ |
target_node = |
ACPI_CAST_PTR(struct acpi_namespace_node, |
target_node->object); |
} |
/* |
* For objects that can never change (i.e., the NS node will |
* permanently point to the same object), we can simply attach |
* the object to the new NS node. For other objects (such as |
* Integers, buffers, etc.), we have to point the Alias node |
* to the original Node. |
*/ |
switch (target_node->type) { |
/* For these types, the sub-object can change dynamically via a Store */ |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_PACKAGE: |
case ACPI_TYPE_BUFFER_FIELD: |
/* |
* These types open a new scope, so we need the NS node in order to access |
* any children. |
*/ |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_POWER: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_THERMAL: |
case ACPI_TYPE_LOCAL_SCOPE: |
/* |
* The new alias has the type ALIAS and points to the original |
* NS node, not the object itself. |
*/ |
alias_node->type = ACPI_TYPE_LOCAL_ALIAS; |
alias_node->object = |
ACPI_CAST_PTR(union acpi_operand_object, target_node); |
break; |
case ACPI_TYPE_METHOD: |
/* |
* Control method aliases need to be differentiated |
*/ |
alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; |
alias_node->object = |
ACPI_CAST_PTR(union acpi_operand_object, target_node); |
break; |
default: |
/* Attach the original source object to the new Alias Node */ |
/* |
* The new alias assumes the type of the target, and it points |
* to the same object. The reference count of the object has an |
* additional reference to prevent deletion out from under either the |
* target node or the alias Node |
*/ |
status = acpi_ns_attach_object(alias_node, |
acpi_ns_get_attached_object |
(target_node), |
target_node->type); |
break; |
} |
/* Since both operands are Nodes, we don't need to delete them */ |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_create_event |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new event object |
* |
******************************************************************************/ |
acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_TRACE(ex_create_event); |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_EVENT); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* Create the actual OS semaphore, with zero initial units -- meaning |
* that the event is created in an unsignalled state |
*/ |
status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, |
&obj_desc->event.os_semaphore); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Attach object to the Node */ |
status = |
acpi_ns_attach_object((struct acpi_namespace_node *)walk_state-> |
operands[0], obj_desc, ACPI_TYPE_EVENT); |
cleanup: |
/* |
* Remove local reference to the object (on error, will cause deletion |
* of both object and semaphore if present.) |
*/ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_create_mutex |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new mutex object |
* |
* Mutex (Name[0], sync_level[1]) |
* |
******************************************************************************/ |
acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_TRACE_PTR(ex_create_mutex, ACPI_WALK_OPERANDS); |
/* Create the new mutex object */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Create the actual OS Mutex */ |
status = acpi_os_create_mutex(&obj_desc->mutex.os_mutex); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Init object and attach to NS node */ |
obj_desc->mutex.sync_level = (u8)walk_state->operands[1]->integer.value; |
obj_desc->mutex.node = |
(struct acpi_namespace_node *)walk_state->operands[0]; |
status = |
acpi_ns_attach_object(obj_desc->mutex.node, obj_desc, |
ACPI_TYPE_MUTEX); |
cleanup: |
/* |
* Remove local reference to the object (on error, will cause deletion |
* of both object and semaphore if present.) |
*/ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_create_region |
* |
* PARAMETERS: aml_start - Pointer to the region declaration AML |
* aml_length - Max length of the declaration AML |
* space_id - Address space ID for the region |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new operation region object |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_create_region(u8 * aml_start, |
u32 aml_length, |
u8 space_id, struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_operand_object *obj_desc; |
struct acpi_namespace_node *node; |
union acpi_operand_object *region_obj2; |
ACPI_FUNCTION_TRACE(ex_create_region); |
/* Get the Namespace Node */ |
node = walk_state->op->common.node; |
/* |
* If the region object is already attached to this node, |
* just return |
*/ |
if (acpi_ns_get_attached_object(node)) { |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Space ID must be one of the predefined IDs, or in the user-defined |
* range |
*/ |
if (!acpi_is_valid_space_id(space_id)) { |
/* |
* Print an error message, but continue. We don't want to abort |
* a table load for this exception. Instead, if the region is |
* actually used at runtime, abort the executing method. |
*/ |
ACPI_ERROR((AE_INFO, |
"Invalid/unknown Address Space ID: 0x%2.2X", |
space_id)); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n", |
acpi_ut_get_region_name(space_id), space_id)); |
/* Create the region descriptor */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* Remember location in AML stream of address & length |
* operands since they need to be evaluated at run time. |
*/ |
region_obj2 = obj_desc->common.next_object; |
region_obj2->extra.aml_start = aml_start; |
region_obj2->extra.aml_length = aml_length; |
if (walk_state->scope_info) { |
region_obj2->extra.scope_node = |
walk_state->scope_info->scope.node; |
} else { |
region_obj2->extra.scope_node = node; |
} |
/* Init the region from the operands */ |
obj_desc->region.space_id = space_id; |
obj_desc->region.address = 0; |
obj_desc->region.length = 0; |
obj_desc->region.node = node; |
/* Install the new region object in the parent Node */ |
status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION); |
cleanup: |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_create_processor |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new processor object and populate the fields |
* |
* Processor (Name[0], cpu_ID[1], pblock_addr[2], pblock_length[3]) |
* |
******************************************************************************/ |
acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ex_create_processor, walk_state); |
/* Create the processor object */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PROCESSOR); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Initialize the processor object from the operands */ |
obj_desc->processor.proc_id = (u8) operand[1]->integer.value; |
obj_desc->processor.length = (u8) operand[3]->integer.value; |
obj_desc->processor.address = |
(acpi_io_address) operand[2]->integer.value; |
/* Install the processor object in the parent Node */ |
status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0], |
obj_desc, ACPI_TYPE_PROCESSOR); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_create_power_resource |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new power_resource object and populate the fields |
* |
* power_resource (Name[0], system_level[1], resource_order[2]) |
* |
******************************************************************************/ |
acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
acpi_status status; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_TRACE_PTR(ex_create_power_resource, walk_state); |
/* Create the power resource object */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_POWER); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Initialize the power object from the operands */ |
obj_desc->power_resource.system_level = (u8) operand[1]->integer.value; |
obj_desc->power_resource.resource_order = |
(u16) operand[2]->integer.value; |
/* Install the power resource object in the parent Node */ |
status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0], |
obj_desc, ACPI_TYPE_POWER); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_create_method |
* |
* PARAMETERS: aml_start - First byte of the method's AML |
* aml_length - AML byte count for this method |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new method object |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_create_method(u8 * aml_start, |
u32 aml_length, struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *obj_desc; |
acpi_status status; |
u8 method_flags; |
ACPI_FUNCTION_TRACE_PTR(ex_create_method, walk_state); |
/* Create a new method object */ |
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto exit; |
} |
/* Save the method's AML pointer and length */ |
obj_desc->method.aml_start = aml_start; |
obj_desc->method.aml_length = aml_length; |
obj_desc->method.node = operand[0]; |
/* |
* Disassemble the method flags. Split off the arg_count, Serialized |
* flag, and sync_level for efficiency. |
*/ |
method_flags = (u8) operand[1]->integer.value; |
obj_desc->method.param_count = |
(u8) (method_flags & AML_METHOD_ARG_COUNT); |
/* |
* Get the sync_level. If method is serialized, a mutex will be |
* created for this method when it is parsed. |
*/ |
if (method_flags & AML_METHOD_SERIALIZED) { |
obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED; |
/* |
* ACPI 1.0: sync_level = 0 |
* ACPI 2.0: sync_level = sync_level in method declaration |
*/ |
obj_desc->method.sync_level = (u8) |
((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); |
} |
/* Attach the new object to the method Node */ |
status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0], |
obj_desc, ACPI_TYPE_METHOD); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
exit: |
/* Remove a reference to the operand */ |
acpi_ut_remove_reference(operand[1]); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exdebug.c |
---|
0,0 → 1,634 |
/****************************************************************************** |
* |
* Module Name: exdebug - Support for stores to the AML Debug Object |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#include "acparser.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exdebug") |
static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; |
/* Local prototypes */ |
#ifdef ACPI_DEBUG_OUTPUT |
static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type); |
#endif |
#ifndef ACPI_NO_ERROR_MESSAGES |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_do_debug_object |
* |
* PARAMETERS: source_desc - Object to be output to "Debug Object" |
* level - Indentation level (used for packages) |
* index - Current package element, zero if not pkg |
* |
* RETURN: None |
* |
* DESCRIPTION: Handles stores to the AML Debug Object. For example: |
* Store(INT1, Debug) |
* |
* This function is not compiled if ACPI_NO_ERROR_MESSAGES is set. |
* |
* This function is only enabled if acpi_gbl_enable_aml_debug_object is set, or |
* if ACPI_LV_DEBUG_OBJECT is set in the acpi_dbg_level. Thus, in the normal |
* operational case, stores to the debug object are ignored but can be easily |
* enabled if necessary. |
* |
******************************************************************************/ |
void |
acpi_ex_do_debug_object(union acpi_operand_object *source_desc, |
u32 level, u32 index) |
{ |
u32 i; |
u32 timer; |
union acpi_operand_object *object_desc; |
u32 value; |
ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc); |
/* Output must be enabled via the debug_object global or the dbg_level */ |
if (!acpi_gbl_enable_aml_debug_object && |
!(acpi_dbg_level & ACPI_LV_DEBUG_OBJECT)) { |
return_VOID; |
} |
/* |
* We will emit the current timer value (in microseconds) with each |
* debug output. Only need the lower 26 bits. This allows for 67 |
* million microseconds or 67 seconds before rollover. |
*/ |
timer = ((u32)acpi_os_get_timer() / 10); /* (100 nanoseconds to microseconds) */ |
timer &= 0x03FFFFFF; |
/* |
* Print line header as long as we are not in the middle of an |
* object display |
*/ |
if (!((level > 0) && index == 0)) { |
acpi_os_printf("[ACPI Debug %.8u] %*s", timer, level, " "); |
} |
/* Display the index for package output only */ |
if (index > 0) { |
acpi_os_printf("(%.2u) ", index - 1); |
} |
if (!source_desc) { |
acpi_os_printf("[Null Object]\n"); |
return_VOID; |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) { |
acpi_os_printf("%s ", |
acpi_ut_get_object_type_name(source_desc)); |
if (!acpi_ut_valid_internal_object(source_desc)) { |
acpi_os_printf("%p, Invalid Internal Object!\n", |
source_desc); |
return_VOID; |
} |
} else if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == |
ACPI_DESC_TYPE_NAMED) { |
acpi_os_printf("%s: %p\n", |
acpi_ut_get_type_name(((struct |
acpi_namespace_node *) |
source_desc)->type), |
source_desc); |
return_VOID; |
} else { |
return_VOID; |
} |
/* source_desc is of type ACPI_DESC_TYPE_OPERAND */ |
switch (source_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
/* Output correct integer width */ |
if (acpi_gbl_integer_byte_width == 4) { |
acpi_os_printf("0x%8.8X\n", |
(u32)source_desc->integer.value); |
} else { |
acpi_os_printf("0x%8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(source_desc->integer. |
value)); |
} |
break; |
case ACPI_TYPE_BUFFER: |
acpi_os_printf("[0x%.2X]\n", (u32)source_desc->buffer.length); |
acpi_ut_dump_buffer(source_desc->buffer.pointer, |
(source_desc->buffer.length < 256) ? |
source_desc->buffer.length : 256, |
DB_BYTE_DISPLAY, 0); |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf("[0x%.2X] \"%s\"\n", |
source_desc->string.length, |
source_desc->string.pointer); |
break; |
case ACPI_TYPE_PACKAGE: |
acpi_os_printf("[Contains 0x%.2X Elements]\n", |
source_desc->package.count); |
/* Output the entire contents of the package */ |
for (i = 0; i < source_desc->package.count; i++) { |
acpi_ex_do_debug_object(source_desc->package. |
elements[i], level + 4, i + 1); |
} |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
acpi_os_printf("[%s] ", |
acpi_ut_get_reference_name(source_desc)); |
/* Decode the reference */ |
switch (source_desc->reference.class) { |
case ACPI_REFCLASS_INDEX: |
acpi_os_printf("0x%X\n", source_desc->reference.value); |
break; |
case ACPI_REFCLASS_TABLE: |
/* Case for ddb_handle */ |
acpi_os_printf("Table Index 0x%X\n", |
source_desc->reference.value); |
return_VOID; |
default: |
break; |
} |
acpi_os_printf(" "); |
/* Check for valid node first, then valid object */ |
if (source_desc->reference.node) { |
if (ACPI_GET_DESCRIPTOR_TYPE |
(source_desc->reference.node) != |
ACPI_DESC_TYPE_NAMED) { |
acpi_os_printf |
(" %p - Not a valid namespace node\n", |
source_desc->reference.node); |
} else { |
acpi_os_printf("Node %p [%4.4s] ", |
source_desc->reference.node, |
(source_desc->reference.node)-> |
name.ascii); |
switch ((source_desc->reference.node)->type) { |
/* These types have no attached object */ |
case ACPI_TYPE_DEVICE: |
acpi_os_printf("Device\n"); |
break; |
case ACPI_TYPE_THERMAL: |
acpi_os_printf("Thermal Zone\n"); |
break; |
default: |
acpi_ex_do_debug_object((source_desc-> |
reference. |
node)->object, |
level + 4, 0); |
break; |
} |
} |
} else if (source_desc->reference.object) { |
if (ACPI_GET_DESCRIPTOR_TYPE |
(source_desc->reference.object) == |
ACPI_DESC_TYPE_NAMED) { |
acpi_ex_do_debug_object(((struct |
acpi_namespace_node *) |
source_desc->reference. |
object)->object, |
level + 4, 0); |
} else { |
object_desc = source_desc->reference.object; |
value = source_desc->reference.value; |
switch (object_desc->common.type) { |
case ACPI_TYPE_BUFFER: |
acpi_os_printf("Buffer[%u] = 0x%2.2X\n", |
value, |
*source_desc->reference. |
index_pointer); |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf |
("String[%u] = \"%c\" (0x%2.2X)\n", |
value, |
*source_desc->reference. |
index_pointer, |
*source_desc->reference. |
index_pointer); |
break; |
case ACPI_TYPE_PACKAGE: |
acpi_os_printf("Package[%u] = ", value); |
acpi_ex_do_debug_object(*source_desc-> |
reference.where, |
level + 4, 0); |
break; |
default: |
acpi_os_printf |
("Unknown Reference object type %X\n", |
object_desc->common.type); |
break; |
} |
} |
} |
break; |
default: |
acpi_os_printf("%p\n", source_desc); |
break; |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "\n")); |
return_VOID; |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_interpreter_trace_enabled |
* |
* PARAMETERS: name - Whether method name should be matched, |
* this should be checked before starting |
* the tracer |
* |
* RETURN: TRUE if interpreter trace is enabled. |
* |
* DESCRIPTION: Check whether interpreter trace is enabled |
* |
******************************************************************************/ |
static u8 acpi_ex_interpreter_trace_enabled(char *name) |
{ |
/* Check if tracing is enabled */ |
if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) { |
return (FALSE); |
} |
/* |
* Check if tracing is filtered: |
* |
* 1. If the tracer is started, acpi_gbl_trace_method_object should have |
* been filled by the trace starter |
* 2. If the tracer is not started, acpi_gbl_trace_method_name should be |
* matched if it is specified |
* 3. If the tracer is oneshot style, acpi_gbl_trace_method_name should |
* not be cleared by the trace stopper during the first match |
*/ |
if (acpi_gbl_trace_method_object) { |
return (TRUE); |
} |
if (name && |
(acpi_gbl_trace_method_name && |
strcmp(acpi_gbl_trace_method_name, name))) { |
return (FALSE); |
} |
if ((acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) && |
!acpi_gbl_trace_method_name) { |
return (FALSE); |
} |
return (TRUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_get_trace_event_name |
* |
* PARAMETERS: type - Trace event type |
* |
* RETURN: Trace event name. |
* |
* DESCRIPTION: Used to obtain the full trace event name. |
* |
******************************************************************************/ |
#ifdef ACPI_DEBUG_OUTPUT |
static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type) |
{ |
switch (type) { |
case ACPI_TRACE_AML_METHOD: |
return "Method"; |
case ACPI_TRACE_AML_OPCODE: |
return "Opcode"; |
case ACPI_TRACE_AML_REGION: |
return "Region"; |
default: |
return ""; |
} |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_trace_point |
* |
* PARAMETERS: type - Trace event type |
* begin - TRUE if before execution |
* aml - Executed AML address |
* pathname - Object path |
* |
* RETURN: None |
* |
* DESCRIPTION: Internal interpreter execution trace. |
* |
******************************************************************************/ |
void |
acpi_ex_trace_point(acpi_trace_event_type type, |
u8 begin, u8 *aml, char *pathname) |
{ |
ACPI_FUNCTION_NAME(ex_trace_point); |
if (pathname) { |
ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, |
"%s %s [0x%p:%s] execution.\n", |
acpi_ex_get_trace_event_name(type), |
begin ? "Begin" : "End", aml, pathname)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, |
"%s %s [0x%p] execution.\n", |
acpi_ex_get_trace_event_name(type), |
begin ? "Begin" : "End", aml)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_start_trace_method |
* |
* PARAMETERS: method_node - Node of the method |
* obj_desc - The method object |
* walk_state - current state, NULL if not yet executing |
* a method. |
* |
* RETURN: None |
* |
* DESCRIPTION: Start control method execution trace |
* |
******************************************************************************/ |
void |
acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
char *pathname = NULL; |
u8 enabled = FALSE; |
ACPI_FUNCTION_NAME(ex_start_trace_method); |
if (method_node) { |
pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
enabled = acpi_ex_interpreter_trace_enabled(pathname); |
if (enabled && !acpi_gbl_trace_method_object) { |
acpi_gbl_trace_method_object = obj_desc; |
acpi_gbl_original_dbg_level = acpi_dbg_level; |
acpi_gbl_original_dbg_layer = acpi_dbg_layer; |
acpi_dbg_level = ACPI_TRACE_LEVEL_ALL; |
acpi_dbg_layer = ACPI_TRACE_LAYER_ALL; |
if (acpi_gbl_trace_dbg_level) { |
acpi_dbg_level = acpi_gbl_trace_dbg_level; |
} |
if (acpi_gbl_trace_dbg_layer) { |
acpi_dbg_layer = acpi_gbl_trace_dbg_layer; |
} |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
exit: |
if (enabled) { |
ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE, |
obj_desc ? obj_desc->method.aml_start : NULL, |
pathname); |
} |
if (pathname) { |
ACPI_FREE(pathname); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_stop_trace_method |
* |
* PARAMETERS: method_node - Node of the method |
* obj_desc - The method object |
* walk_state - current state, NULL if not yet executing |
* a method. |
* |
* RETURN: None |
* |
* DESCRIPTION: Stop control method execution trace |
* |
******************************************************************************/ |
void |
acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
char *pathname = NULL; |
u8 enabled; |
ACPI_FUNCTION_NAME(ex_stop_trace_method); |
if (method_node) { |
pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
goto exit_path; |
} |
enabled = acpi_ex_interpreter_trace_enabled(NULL); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
if (enabled) { |
ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE, |
obj_desc ? obj_desc->method.aml_start : NULL, |
pathname); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
goto exit_path; |
} |
/* Check whether the tracer should be stopped */ |
if (acpi_gbl_trace_method_object == obj_desc) { |
/* Disable further tracing if type is one-shot */ |
if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) { |
acpi_gbl_trace_method_name = NULL; |
} |
acpi_dbg_level = acpi_gbl_original_dbg_level; |
acpi_dbg_layer = acpi_gbl_original_dbg_layer; |
acpi_gbl_trace_method_object = NULL; |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
exit_path: |
if (pathname) { |
ACPI_FREE(pathname); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_start_trace_opcode |
* |
* PARAMETERS: op - The parser opcode object |
* walk_state - current state, NULL if not yet executing |
* a method. |
* |
* RETURN: None |
* |
* DESCRIPTION: Start opcode execution trace |
* |
******************************************************************************/ |
void |
acpi_ex_start_trace_opcode(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state) |
{ |
ACPI_FUNCTION_NAME(ex_start_trace_opcode); |
if (acpi_ex_interpreter_trace_enabled(NULL) && |
(acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { |
ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, |
op->common.aml, op->common.aml_op_name); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_stop_trace_opcode |
* |
* PARAMETERS: op - The parser opcode object |
* walk_state - current state, NULL if not yet executing |
* a method. |
* |
* RETURN: None |
* |
* DESCRIPTION: Stop opcode execution trace |
* |
******************************************************************************/ |
void |
acpi_ex_stop_trace_opcode(union acpi_parse_object *op, |
struct acpi_walk_state *walk_state) |
{ |
ACPI_FUNCTION_NAME(ex_stop_trace_opcode); |
if (acpi_ex_interpreter_trace_enabled(NULL) && |
(acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { |
ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, |
op->common.aml, op->common.aml_op_name); |
} |
} |
/drivers/acpi/acpica/exdump.c |
---|
0,0 → 1,1209 |
/****************************************************************************** |
* |
* Module Name: exdump - Interpreter debug output routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exdump") |
/* |
* The following routines are used for debug output only |
*/ |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
/* Local prototypes */ |
static void acpi_ex_out_string(char *title, char *value); |
static void acpi_ex_out_pointer(char *title, void *value); |
static void |
acpi_ex_dump_object(union acpi_operand_object *obj_desc, |
struct acpi_exdump_info *info); |
static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc); |
static void |
acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, |
u32 level, u32 index); |
/******************************************************************************* |
* |
* Object Descriptor info tables |
* |
* Note: The first table entry must be an INIT opcode and must contain |
* the table length (number of table entries) |
* |
******************************************************************************/ |
static struct acpi_exdump_info acpi_ex_dump_integer[2] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_integer), NULL}, |
{ACPI_EXD_UINT64, ACPI_EXD_OFFSET(integer.value), "Value"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_string[4] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_string), NULL}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(string.length), "Length"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(string.pointer), "Pointer"}, |
{ACPI_EXD_STRING, 0, NULL} |
}; |
static struct acpi_exdump_info acpi_ex_dump_buffer[5] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(buffer.node), "Parent Node"}, |
{ACPI_EXD_BUFFER, 0, NULL} |
}; |
static struct acpi_exdump_info acpi_ex_dump_package[6] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_package), NULL}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(package.node), "Parent Node"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(package.flags), "Flags"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(package.count), "Elements"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(package.elements), "Element List"}, |
{ACPI_EXD_PACKAGE, 0, NULL} |
}; |
static struct acpi_exdump_info acpi_ex_dump_device[4] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]), |
"System Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]), |
"Device Notify"}, |
{ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(device.handler), "Handler"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_event[2] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_event), NULL}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_method[9] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.info_flags), "Info Flags"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), |
"Parameter Count"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.thread_count), "Thread Count"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(method.aml_length), "Aml Length"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_mutex[6] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.original_sync_level), |
"Original Sync Level"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"}, |
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth), |
"Acquire Depth"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_region[8] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region), NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.space_id), "Space Id"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.flags), "Flags"}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(region.node), "Parent Node"}, |
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(region.address), "Address"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(region.length), "Length"}, |
{ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(region.handler), "Handler"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(region.next), "Next"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_power[6] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_power), NULL}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.system_level), |
"System Level"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.resource_order), |
"Resource Order"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[0]), |
"System Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]), |
"Device Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.handler), "Handler"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_processor[7] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"}, |
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[0]), |
"System Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[1]), |
"Device Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.handler), "Handler"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_thermal[4] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_thermal), NULL}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[0]), |
"System Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[1]), |
"Device Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.handler), "Handler"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_buffer_field[3] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer_field), NULL}, |
{ACPI_EXD_FIELD, 0, NULL}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer_field.buffer_obj), |
"Buffer Object"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_region_field[5] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region_field), NULL}, |
{ACPI_EXD_FIELD, 0, NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(field.access_length), "AccessLength"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.region_obj), "Region Object"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.resource_buffer), |
"ResourceBuffer"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_bank_field[5] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_bank_field), NULL}, |
{ACPI_EXD_FIELD, 0, NULL}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(bank_field.value), "Value"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(bank_field.region_obj), |
"Region Object"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(bank_field.bank_obj), "Bank Object"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_index_field[5] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_bank_field), NULL}, |
{ACPI_EXD_FIELD, 0, NULL}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(index_field.value), "Value"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(index_field.index_obj), |
"Index Object"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(index_field.data_obj), "Data Object"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_reference[9] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_reference), NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.class), "Class"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.target_type), "Target Type"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.value), "Value"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.object), "Object Desc"}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(reference.node), "Node"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.index_pointer), |
"Index Pointer"}, |
{ACPI_EXD_REFERENCE, 0, NULL} |
}; |
static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_address_handler), |
NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(address_space.space_id), "Space Id"}, |
{ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(address_space.next), "Next"}, |
{ACPI_EXD_RGN_LIST, ACPI_EXD_OFFSET(address_space.region_list), |
"Region List"}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(address_space.node), "Node"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_notify[7] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(notify.node), "Node"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(notify.handler_type), "Handler Type"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.handler), "Handler"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[0]), |
"Next System Notify"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[1]), "Next Device Notify"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_extra[6] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_extra), NULL}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.method_REG), "_REG Method"}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(extra.scope_node), "Scope Node"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.region_context), |
"Region Context"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.aml_start), "Aml Start"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(extra.aml_length), "Aml Length"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_data[3] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_data), NULL}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.handler), "Handler"}, |
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.pointer), "Raw Data"} |
}; |
/* Miscellaneous tables */ |
static struct acpi_exdump_info acpi_ex_dump_common[5] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_common), NULL}, |
{ACPI_EXD_TYPE, 0, NULL}, |
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(common.reference_count), |
"Reference Count"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common.flags), "Flags"}, |
{ACPI_EXD_LIST, ACPI_EXD_OFFSET(common.next_object), "Object List"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_field_common[7] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_field_common), NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common_field.field_flags), |
"Field Flags"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common_field.access_byte_width), |
"Access Byte Width"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(common_field.bit_length), |
"Bit Length"}, |
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common_field.start_field_bit_offset), |
"Field Bit Offset"}, |
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(common_field.base_byte_offset), |
"Base Byte Offset"}, |
{ACPI_EXD_NODE, ACPI_EXD_OFFSET(common_field.node), "Parent Node"} |
}; |
static struct acpi_exdump_info acpi_ex_dump_node[7] = { |
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL}, |
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"}, |
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"}, |
{ACPI_EXD_LIST, ACPI_EXD_NSOFFSET(object), "Object List"}, |
{ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(parent), "Parent"}, |
{ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(child), "Child"}, |
{ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(peer), "Peer"} |
}; |
/* Dispatch table, indexed by object type */ |
static struct acpi_exdump_info *acpi_ex_dump_info[] = { |
NULL, |
acpi_ex_dump_integer, |
acpi_ex_dump_string, |
acpi_ex_dump_buffer, |
acpi_ex_dump_package, |
NULL, |
acpi_ex_dump_device, |
acpi_ex_dump_event, |
acpi_ex_dump_method, |
acpi_ex_dump_mutex, |
acpi_ex_dump_region, |
acpi_ex_dump_power, |
acpi_ex_dump_processor, |
acpi_ex_dump_thermal, |
acpi_ex_dump_buffer_field, |
NULL, |
NULL, |
acpi_ex_dump_region_field, |
acpi_ex_dump_bank_field, |
acpi_ex_dump_index_field, |
acpi_ex_dump_reference, |
NULL, |
NULL, |
acpi_ex_dump_notify, |
acpi_ex_dump_address_handler, |
NULL, |
NULL, |
NULL, |
acpi_ex_dump_extra, |
acpi_ex_dump_data |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_dump_object |
* |
* PARAMETERS: obj_desc - Descriptor to dump |
* info - Info table corresponding to this object |
* type |
* |
* RETURN: None |
* |
* DESCRIPTION: Walk the info table for this object |
* |
******************************************************************************/ |
static void |
acpi_ex_dump_object(union acpi_operand_object *obj_desc, |
struct acpi_exdump_info *info) |
{ |
u8 *target; |
char *name; |
const char *reference_name; |
u8 count; |
union acpi_operand_object *start; |
union acpi_operand_object *data = NULL; |
union acpi_operand_object *next; |
struct acpi_namespace_node *node; |
if (!info) { |
acpi_os_printf |
("ExDumpObject: Display not implemented for object type %s\n", |
acpi_ut_get_object_type_name(obj_desc)); |
return; |
} |
/* First table entry must contain the table length (# of table entries) */ |
count = info->offset; |
while (count) { |
target = ACPI_ADD_PTR(u8, obj_desc, info->offset); |
name = info->name; |
switch (info->opcode) { |
case ACPI_EXD_INIT: |
break; |
case ACPI_EXD_TYPE: |
acpi_os_printf("%20s : %2.2X [%s]\n", "Type", |
obj_desc->common.type, |
acpi_ut_get_object_type_name(obj_desc)); |
break; |
case ACPI_EXD_UINT8: |
acpi_os_printf("%20s : %2.2X\n", name, *target); |
break; |
case ACPI_EXD_UINT16: |
acpi_os_printf("%20s : %4.4X\n", name, |
ACPI_GET16(target)); |
break; |
case ACPI_EXD_UINT32: |
acpi_os_printf("%20s : %8.8X\n", name, |
ACPI_GET32(target)); |
break; |
case ACPI_EXD_UINT64: |
acpi_os_printf("%20s : %8.8X%8.8X\n", "Value", |
ACPI_FORMAT_UINT64(ACPI_GET64(target))); |
break; |
case ACPI_EXD_POINTER: |
case ACPI_EXD_ADDRESS: |
acpi_ex_out_pointer(name, |
*ACPI_CAST_PTR(void *, target)); |
break; |
case ACPI_EXD_STRING: |
acpi_ut_print_string(obj_desc->string.pointer, |
ACPI_UINT8_MAX); |
acpi_os_printf("\n"); |
break; |
case ACPI_EXD_BUFFER: |
ACPI_DUMP_BUFFER(obj_desc->buffer.pointer, |
obj_desc->buffer.length); |
break; |
case ACPI_EXD_PACKAGE: |
/* Dump the package contents */ |
acpi_os_printf("\nPackage Contents:\n"); |
acpi_ex_dump_package_obj(obj_desc, 0, 0); |
break; |
case ACPI_EXD_FIELD: |
acpi_ex_dump_object(obj_desc, |
acpi_ex_dump_field_common); |
break; |
case ACPI_EXD_REFERENCE: |
reference_name = acpi_ut_get_reference_name(obj_desc); |
acpi_ex_out_string("Class Name", |
ACPI_CAST_PTR(char, reference_name)); |
acpi_ex_dump_reference_obj(obj_desc); |
break; |
case ACPI_EXD_LIST: |
start = *ACPI_CAST_PTR(void *, target); |
next = start; |
acpi_os_printf("%20s : %p", name, next); |
if (next) { |
acpi_os_printf("(%s %2.2X)", |
acpi_ut_get_object_type_name |
(next), next->common.type); |
while (next->common.next_object) { |
if ((next->common.type == |
ACPI_TYPE_LOCAL_DATA) && !data) { |
data = next; |
} |
next = next->common.next_object; |
acpi_os_printf("->%p(%s %2.2X)", next, |
acpi_ut_get_object_type_name |
(next), |
next->common.type); |
if ((next == start) || (next == data)) { |
acpi_os_printf |
("\n**** Error: Object list appears to be circular linked"); |
break; |
} |
} |
} |
acpi_os_printf("\n"); |
break; |
case ACPI_EXD_HDLR_LIST: |
start = *ACPI_CAST_PTR(void *, target); |
next = start; |
acpi_os_printf("%20s : %p", name, next); |
if (next) { |
acpi_os_printf("(%s %2.2X)", |
acpi_ut_get_object_type_name |
(next), next->common.type); |
while (next->address_space.next) { |
if ((next->common.type == |
ACPI_TYPE_LOCAL_DATA) && !data) { |
data = next; |
} |
next = next->address_space.next; |
acpi_os_printf("->%p(%s %2.2X)", next, |
acpi_ut_get_object_type_name |
(next), |
next->common.type); |
if ((next == start) || (next == data)) { |
acpi_os_printf |
("\n**** Error: Handler list appears to be circular linked"); |
break; |
} |
} |
} |
acpi_os_printf("\n"); |
break; |
case ACPI_EXD_RGN_LIST: |
start = *ACPI_CAST_PTR(void *, target); |
next = start; |
acpi_os_printf("%20s : %p", name, next); |
if (next) { |
acpi_os_printf("(%s %2.2X)", |
acpi_ut_get_object_type_name |
(next), next->common.type); |
while (next->region.next) { |
if ((next->common.type == |
ACPI_TYPE_LOCAL_DATA) && !data) { |
data = next; |
} |
next = next->region.next; |
acpi_os_printf("->%p(%s %2.2X)", next, |
acpi_ut_get_object_type_name |
(next), |
next->common.type); |
if ((next == start) || (next == data)) { |
acpi_os_printf |
("\n**** Error: Region list appears to be circular linked"); |
break; |
} |
} |
} |
acpi_os_printf("\n"); |
break; |
case ACPI_EXD_NODE: |
node = |
*ACPI_CAST_PTR(struct acpi_namespace_node *, |
target); |
acpi_os_printf("%20s : %p", name, node); |
if (node) { |
acpi_os_printf(" [%4.4s]", node->name.ascii); |
} |
acpi_os_printf("\n"); |
break; |
default: |
acpi_os_printf("**** Invalid table opcode [%X] ****\n", |
info->opcode); |
return; |
} |
info++; |
count--; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_dump_operand |
* |
* PARAMETERS: *obj_desc - Pointer to entry to be dumped |
* depth - Current nesting depth |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump an operand object |
* |
******************************************************************************/ |
void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) |
{ |
u32 length; |
u32 index; |
ACPI_FUNCTION_NAME(ex_dump_operand) |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_EXEC, _COMPONENT)) { |
return; |
} |
if (!obj_desc) { |
/* This could be a null element of a package */ |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n")); |
return; |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_NAMED) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p Namespace Node: ", |
obj_desc)); |
ACPI_DUMP_ENTRY(obj_desc, ACPI_LV_EXEC); |
return; |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"%p is not a node or operand object: [%s]\n", |
obj_desc, |
acpi_ut_get_descriptor_name(obj_desc))); |
ACPI_DUMP_BUFFER(obj_desc, sizeof(union acpi_operand_object)); |
return; |
} |
/* obj_desc is a valid object */ |
if (depth > 0) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%*s[%u] %p ", |
depth, " ", depth, obj_desc)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p ", obj_desc)); |
} |
/* Decode object type */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_LOCAL_REFERENCE: |
acpi_os_printf("Reference: [%s] ", |
acpi_ut_get_reference_name(obj_desc)); |
switch (obj_desc->reference.class) { |
case ACPI_REFCLASS_DEBUG: |
acpi_os_printf("\n"); |
break; |
case ACPI_REFCLASS_INDEX: |
acpi_os_printf("%p\n", obj_desc->reference.object); |
break; |
case ACPI_REFCLASS_TABLE: |
acpi_os_printf("Table Index %X\n", |
obj_desc->reference.value); |
break; |
case ACPI_REFCLASS_REFOF: |
acpi_os_printf("%p [%s]\n", obj_desc->reference.object, |
acpi_ut_get_type_name(((union |
acpi_operand_object |
*) |
obj_desc-> |
reference. |
object)->common. |
type)); |
break; |
case ACPI_REFCLASS_NAME: |
acpi_os_printf("- [%4.4s]\n", |
obj_desc->reference.node->name.ascii); |
break; |
case ACPI_REFCLASS_ARG: |
case ACPI_REFCLASS_LOCAL: |
acpi_os_printf("%X\n", obj_desc->reference.value); |
break; |
default: /* Unknown reference class */ |
acpi_os_printf("%2.2X\n", obj_desc->reference.class); |
break; |
} |
break; |
case ACPI_TYPE_BUFFER: |
acpi_os_printf("Buffer length %.2X @ %p\n", |
obj_desc->buffer.length, |
obj_desc->buffer.pointer); |
/* Debug only -- dump the buffer contents */ |
if (obj_desc->buffer.pointer) { |
length = obj_desc->buffer.length; |
if (length > 128) { |
length = 128; |
} |
acpi_os_printf |
("Buffer Contents: (displaying length 0x%.2X)\n", |
length); |
ACPI_DUMP_BUFFER(obj_desc->buffer.pointer, length); |
} |
break; |
case ACPI_TYPE_INTEGER: |
acpi_os_printf("Integer %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(obj_desc->integer.value)); |
break; |
case ACPI_TYPE_PACKAGE: |
acpi_os_printf("Package [Len %X] ElementArray %p\n", |
obj_desc->package.count, |
obj_desc->package.elements); |
/* |
* If elements exist, package element pointer is valid, |
* and debug_level exceeds 1, dump package's elements. |
*/ |
if (obj_desc->package.count && |
obj_desc->package.elements && acpi_dbg_level > 1) { |
for (index = 0; index < obj_desc->package.count; |
index++) { |
acpi_ex_dump_operand(obj_desc->package. |
elements[index], |
depth + 1); |
} |
} |
break; |
case ACPI_TYPE_REGION: |
acpi_os_printf("Region %s (%X)", |
acpi_ut_get_region_name(obj_desc->region. |
space_id), |
obj_desc->region.space_id); |
/* |
* If the address and length have not been evaluated, |
* don't print them. |
*/ |
if (!(obj_desc->region.flags & AOPOBJ_DATA_VALID)) { |
acpi_os_printf("\n"); |
} else { |
acpi_os_printf(" base %8.8X%8.8X Length %X\n", |
ACPI_FORMAT_UINT64(obj_desc->region. |
address), |
obj_desc->region.length); |
} |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf("String length %X @ %p ", |
obj_desc->string.length, |
obj_desc->string.pointer); |
acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX); |
acpi_os_printf("\n"); |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
acpi_os_printf("BankField\n"); |
break; |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
acpi_os_printf |
("RegionField: Bits=%X AccWidth=%X Lock=%X Update=%X at " |
"byte=%X bit=%X of below:\n", obj_desc->field.bit_length, |
obj_desc->field.access_byte_width, |
obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK, |
obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK, |
obj_desc->field.base_byte_offset, |
obj_desc->field.start_field_bit_offset); |
acpi_ex_dump_operand(obj_desc->field.region_obj, depth + 1); |
break; |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
acpi_os_printf("IndexField\n"); |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
acpi_os_printf("BufferField: %X bits at byte %X bit %X of\n", |
obj_desc->buffer_field.bit_length, |
obj_desc->buffer_field.base_byte_offset, |
obj_desc->buffer_field.start_field_bit_offset); |
if (!obj_desc->buffer_field.buffer_obj) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "*NULL*\n")); |
} else if ((obj_desc->buffer_field.buffer_obj)->common.type != |
ACPI_TYPE_BUFFER) { |
acpi_os_printf("*not a Buffer*\n"); |
} else { |
acpi_ex_dump_operand(obj_desc->buffer_field.buffer_obj, |
depth + 1); |
} |
break; |
case ACPI_TYPE_EVENT: |
acpi_os_printf("Event\n"); |
break; |
case ACPI_TYPE_METHOD: |
acpi_os_printf("Method(%X) @ %p:%X\n", |
obj_desc->method.param_count, |
obj_desc->method.aml_start, |
obj_desc->method.aml_length); |
break; |
case ACPI_TYPE_MUTEX: |
acpi_os_printf("Mutex\n"); |
break; |
case ACPI_TYPE_DEVICE: |
acpi_os_printf("Device\n"); |
break; |
case ACPI_TYPE_POWER: |
acpi_os_printf("Power\n"); |
break; |
case ACPI_TYPE_PROCESSOR: |
acpi_os_printf("Processor\n"); |
break; |
case ACPI_TYPE_THERMAL: |
acpi_os_printf("Thermal\n"); |
break; |
default: |
/* Unknown Type */ |
acpi_os_printf("Unknown Type %X\n", obj_desc->common.type); |
break; |
} |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_dump_operands |
* |
* PARAMETERS: operands - A list of Operand objects |
* opcode_name - AML opcode name |
* num_operands - Operand count for this opcode |
* |
* DESCRIPTION: Dump the operands associated with the opcode |
* |
******************************************************************************/ |
void |
acpi_ex_dump_operands(union acpi_operand_object **operands, |
const char *opcode_name, u32 num_operands) |
{ |
ACPI_FUNCTION_NAME(ex_dump_operands); |
if (!opcode_name) { |
opcode_name = "UNKNOWN"; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"**** Start operand dump for opcode [%s], %u operands\n", |
opcode_name, num_operands)); |
if (num_operands == 0) { |
num_operands = 1; |
} |
/* Dump the individual operands */ |
while (num_operands) { |
acpi_ex_dump_operand(*operands, 0); |
operands++; |
num_operands--; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"**** End operand dump for [%s]\n", opcode_name)); |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_out* functions |
* |
* PARAMETERS: title - Descriptive text |
* value - Value to be displayed |
* |
* DESCRIPTION: Object dump output formatting functions. These functions |
* reduce the number of format strings required and keeps them |
* all in one place for easy modification. |
* |
******************************************************************************/ |
static void acpi_ex_out_string(char *title, char *value) |
{ |
acpi_os_printf("%20s : %s\n", title, value); |
} |
static void acpi_ex_out_pointer(char *title, void *value) |
{ |
acpi_os_printf("%20s : %p\n", title, value); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_dump_namespace_node |
* |
* PARAMETERS: node - Descriptor to dump |
* flags - Force display if TRUE |
* |
* DESCRIPTION: Dumps the members of the given.Node |
* |
******************************************************************************/ |
void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags) |
{ |
ACPI_FUNCTION_ENTRY(); |
if (!flags) { |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_OBJECTS, _COMPONENT)) { |
return; |
} |
} |
acpi_os_printf("%20s : %4.4s\n", "Name", acpi_ut_get_node_name(node)); |
acpi_os_printf("%20s : %2.2X [%s]\n", "Type", |
node->type, acpi_ut_get_type_name(node->type)); |
acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node), |
acpi_ex_dump_node); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_dump_reference_obj |
* |
* PARAMETERS: object - Descriptor to dump |
* |
* DESCRIPTION: Dumps a reference object |
* |
******************************************************************************/ |
static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) |
{ |
struct acpi_buffer ret_buf; |
acpi_status status; |
ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
if (obj_desc->reference.class == ACPI_REFCLASS_NAME) { |
acpi_os_printf(" %p ", obj_desc->reference.node); |
status = acpi_ns_handle_to_pathname(obj_desc->reference.node, |
&ret_buf, TRUE); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf(" Could not convert name to pathname\n"); |
} else { |
acpi_os_printf("%s\n", (char *)ret_buf.pointer); |
ACPI_FREE(ret_buf.pointer); |
} |
} else if (obj_desc->reference.object) { |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == |
ACPI_DESC_TYPE_OPERAND) { |
acpi_os_printf("%22s %p", "Target :", |
obj_desc->reference.object); |
if (obj_desc->reference.class == ACPI_REFCLASS_TABLE) { |
acpi_os_printf(" Table Index: %X\n", |
obj_desc->reference.value); |
} else { |
acpi_os_printf(" [%s]\n", |
acpi_ut_get_type_name(((union |
acpi_operand_object |
*) |
obj_desc-> |
reference. |
object)-> |
common. |
type)); |
} |
} else { |
acpi_os_printf(" Target: %p\n", |
obj_desc->reference.object); |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_dump_package_obj |
* |
* PARAMETERS: obj_desc - Descriptor to dump |
* level - Indentation Level |
* index - Package index for this object |
* |
* DESCRIPTION: Dumps the elements of the package |
* |
******************************************************************************/ |
static void |
acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, |
u32 level, u32 index) |
{ |
u32 i; |
/* Indentation and index output */ |
if (level > 0) { |
for (i = 0; i < level; i++) { |
acpi_os_printf(" "); |
} |
acpi_os_printf("[%.2d] ", index); |
} |
acpi_os_printf("%p ", obj_desc); |
/* Null package elements are allowed */ |
if (!obj_desc) { |
acpi_os_printf("[Null Object]\n"); |
return; |
} |
/* Packages may only contain a few object types */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
acpi_os_printf("[Integer] = %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(obj_desc->integer.value)); |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf("[String] Value: "); |
acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX); |
acpi_os_printf("\n"); |
break; |
case ACPI_TYPE_BUFFER: |
acpi_os_printf("[Buffer] Length %.2X = ", |
obj_desc->buffer.length); |
if (obj_desc->buffer.length) { |
acpi_ut_debug_dump_buffer(ACPI_CAST_PTR |
(u8, |
obj_desc->buffer.pointer), |
obj_desc->buffer.length, |
DB_DWORD_DISPLAY, _COMPONENT); |
} else { |
acpi_os_printf("\n"); |
} |
break; |
case ACPI_TYPE_PACKAGE: |
acpi_os_printf("[Package] Contains %u Elements:\n", |
obj_desc->package.count); |
for (i = 0; i < obj_desc->package.count; i++) { |
acpi_ex_dump_package_obj(obj_desc->package.elements[i], |
level + 1, i); |
} |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
acpi_os_printf("[Object Reference] Type [%s] %2.2X", |
acpi_ut_get_reference_name(obj_desc), |
obj_desc->reference.class); |
acpi_ex_dump_reference_obj(obj_desc); |
break; |
default: |
acpi_os_printf("[Unknown Type] %X\n", obj_desc->common.type); |
break; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_dump_object_descriptor |
* |
* PARAMETERS: obj_desc - Descriptor to dump |
* flags - Force display if TRUE |
* |
* DESCRIPTION: Dumps the members of the object descriptor given. |
* |
******************************************************************************/ |
void |
acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) |
{ |
ACPI_FUNCTION_TRACE(ex_dump_object_descriptor); |
if (!obj_desc) { |
return_VOID; |
} |
if (!flags) { |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_OBJECTS, _COMPONENT)) { |
return_VOID; |
} |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_NAMED) { |
acpi_ex_dump_namespace_node((struct acpi_namespace_node *) |
obj_desc, flags); |
acpi_os_printf("\nAttached Object (%p):\n", |
((struct acpi_namespace_node *)obj_desc)-> |
object); |
obj_desc = ((struct acpi_namespace_node *)obj_desc)->object; |
goto dump_object; |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { |
acpi_os_printf("%p is not an ACPI operand object: [%s]\n", |
obj_desc, acpi_ut_get_descriptor_name(obj_desc)); |
return_VOID; |
} |
/* Validate the object type */ |
if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) { |
acpi_os_printf("Not a known object type: %2.2X\n", |
obj_desc->common.type); |
return_VOID; |
} |
dump_object: |
/* Common Fields */ |
acpi_ex_dump_object(obj_desc, acpi_ex_dump_common); |
/* Object-specific fields */ |
acpi_ex_dump_object(obj_desc, acpi_ex_dump_info[obj_desc->common.type]); |
if (obj_desc->common.type == ACPI_TYPE_REGION) { |
obj_desc = obj_desc->common.next_object; |
if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) { |
acpi_os_printf |
("Secondary object is not a known object type: %2.2X\n", |
obj_desc->common.type); |
return_VOID; |
} |
acpi_os_printf("\nExtra attached Object (%p):\n", obj_desc); |
acpi_ex_dump_object(obj_desc, |
acpi_ex_dump_info[obj_desc->common.type]); |
} |
return_VOID; |
} |
#endif |
/drivers/acpi/acpica/exfield.c |
---|
0,0 → 1,536 |
/****************************************************************************** |
* |
* Module Name: exfield - ACPI AML (p-code) execution - field manipulation |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exfield") |
/* Local prototypes */ |
static u32 |
acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_get_serial_access_length |
* |
* PARAMETERS: accessor_type - The type of the protocol indicated by region |
* field access attributes |
* access_length - The access length of the region field |
* |
* RETURN: Decoded access length |
* |
* DESCRIPTION: This routine returns the length of the generic_serial_bus |
* protocol bytes |
* |
******************************************************************************/ |
static u32 |
acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length) |
{ |
u32 length; |
switch (accessor_type) { |
case AML_FIELD_ATTRIB_QUICK: |
length = 0; |
break; |
case AML_FIELD_ATTRIB_SEND_RCV: |
case AML_FIELD_ATTRIB_BYTE: |
length = 1; |
break; |
case AML_FIELD_ATTRIB_WORD: |
case AML_FIELD_ATTRIB_WORD_CALL: |
length = 2; |
break; |
case AML_FIELD_ATTRIB_MULTIBYTE: |
case AML_FIELD_ATTRIB_RAW_BYTES: |
case AML_FIELD_ATTRIB_RAW_PROCESS: |
length = access_length; |
break; |
case AML_FIELD_ATTRIB_BLOCK: |
case AML_FIELD_ATTRIB_BLOCK_CALL: |
default: |
length = ACPI_GSBUS_BUFFER_SIZE - 2; |
break; |
} |
return (length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_read_data_from_field |
* |
* PARAMETERS: walk_state - Current execution state |
* obj_desc - The named field |
* ret_buffer_desc - Where the return data object is stored |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read from a named field. Returns either an Integer or a |
* Buffer, depending on the size of the field. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, |
union acpi_operand_object *obj_desc, |
union acpi_operand_object **ret_buffer_desc) |
{ |
acpi_status status; |
union acpi_operand_object *buffer_desc; |
acpi_size length; |
void *buffer; |
u32 function; |
u16 accessor_type; |
ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); |
/* Parameter validation */ |
if (!obj_desc) { |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
if (!ret_buffer_desc) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { |
/* |
* If the buffer_field arguments have not been previously evaluated, |
* evaluate them now and save the results. |
*/ |
if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { |
status = acpi_ds_get_buffer_field_arguments(obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && |
(obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_SMBUS |
|| obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_GSBUS |
|| obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_IPMI)) { |
/* |
* This is an SMBus, GSBus or IPMI read. We must create a buffer to hold |
* the data and then directly access the region handler. |
* |
* Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function |
*/ |
if (obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_SMBUS) { |
length = ACPI_SMBUS_BUFFER_SIZE; |
function = |
ACPI_READ | (obj_desc->field.attribute << 16); |
} else if (obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_GSBUS) { |
accessor_type = obj_desc->field.attribute; |
length = acpi_ex_get_serial_access_length(accessor_type, |
obj_desc-> |
field. |
access_length); |
/* |
* Add additional 2 bytes for the generic_serial_bus data buffer: |
* |
* Status; (Byte 0 of the data buffer) |
* Length; (Byte 1 of the data buffer) |
* Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) |
*/ |
length += 2; |
function = ACPI_READ | (accessor_type << 16); |
} else { /* IPMI */ |
length = ACPI_IPMI_BUFFER_SIZE; |
function = ACPI_READ; |
} |
buffer_desc = acpi_ut_create_buffer_object(length); |
if (!buffer_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Lock entire transaction if requested */ |
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); |
/* Call the region handler for the read */ |
status = acpi_ex_access_region(obj_desc, 0, |
ACPI_CAST_PTR(u64, |
buffer_desc-> |
buffer.pointer), |
function); |
acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
goto exit; |
} |
/* |
* Allocate a buffer for the contents of the field. |
* |
* If the field is larger than the current integer width, create |
* a BUFFER to hold it. Otherwise, use an INTEGER. This allows |
* the use of arithmetic operators on the returned value if the |
* field size is equal or smaller than an Integer. |
* |
* Note: Field.length is in bits. |
*/ |
length = |
(acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); |
if (length > acpi_gbl_integer_byte_width) { |
/* Field is too large for an Integer, create a Buffer instead */ |
buffer_desc = acpi_ut_create_buffer_object(length); |
if (!buffer_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
buffer = buffer_desc->buffer.pointer; |
} else { |
/* Field will fit within an Integer (normal case) */ |
buffer_desc = acpi_ut_create_integer_object((u64) 0); |
if (!buffer_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
length = acpi_gbl_integer_byte_width; |
buffer = &buffer_desc->integer.value; |
} |
if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && |
(obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_GPIO)) { |
/* |
* For GPIO (general_purpose_io), the Address will be the bit offset |
* from the previous Connection() operator, making it effectively a |
* pin number index. The bit_length is the length of the field, which |
* is thus the number of pins. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"GPIO FieldRead [FROM]: Pin %u Bits %u\n", |
obj_desc->field.pin_number_index, |
obj_desc->field.bit_length)); |
/* Lock entire transaction if requested */ |
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); |
/* Perform the write */ |
status = acpi_ex_access_region(obj_desc, 0, |
(u64 *)buffer, ACPI_READ); |
acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(buffer_desc); |
} else { |
*ret_buffer_desc = buffer_desc; |
} |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", |
obj_desc, obj_desc->common.type, buffer, |
(u32) length)); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", |
obj_desc->common_field.bit_length, |
obj_desc->common_field.start_field_bit_offset, |
obj_desc->common_field.base_byte_offset)); |
/* Lock entire transaction if requested */ |
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); |
/* Read from the field */ |
status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); |
acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
exit: |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(buffer_desc); |
} else { |
*ret_buffer_desc = buffer_desc; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_write_data_to_field |
* |
* PARAMETERS: source_desc - Contains data to write |
* obj_desc - The named field |
* result_desc - Where the return value is returned, if any |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write to a named field |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, |
union acpi_operand_object *obj_desc, |
union acpi_operand_object **result_desc) |
{ |
acpi_status status; |
u32 length; |
void *buffer; |
union acpi_operand_object *buffer_desc; |
u32 function; |
u16 accessor_type; |
ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); |
/* Parameter validation */ |
if (!source_desc || !obj_desc) { |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { |
/* |
* If the buffer_field arguments have not been previously evaluated, |
* evaluate them now and save the results. |
*/ |
if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { |
status = acpi_ds_get_buffer_field_arguments(obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && |
(obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_SMBUS |
|| obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_GSBUS |
|| obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_IPMI)) { |
/* |
* This is an SMBus, GSBus or IPMI write. We will bypass the entire field |
* mechanism and handoff the buffer directly to the handler. For |
* these address spaces, the buffer is bi-directional; on a write, |
* return data is returned in the same buffer. |
* |
* Source must be a buffer of sufficient size: |
* ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. |
* |
* Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function |
*/ |
if (source_desc->common.type != ACPI_TYPE_BUFFER) { |
ACPI_ERROR((AE_INFO, |
"SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", |
acpi_ut_get_object_type_name(source_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
if (obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_SMBUS) { |
length = ACPI_SMBUS_BUFFER_SIZE; |
function = |
ACPI_WRITE | (obj_desc->field.attribute << 16); |
} else if (obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_GSBUS) { |
accessor_type = obj_desc->field.attribute; |
length = acpi_ex_get_serial_access_length(accessor_type, |
obj_desc-> |
field. |
access_length); |
/* |
* Add additional 2 bytes for the generic_serial_bus data buffer: |
* |
* Status; (Byte 0 of the data buffer) |
* Length; (Byte 1 of the data buffer) |
* Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) |
*/ |
length += 2; |
function = ACPI_WRITE | (accessor_type << 16); |
} else { /* IPMI */ |
length = ACPI_IPMI_BUFFER_SIZE; |
function = ACPI_WRITE; |
} |
if (source_desc->buffer.length < length) { |
ACPI_ERROR((AE_INFO, |
"SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", |
length, source_desc->buffer.length)); |
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); |
} |
/* Create the bi-directional buffer */ |
buffer_desc = acpi_ut_create_buffer_object(length); |
if (!buffer_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
buffer = buffer_desc->buffer.pointer; |
memcpy(buffer, source_desc->buffer.pointer, length); |
/* Lock entire transaction if requested */ |
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); |
/* |
* Perform the write (returns status and perhaps data in the |
* same buffer) |
*/ |
status = acpi_ex_access_region(obj_desc, 0, |
(u64 *) buffer, function); |
acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
*result_desc = buffer_desc; |
return_ACPI_STATUS(status); |
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && |
(obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_GPIO)) { |
/* |
* For GPIO (general_purpose_io), we will bypass the entire field |
* mechanism and handoff the bit address and bit width directly to |
* the handler. The Address will be the bit offset |
* from the previous Connection() operator, making it effectively a |
* pin number index. The bit_length is the length of the field, which |
* is thus the number of pins. |
*/ |
if (source_desc->common.type != ACPI_TYPE_INTEGER) { |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", |
acpi_ut_get_type_name(source_desc->common. |
type), |
source_desc->common.type, |
(u32)source_desc->integer.value, |
obj_desc->field.pin_number_index, |
obj_desc->field.bit_length)); |
buffer = &source_desc->integer.value; |
/* Lock entire transaction if requested */ |
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); |
/* Perform the write */ |
status = acpi_ex_access_region(obj_desc, 0, |
(u64 *)buffer, ACPI_WRITE); |
acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
return_ACPI_STATUS(status); |
} |
/* Get a pointer to the data to be written */ |
switch (source_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
buffer = &source_desc->integer.value; |
length = sizeof(source_desc->integer.value); |
break; |
case ACPI_TYPE_BUFFER: |
buffer = source_desc->buffer.pointer; |
length = source_desc->buffer.length; |
break; |
case ACPI_TYPE_STRING: |
buffer = source_desc->string.pointer; |
length = source_desc->string.length; |
break; |
default: |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", |
source_desc, |
acpi_ut_get_type_name(source_desc->common.type), |
source_desc->common.type, buffer, length)); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", |
obj_desc, |
acpi_ut_get_type_name(obj_desc->common.type), |
obj_desc->common.type, |
obj_desc->common_field.bit_length, |
obj_desc->common_field.start_field_bit_offset, |
obj_desc->common_field.base_byte_offset)); |
/* Lock entire transaction if requested */ |
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); |
/* Write to the field */ |
status = acpi_ex_insert_into_field(obj_desc, buffer, length); |
acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exfldio.c |
---|
0,0 → 1,1004 |
/****************************************************************************** |
* |
* Module Name: exfldio - Aml Field I/O |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#include "acevents.h" |
#include "acdispat.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exfldio") |
/* Local prototypes */ |
static acpi_status |
acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, |
u32 field_datum_byte_offset, u64 *value, u32 read_write); |
static u8 |
acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value); |
static acpi_status |
acpi_ex_setup_region(union acpi_operand_object *obj_desc, |
u32 field_datum_byte_offset); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_setup_region |
* |
* PARAMETERS: obj_desc - Field to be read or written |
* field_datum_byte_offset - Byte offset of this datum within the |
* parent field |
* |
* RETURN: Status |
* |
* DESCRIPTION: Common processing for acpi_ex_extract_from_field and |
* acpi_ex_insert_into_field. Initialize the Region if necessary and |
* validate the request. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_setup_region(union acpi_operand_object *obj_desc, |
u32 field_datum_byte_offset) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *rgn_desc; |
u8 space_id; |
ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset); |
rgn_desc = obj_desc->common_field.region_obj; |
/* We must have a valid region */ |
if (rgn_desc->common.type != ACPI_TYPE_REGION) { |
ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)", |
rgn_desc->common.type, |
acpi_ut_get_object_type_name(rgn_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
space_id = rgn_desc->region.space_id; |
/* Validate the Space ID */ |
if (!acpi_is_valid_space_id(space_id)) { |
ACPI_ERROR((AE_INFO, |
"Invalid/unknown Address Space ID: 0x%2.2X", |
space_id)); |
return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); |
} |
/* |
* If the Region Address and Length have not been previously evaluated, |
* evaluate them now and save the results. |
*/ |
if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) { |
status = acpi_ds_get_region_arguments(rgn_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* |
* Exit now for SMBus, GSBus or IPMI address space, it has a non-linear |
* address space and the request cannot be directly validated |
*/ |
if (space_id == ACPI_ADR_SPACE_SMBUS || |
space_id == ACPI_ADR_SPACE_GSBUS || |
space_id == ACPI_ADR_SPACE_IPMI) { |
/* SMBus or IPMI has a non-linear address space */ |
return_ACPI_STATUS(AE_OK); |
} |
#ifdef ACPI_UNDER_DEVELOPMENT |
/* |
* If the Field access is any_acc, we can now compute the optimal |
* access (because we know know the length of the parent region) |
*/ |
if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
#endif |
/* |
* Validate the request. The entire request from the byte offset for a |
* length of one field datum (access width) must fit within the region. |
* (Region length is specified in bytes) |
*/ |
if (rgn_desc->region.length < |
(obj_desc->common_field.base_byte_offset + field_datum_byte_offset + |
obj_desc->common_field.access_byte_width)) { |
if (acpi_gbl_enable_interpreter_slack) { |
/* |
* Slack mode only: We will go ahead and allow access to this |
* field if it is within the region length rounded up to the next |
* access width boundary. acpi_size cast for 64-bit compile. |
*/ |
if (ACPI_ROUND_UP(rgn_desc->region.length, |
obj_desc->common_field. |
access_byte_width) >= |
((acpi_size) obj_desc->common_field. |
base_byte_offset + |
obj_desc->common_field.access_byte_width + |
field_datum_byte_offset)) { |
return_ACPI_STATUS(AE_OK); |
} |
} |
if (rgn_desc->region.length < |
obj_desc->common_field.access_byte_width) { |
/* |
* This is the case where the access_type (acc_word, etc.) is wider |
* than the region itself. For example, a region of length one |
* byte, and a field with Dword access specified. |
*/ |
ACPI_ERROR((AE_INFO, |
"Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)", |
acpi_ut_get_node_name(obj_desc-> |
common_field.node), |
obj_desc->common_field.access_byte_width, |
acpi_ut_get_node_name(rgn_desc->region. |
node), |
rgn_desc->region.length)); |
} |
/* |
* Offset rounded up to next multiple of field width |
* exceeds region length, indicate an error |
*/ |
ACPI_ERROR((AE_INFO, |
"Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)", |
acpi_ut_get_node_name(obj_desc->common_field.node), |
obj_desc->common_field.base_byte_offset, |
field_datum_byte_offset, |
obj_desc->common_field.access_byte_width, |
acpi_ut_get_node_name(rgn_desc->region.node), |
rgn_desc->region.length)); |
return_ACPI_STATUS(AE_AML_REGION_LIMIT); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_access_region |
* |
* PARAMETERS: obj_desc - Field to be read |
* field_datum_byte_offset - Byte offset of this datum within the |
* parent field |
* value - Where to store value (must at least |
* 64 bits) |
* function - Read or Write flag plus other region- |
* dependent flags |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read or Write a single field datum to an Operation Region. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_access_region(union acpi_operand_object *obj_desc, |
u32 field_datum_byte_offset, u64 *value, u32 function) |
{ |
acpi_status status; |
union acpi_operand_object *rgn_desc; |
u32 region_offset; |
ACPI_FUNCTION_TRACE(ex_access_region); |
/* |
* Ensure that the region operands are fully evaluated and verify |
* the validity of the request |
*/ |
status = acpi_ex_setup_region(obj_desc, field_datum_byte_offset); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* The physical address of this field datum is: |
* |
* 1) The base of the region, plus |
* 2) The base offset of the field, plus |
* 3) The current offset into the field |
*/ |
rgn_desc = obj_desc->common_field.region_obj; |
region_offset = |
obj_desc->common_field.base_byte_offset + field_datum_byte_offset; |
if ((function & ACPI_IO_MASK) == ACPI_READ) { |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[READ]")); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[WRITE]")); |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD, |
" Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", |
acpi_ut_get_region_name(rgn_desc->region. |
space_id), |
rgn_desc->region.space_id, |
obj_desc->common_field.access_byte_width, |
obj_desc->common_field.base_byte_offset, |
field_datum_byte_offset, |
ACPI_FORMAT_UINT64(rgn_desc->region.address + |
region_offset))); |
/* Invoke the appropriate address_space/op_region handler */ |
status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc, |
function, region_offset, |
ACPI_MUL_8(obj_desc-> |
common_field. |
access_byte_width), |
value); |
if (ACPI_FAILURE(status)) { |
if (status == AE_NOT_IMPLEMENTED) { |
ACPI_ERROR((AE_INFO, |
"Region %s (ID=%u) not implemented", |
acpi_ut_get_region_name(rgn_desc->region. |
space_id), |
rgn_desc->region.space_id)); |
} else if (status == AE_NOT_EXIST) { |
ACPI_ERROR((AE_INFO, |
"Region %s (ID=%u) has no handler", |
acpi_ut_get_region_name(rgn_desc->region. |
space_id), |
rgn_desc->region.space_id)); |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_register_overflow |
* |
* PARAMETERS: obj_desc - Register(Field) to be written |
* value - Value to be stored |
* |
* RETURN: TRUE if value overflows the field, FALSE otherwise |
* |
* DESCRIPTION: Check if a value is out of range of the field being written. |
* Used to check if the values written to Index and Bank registers |
* are out of range. Normally, the value is simply truncated |
* to fit the field, but this case is most likely a serious |
* coding error in the ASL. |
* |
******************************************************************************/ |
static u8 |
acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) |
{ |
if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) { |
/* |
* The field is large enough to hold the maximum integer, so we can |
* never overflow it. |
*/ |
return (FALSE); |
} |
if (value >= ((u64) 1 << obj_desc->common_field.bit_length)) { |
/* |
* The Value is larger than the maximum value that can fit into |
* the register. |
*/ |
ACPI_ERROR((AE_INFO, |
"Index value 0x%8.8X%8.8X overflows field width 0x%X", |
ACPI_FORMAT_UINT64(value), |
obj_desc->common_field.bit_length)); |
return (TRUE); |
} |
/* The Value will fit into the field with no truncation */ |
return (FALSE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_field_datum_io |
* |
* PARAMETERS: obj_desc - Field to be read |
* field_datum_byte_offset - Byte offset of this datum within the |
* parent field |
* value - Where to store value (must be 64 bits) |
* read_write - Read or Write flag |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read or Write a single datum of a field. The field_type is |
* demultiplexed here to handle the different types of fields |
* (buffer_field, region_field, index_field, bank_field) |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, |
u32 field_datum_byte_offset, u64 *value, u32 read_write) |
{ |
acpi_status status; |
u64 local_value; |
ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset); |
if (read_write == ACPI_READ) { |
if (!value) { |
local_value = 0; |
/* To support reads without saving return value */ |
value = &local_value; |
} |
/* Clear the entire return buffer first, [Very Important!] */ |
*value = 0; |
} |
/* |
* The four types of fields are: |
* |
* buffer_field - Read/write from/to a Buffer |
* region_field - Read/write from/to a Operation Region. |
* bank_field - Write to a Bank Register, then read/write from/to an |
* operation_region |
* index_field - Write to an Index Register, then read/write from/to a |
* Data Register |
*/ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_BUFFER_FIELD: |
/* |
* If the buffer_field arguments have not been previously evaluated, |
* evaluate them now and save the results. |
*/ |
if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { |
status = acpi_ds_get_buffer_field_arguments(obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
if (read_write == ACPI_READ) { |
/* |
* Copy the data from the source buffer. |
* Length is the field width in bytes. |
*/ |
memcpy(value, |
(obj_desc->buffer_field.buffer_obj)->buffer. |
pointer + |
obj_desc->buffer_field.base_byte_offset + |
field_datum_byte_offset, |
obj_desc->common_field.access_byte_width); |
} else { |
/* |
* Copy the data to the target buffer. |
* Length is the field width in bytes. |
*/ |
memcpy((obj_desc->buffer_field.buffer_obj)->buffer. |
pointer + |
obj_desc->buffer_field.base_byte_offset + |
field_datum_byte_offset, value, |
obj_desc->common_field.access_byte_width); |
} |
status = AE_OK; |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
/* |
* Ensure that the bank_value is not beyond the capacity of |
* the register |
*/ |
if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj, |
(u64) obj_desc->bank_field. |
value)) { |
return_ACPI_STATUS(AE_AML_REGISTER_LIMIT); |
} |
/* |
* For bank_fields, we must write the bank_value to the bank_register |
* (itself a region_field) before we can access the data. |
*/ |
status = |
acpi_ex_insert_into_field(obj_desc->bank_field.bank_obj, |
&obj_desc->bank_field.value, |
sizeof(obj_desc->bank_field. |
value)); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Now that the Bank has been selected, fall through to the |
* region_field case and write the datum to the Operation Region |
*/ |
/*lint -fallthrough */ |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
/* |
* For simple region_fields, we just directly access the owning |
* Operation Region. |
*/ |
status = |
acpi_ex_access_region(obj_desc, field_datum_byte_offset, |
value, read_write); |
break; |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
/* |
* Ensure that the index_value is not beyond the capacity of |
* the register |
*/ |
if (acpi_ex_register_overflow(obj_desc->index_field.index_obj, |
(u64) obj_desc->index_field. |
value)) { |
return_ACPI_STATUS(AE_AML_REGISTER_LIMIT); |
} |
/* Write the index value to the index_register (itself a region_field) */ |
field_datum_byte_offset += obj_desc->index_field.value; |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Write to Index Register: Value %8.8X\n", |
field_datum_byte_offset)); |
status = |
acpi_ex_insert_into_field(obj_desc->index_field.index_obj, |
&field_datum_byte_offset, |
sizeof(field_datum_byte_offset)); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (read_write == ACPI_READ) { |
/* Read the datum from the data_register */ |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Read from Data Register\n")); |
status = |
acpi_ex_extract_from_field(obj_desc->index_field. |
data_obj, value, |
sizeof(u64)); |
} else { |
/* Write the datum to the data_register */ |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Write to Data Register: Value %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(*value))); |
status = |
acpi_ex_insert_into_field(obj_desc->index_field. |
data_obj, value, |
sizeof(u64)); |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %u", |
obj_desc->common.type)); |
status = AE_AML_INTERNAL; |
break; |
} |
if (ACPI_SUCCESS(status)) { |
if (read_write == ACPI_READ) { |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Value Read %8.8X%8.8X, Width %u\n", |
ACPI_FORMAT_UINT64(*value), |
obj_desc->common_field. |
access_byte_width)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Value Written %8.8X%8.8X, Width %u\n", |
ACPI_FORMAT_UINT64(*value), |
obj_desc->common_field. |
access_byte_width)); |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_write_with_update_rule |
* |
* PARAMETERS: obj_desc - Field to be written |
* mask - bitmask within field datum |
* field_value - Value to write |
* field_datum_byte_offset - Offset of datum within field |
* |
* RETURN: Status |
* |
* DESCRIPTION: Apply the field update rule to a field write |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, |
u64 mask, |
u64 field_value, u32 field_datum_byte_offset) |
{ |
acpi_status status = AE_OK; |
u64 merged_value; |
u64 current_value; |
ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask); |
/* Start with the new bits */ |
merged_value = field_value; |
/* If the mask is all ones, we don't need to worry about the update rule */ |
if (mask != ACPI_UINT64_MAX) { |
/* Decode the update rule */ |
switch (obj_desc->common_field. |
field_flags & AML_FIELD_UPDATE_RULE_MASK) { |
case AML_FIELD_UPDATE_PRESERVE: |
/* |
* Check if update rule needs to be applied (not if mask is all |
* ones) The left shift drops the bits we want to ignore. |
*/ |
if ((~mask << (ACPI_MUL_8(sizeof(mask)) - |
ACPI_MUL_8(obj_desc->common_field. |
access_byte_width))) != 0) { |
/* |
* Read the current contents of the byte/word/dword containing |
* the field, and merge with the new field value. |
*/ |
status = |
acpi_ex_field_datum_io(obj_desc, |
field_datum_byte_offset, |
¤t_value, |
ACPI_READ); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
merged_value |= (current_value & ~mask); |
} |
break; |
case AML_FIELD_UPDATE_WRITE_AS_ONES: |
/* Set positions outside the field to all ones */ |
merged_value |= ~mask; |
break; |
case AML_FIELD_UPDATE_WRITE_AS_ZEROS: |
/* Set positions outside the field to all zeros */ |
merged_value &= mask; |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown UpdateRule value: 0x%X", |
(obj_desc->common_field. |
field_flags & |
AML_FIELD_UPDATE_RULE_MASK))); |
return_ACPI_STATUS(AE_AML_OPERAND_VALUE); |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(mask), |
field_datum_byte_offset, |
obj_desc->common_field.access_byte_width, |
ACPI_FORMAT_UINT64(field_value), |
ACPI_FORMAT_UINT64(merged_value))); |
/* Write the merged value */ |
status = acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset, |
&merged_value, ACPI_WRITE); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_extract_from_field |
* |
* PARAMETERS: obj_desc - Field to be read |
* buffer - Where to store the field data |
* buffer_length - Length of Buffer |
* |
* RETURN: Status |
* |
* DESCRIPTION: Retrieve the current value of the given field |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, |
void *buffer, u32 buffer_length) |
{ |
acpi_status status; |
u64 raw_datum; |
u64 merged_datum; |
u32 field_offset = 0; |
u32 buffer_offset = 0; |
u32 buffer_tail_bits; |
u32 datum_count; |
u32 field_datum_count; |
u32 access_bit_width; |
u32 i; |
ACPI_FUNCTION_TRACE(ex_extract_from_field); |
/* Validate target buffer and clear it */ |
if (buffer_length < |
ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) { |
ACPI_ERROR((AE_INFO, |
"Field size %u (bits) is too large for buffer (%u)", |
obj_desc->common_field.bit_length, buffer_length)); |
return_ACPI_STATUS(AE_BUFFER_OVERFLOW); |
} |
memset(buffer, 0, buffer_length); |
access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width); |
/* Handle the simple case here */ |
if ((obj_desc->common_field.start_field_bit_offset == 0) && |
(obj_desc->common_field.bit_length == access_bit_width)) { |
if (buffer_length >= sizeof(u64)) { |
status = |
acpi_ex_field_datum_io(obj_desc, 0, buffer, |
ACPI_READ); |
} else { |
/* Use raw_datum (u64) to handle buffers < 64 bits */ |
status = |
acpi_ex_field_datum_io(obj_desc, 0, &raw_datum, |
ACPI_READ); |
memcpy(buffer, &raw_datum, buffer_length); |
} |
return_ACPI_STATUS(status); |
} |
/* TBD: Move to common setup code */ |
/* Field algorithm is limited to sizeof(u64), truncate if needed */ |
if (obj_desc->common_field.access_byte_width > sizeof(u64)) { |
obj_desc->common_field.access_byte_width = sizeof(u64); |
access_bit_width = sizeof(u64) * 8; |
} |
/* Compute the number of datums (access width data items) */ |
datum_count = |
ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, |
access_bit_width); |
field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + |
obj_desc->common_field. |
start_field_bit_offset, |
access_bit_width); |
/* Priming read from the field */ |
status = |
acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum, |
ACPI_READ); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
merged_datum = |
raw_datum >> obj_desc->common_field.start_field_bit_offset; |
/* Read the rest of the field */ |
for (i = 1; i < field_datum_count; i++) { |
/* Get next input datum from the field */ |
field_offset += obj_desc->common_field.access_byte_width; |
status = acpi_ex_field_datum_io(obj_desc, field_offset, |
&raw_datum, ACPI_READ); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Merge with previous datum if necessary. |
* |
* Note: Before the shift, check if the shift value will be larger than |
* the integer size. If so, there is no need to perform the operation. |
* This avoids the differences in behavior between different compilers |
* concerning shift values larger than the target data width. |
*/ |
if (access_bit_width - |
obj_desc->common_field.start_field_bit_offset < |
ACPI_INTEGER_BIT_SIZE) { |
merged_datum |= |
raw_datum << (access_bit_width - |
obj_desc->common_field. |
start_field_bit_offset); |
} |
if (i == datum_count) { |
break; |
} |
/* Write merged datum to target buffer */ |
memcpy(((char *)buffer) + buffer_offset, &merged_datum, |
ACPI_MIN(obj_desc->common_field.access_byte_width, |
buffer_length - buffer_offset)); |
buffer_offset += obj_desc->common_field.access_byte_width; |
merged_datum = |
raw_datum >> obj_desc->common_field.start_field_bit_offset; |
} |
/* Mask off any extra bits in the last datum */ |
buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width; |
if (buffer_tail_bits) { |
merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits); |
} |
/* Write the last datum to the buffer */ |
memcpy(((char *)buffer) + buffer_offset, &merged_datum, |
ACPI_MIN(obj_desc->common_field.access_byte_width, |
buffer_length - buffer_offset)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_insert_into_field |
* |
* PARAMETERS: obj_desc - Field to be written |
* buffer - Data to be written |
* buffer_length - Length of Buffer |
* |
* RETURN: Status |
* |
* DESCRIPTION: Store the Buffer contents into the given field |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, |
void *buffer, u32 buffer_length) |
{ |
void *new_buffer; |
acpi_status status; |
u64 mask; |
u64 width_mask; |
u64 merged_datum; |
u64 raw_datum = 0; |
u32 field_offset = 0; |
u32 buffer_offset = 0; |
u32 buffer_tail_bits; |
u32 datum_count; |
u32 field_datum_count; |
u32 access_bit_width; |
u32 required_length; |
u32 i; |
ACPI_FUNCTION_TRACE(ex_insert_into_field); |
/* Validate input buffer */ |
new_buffer = NULL; |
required_length = |
ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); |
/* |
* We must have a buffer that is at least as long as the field |
* we are writing to. This is because individual fields are |
* indivisible and partial writes are not supported -- as per |
* the ACPI specification. |
*/ |
if (buffer_length < required_length) { |
/* We need to create a new buffer */ |
new_buffer = ACPI_ALLOCATE_ZEROED(required_length); |
if (!new_buffer) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* |
* Copy the original data to the new buffer, starting |
* at Byte zero. All unused (upper) bytes of the |
* buffer will be 0. |
*/ |
memcpy((char *)new_buffer, (char *)buffer, buffer_length); |
buffer = new_buffer; |
buffer_length = required_length; |
} |
/* TBD: Move to common setup code */ |
/* Algo is limited to sizeof(u64), so cut the access_byte_width */ |
if (obj_desc->common_field.access_byte_width > sizeof(u64)) { |
obj_desc->common_field.access_byte_width = sizeof(u64); |
} |
access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width); |
/* |
* Create the bitmasks used for bit insertion. |
* Note: This if/else is used to bypass compiler differences with the |
* shift operator |
*/ |
if (access_bit_width == ACPI_INTEGER_BIT_SIZE) { |
width_mask = ACPI_UINT64_MAX; |
} else { |
width_mask = ACPI_MASK_BITS_ABOVE(access_bit_width); |
} |
mask = width_mask & |
ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset); |
/* Compute the number of datums (access width data items) */ |
datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, |
access_bit_width); |
field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + |
obj_desc->common_field. |
start_field_bit_offset, |
access_bit_width); |
/* Get initial Datum from the input buffer */ |
memcpy(&raw_datum, buffer, |
ACPI_MIN(obj_desc->common_field.access_byte_width, |
buffer_length - buffer_offset)); |
merged_datum = |
raw_datum << obj_desc->common_field.start_field_bit_offset; |
/* Write the entire field */ |
for (i = 1; i < field_datum_count; i++) { |
/* Write merged datum to the target field */ |
merged_datum &= mask; |
status = acpi_ex_write_with_update_rule(obj_desc, mask, |
merged_datum, |
field_offset); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
field_offset += obj_desc->common_field.access_byte_width; |
/* |
* Start new output datum by merging with previous input datum |
* if necessary. |
* |
* Note: Before the shift, check if the shift value will be larger than |
* the integer size. If so, there is no need to perform the operation. |
* This avoids the differences in behavior between different compilers |
* concerning shift values larger than the target data width. |
*/ |
if ((access_bit_width - |
obj_desc->common_field.start_field_bit_offset) < |
ACPI_INTEGER_BIT_SIZE) { |
merged_datum = |
raw_datum >> (access_bit_width - |
obj_desc->common_field. |
start_field_bit_offset); |
} else { |
merged_datum = 0; |
} |
mask = width_mask; |
if (i == datum_count) { |
break; |
} |
/* Get the next input datum from the buffer */ |
buffer_offset += obj_desc->common_field.access_byte_width; |
memcpy(&raw_datum, ((char *)buffer) + buffer_offset, |
ACPI_MIN(obj_desc->common_field.access_byte_width, |
buffer_length - buffer_offset)); |
merged_datum |= |
raw_datum << obj_desc->common_field.start_field_bit_offset; |
} |
/* Mask off any extra bits in the last datum */ |
buffer_tail_bits = (obj_desc->common_field.bit_length + |
obj_desc->common_field.start_field_bit_offset) % |
access_bit_width; |
if (buffer_tail_bits) { |
mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits); |
} |
/* Write the last datum to the field */ |
merged_datum &= mask; |
status = acpi_ex_write_with_update_rule(obj_desc, |
mask, merged_datum, |
field_offset); |
exit: |
/* Free temporary buffer if we used one */ |
if (new_buffer) { |
ACPI_FREE(new_buffer); |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exmisc.c |
---|
0,0 → 1,733 |
/****************************************************************************** |
* |
* Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#include "amlresrc.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exmisc") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_get_object_reference |
* |
* PARAMETERS: obj_desc - Create a reference to this object |
* return_desc - Where to store the reference |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Obtain and return a "reference" to the target object |
* Common code for the ref_of_op and the cond_ref_of_op. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_get_object_reference(union acpi_operand_object *obj_desc, |
union acpi_operand_object **return_desc, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object *reference_obj; |
union acpi_operand_object *referenced_obj; |
ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc); |
*return_desc = NULL; |
switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
case ACPI_DESC_TYPE_OPERAND: |
if (obj_desc->common.type != ACPI_TYPE_LOCAL_REFERENCE) { |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* |
* Must be a reference to a Local or Arg |
*/ |
switch (obj_desc->reference.class) { |
case ACPI_REFCLASS_LOCAL: |
case ACPI_REFCLASS_ARG: |
case ACPI_REFCLASS_DEBUG: |
/* The referenced object is the pseudo-node for the local/arg */ |
referenced_obj = obj_desc->reference.object; |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown Reference Class 0x%2.2X", |
obj_desc->reference.class)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
break; |
case ACPI_DESC_TYPE_NAMED: |
/* |
* A named reference that has already been resolved to a Node |
*/ |
referenced_obj = obj_desc; |
break; |
default: |
ACPI_ERROR((AE_INFO, "Invalid descriptor type 0x%X", |
ACPI_GET_DESCRIPTOR_TYPE(obj_desc))); |
return_ACPI_STATUS(AE_TYPE); |
} |
/* Create a new reference object */ |
reference_obj = |
acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); |
if (!reference_obj) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
reference_obj->reference.class = ACPI_REFCLASS_REFOF; |
reference_obj->reference.object = referenced_obj; |
*return_desc = reference_obj; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Object %p Type [%s], returning Reference %p\n", |
obj_desc, acpi_ut_get_object_type_name(obj_desc), |
*return_desc)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_concat_template |
* |
* PARAMETERS: operand0 - First source object |
* operand1 - Second source object |
* actual_return_desc - Where to place the return object |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Concatenate two resource templates |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_concat_template(union acpi_operand_object *operand0, |
union acpi_operand_object *operand1, |
union acpi_operand_object **actual_return_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_operand_object *return_desc; |
u8 *new_buf; |
u8 *end_tag; |
acpi_size length0; |
acpi_size length1; |
acpi_size new_length; |
ACPI_FUNCTION_TRACE(ex_concat_template); |
/* |
* Find the end_tag descriptor in each resource template. |
* Note1: returned pointers point TO the end_tag, not past it. |
* Note2: zero-length buffers are allowed; treated like one end_tag |
*/ |
/* Get the length of the first resource template */ |
status = acpi_ut_get_resource_end_tag(operand0, &end_tag); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer); |
/* Get the length of the second resource template */ |
status = acpi_ut_get_resource_end_tag(operand1, &end_tag); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer); |
/* Combine both lengths, minimum size will be 2 for end_tag */ |
new_length = length0 + length1 + sizeof(struct aml_resource_end_tag); |
/* Create a new buffer object for the result (with one end_tag) */ |
return_desc = acpi_ut_create_buffer_object(new_length); |
if (!return_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* |
* Copy the templates to the new buffer, 0 first, then 1 follows. One |
* end_tag descriptor is copied from Operand1. |
*/ |
new_buf = return_desc->buffer.pointer; |
memcpy(new_buf, operand0->buffer.pointer, length0); |
memcpy(new_buf + length0, operand1->buffer.pointer, length1); |
/* Insert end_tag and set the checksum to zero, means "ignore checksum" */ |
new_buf[new_length - 1] = 0; |
new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1; |
/* Return the completed resource template */ |
*actual_return_desc = return_desc; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_do_concatenate |
* |
* PARAMETERS: operand0 - First source object |
* operand1 - Second source object |
* actual_return_desc - Where to place the return object |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Concatenate two objects OF THE SAME TYPE. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_do_concatenate(union acpi_operand_object *operand0, |
union acpi_operand_object *operand1, |
union acpi_operand_object **actual_return_desc, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object *local_operand1 = operand1; |
union acpi_operand_object *return_desc; |
char *new_buf; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ex_do_concatenate); |
/* |
* Convert the second operand if necessary. The first operand |
* determines the type of the second operand, (See the Data Types |
* section of the ACPI specification.) Both object types are |
* guaranteed to be either Integer/String/Buffer by the operand |
* resolution mechanism. |
*/ |
switch (operand0->common.type) { |
case ACPI_TYPE_INTEGER: |
status = |
acpi_ex_convert_to_integer(operand1, &local_operand1, 16); |
break; |
case ACPI_TYPE_STRING: |
status = acpi_ex_convert_to_string(operand1, &local_operand1, |
ACPI_IMPLICIT_CONVERT_HEX); |
break; |
case ACPI_TYPE_BUFFER: |
status = acpi_ex_convert_to_buffer(operand1, &local_operand1); |
break; |
default: |
ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", |
operand0->common.type)); |
status = AE_AML_INTERNAL; |
} |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* |
* Both operands are now known to be the same object type |
* (Both are Integer, String, or Buffer), and we can now perform the |
* concatenation. |
*/ |
/* |
* There are three cases to handle: |
* |
* 1) Two Integers concatenated to produce a new Buffer |
* 2) Two Strings concatenated to produce a new String |
* 3) Two Buffers concatenated to produce a new Buffer |
*/ |
switch (operand0->common.type) { |
case ACPI_TYPE_INTEGER: |
/* Result of two Integers is a Buffer */ |
/* Need enough buffer space for two integers */ |
return_desc = acpi_ut_create_buffer_object((acpi_size) |
ACPI_MUL_2 |
(acpi_gbl_integer_byte_width)); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
new_buf = (char *)return_desc->buffer.pointer; |
/* Copy the first integer, LSB first */ |
memcpy(new_buf, &operand0->integer.value, |
acpi_gbl_integer_byte_width); |
/* Copy the second integer (LSB first) after the first */ |
memcpy(new_buf + acpi_gbl_integer_byte_width, |
&local_operand1->integer.value, |
acpi_gbl_integer_byte_width); |
break; |
case ACPI_TYPE_STRING: |
/* Result of two Strings is a String */ |
return_desc = acpi_ut_create_string_object(((acpi_size) |
operand0->string. |
length + |
local_operand1-> |
string.length)); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
new_buf = return_desc->string.pointer; |
/* Concatenate the strings */ |
strcpy(new_buf, operand0->string.pointer); |
strcpy(new_buf + operand0->string.length, |
local_operand1->string.pointer); |
break; |
case ACPI_TYPE_BUFFER: |
/* Result of two Buffers is a Buffer */ |
return_desc = acpi_ut_create_buffer_object(((acpi_size) |
operand0->buffer. |
length + |
local_operand1-> |
buffer.length)); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
new_buf = (char *)return_desc->buffer.pointer; |
/* Concatenate the buffers */ |
memcpy(new_buf, operand0->buffer.pointer, |
operand0->buffer.length); |
memcpy(new_buf + operand0->buffer.length, |
local_operand1->buffer.pointer, |
local_operand1->buffer.length); |
break; |
default: |
/* Invalid object type, should not happen here */ |
ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", |
operand0->common.type)); |
status = AE_AML_INTERNAL; |
goto cleanup; |
} |
*actual_return_desc = return_desc; |
cleanup: |
if (local_operand1 != operand1) { |
acpi_ut_remove_reference(local_operand1); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_do_math_op |
* |
* PARAMETERS: opcode - AML opcode |
* integer0 - Integer operand #0 |
* integer1 - Integer operand #1 |
* |
* RETURN: Integer result of the operation |
* |
* DESCRIPTION: Execute a math AML opcode. The purpose of having all of the |
* math functions here is to prevent a lot of pointer dereferencing |
* to obtain the operands. |
* |
******************************************************************************/ |
u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1) |
{ |
ACPI_FUNCTION_ENTRY(); |
switch (opcode) { |
case AML_ADD_OP: /* Add (Integer0, Integer1, Result) */ |
return (integer0 + integer1); |
case AML_BIT_AND_OP: /* And (Integer0, Integer1, Result) */ |
return (integer0 & integer1); |
case AML_BIT_NAND_OP: /* NAnd (Integer0, Integer1, Result) */ |
return (~(integer0 & integer1)); |
case AML_BIT_OR_OP: /* Or (Integer0, Integer1, Result) */ |
return (integer0 | integer1); |
case AML_BIT_NOR_OP: /* NOr (Integer0, Integer1, Result) */ |
return (~(integer0 | integer1)); |
case AML_BIT_XOR_OP: /* XOr (Integer0, Integer1, Result) */ |
return (integer0 ^ integer1); |
case AML_MULTIPLY_OP: /* Multiply (Integer0, Integer1, Result) */ |
return (integer0 * integer1); |
case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */ |
/* |
* We need to check if the shiftcount is larger than the integer bit |
* width since the behavior of this is not well-defined in the C language. |
*/ |
if (integer1 >= acpi_gbl_integer_bit_width) { |
return (0); |
} |
return (integer0 << integer1); |
case AML_SHIFT_RIGHT_OP: /* shift_right (Operand, shift_count, Result) */ |
/* |
* We need to check if the shiftcount is larger than the integer bit |
* width since the behavior of this is not well-defined in the C language. |
*/ |
if (integer1 >= acpi_gbl_integer_bit_width) { |
return (0); |
} |
return (integer0 >> integer1); |
case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */ |
return (integer0 - integer1); |
default: |
return (0); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_do_logical_numeric_op |
* |
* PARAMETERS: opcode - AML opcode |
* integer0 - Integer operand #0 |
* integer1 - Integer operand #1 |
* logical_result - TRUE/FALSE result of the operation |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric |
* operators (LAnd and LOr), both operands must be integers. |
* |
* Note: cleanest machine code seems to be produced by the code |
* below, rather than using statements of the form: |
* Result = (Integer0 && Integer1); |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_do_logical_numeric_op(u16 opcode, |
u64 integer0, u64 integer1, u8 *logical_result) |
{ |
acpi_status status = AE_OK; |
u8 local_result = FALSE; |
ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op); |
switch (opcode) { |
case AML_LAND_OP: /* LAnd (Integer0, Integer1) */ |
if (integer0 && integer1) { |
local_result = TRUE; |
} |
break; |
case AML_LOR_OP: /* LOr (Integer0, Integer1) */ |
if (integer0 || integer1) { |
local_result = TRUE; |
} |
break; |
default: |
status = AE_AML_INTERNAL; |
break; |
} |
/* Return the logical result and status */ |
*logical_result = local_result; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_do_logical_op |
* |
* PARAMETERS: opcode - AML opcode |
* operand0 - operand #0 |
* operand1 - operand #1 |
* logical_result - TRUE/FALSE result of the operation |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the |
* functions here is to prevent a lot of pointer dereferencing |
* to obtain the operands and to simplify the generation of the |
* logical value. For the Numeric operators (LAnd and LOr), both |
* operands must be integers. For the other logical operators, |
* operands can be any combination of Integer/String/Buffer. The |
* first operand determines the type to which the second operand |
* will be converted. |
* |
* Note: cleanest machine code seems to be produced by the code |
* below, rather than using statements of the form: |
* Result = (Operand0 == Operand1); |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_do_logical_op(u16 opcode, |
union acpi_operand_object *operand0, |
union acpi_operand_object *operand1, u8 * logical_result) |
{ |
union acpi_operand_object *local_operand1 = operand1; |
u64 integer0; |
u64 integer1; |
u32 length0; |
u32 length1; |
acpi_status status = AE_OK; |
u8 local_result = FALSE; |
int compare; |
ACPI_FUNCTION_TRACE(ex_do_logical_op); |
/* |
* Convert the second operand if necessary. The first operand |
* determines the type of the second operand, (See the Data Types |
* section of the ACPI 3.0+ specification.) Both object types are |
* guaranteed to be either Integer/String/Buffer by the operand |
* resolution mechanism. |
*/ |
switch (operand0->common.type) { |
case ACPI_TYPE_INTEGER: |
status = |
acpi_ex_convert_to_integer(operand1, &local_operand1, 16); |
break; |
case ACPI_TYPE_STRING: |
status = acpi_ex_convert_to_string(operand1, &local_operand1, |
ACPI_IMPLICIT_CONVERT_HEX); |
break; |
case ACPI_TYPE_BUFFER: |
status = acpi_ex_convert_to_buffer(operand1, &local_operand1); |
break; |
default: |
status = AE_AML_INTERNAL; |
break; |
} |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* |
* Two cases: 1) Both Integers, 2) Both Strings or Buffers |
*/ |
if (operand0->common.type == ACPI_TYPE_INTEGER) { |
/* |
* 1) Both operands are of type integer |
* Note: local_operand1 may have changed above |
*/ |
integer0 = operand0->integer.value; |
integer1 = local_operand1->integer.value; |
switch (opcode) { |
case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ |
if (integer0 == integer1) { |
local_result = TRUE; |
} |
break; |
case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ |
if (integer0 > integer1) { |
local_result = TRUE; |
} |
break; |
case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ |
if (integer0 < integer1) { |
local_result = TRUE; |
} |
break; |
default: |
status = AE_AML_INTERNAL; |
break; |
} |
} else { |
/* |
* 2) Both operands are Strings or both are Buffers |
* Note: Code below takes advantage of common Buffer/String |
* object fields. local_operand1 may have changed above. Use |
* memcmp to handle nulls in buffers. |
*/ |
length0 = operand0->buffer.length; |
length1 = local_operand1->buffer.length; |
/* Lexicographic compare: compare the data bytes */ |
compare = memcmp(operand0->buffer.pointer, |
local_operand1->buffer.pointer, |
(length0 > length1) ? length1 : length0); |
switch (opcode) { |
case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ |
/* Length and all bytes must be equal */ |
if ((length0 == length1) && (compare == 0)) { |
/* Length and all bytes match ==> TRUE */ |
local_result = TRUE; |
} |
break; |
case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ |
if (compare > 0) { |
local_result = TRUE; |
goto cleanup; /* TRUE */ |
} |
if (compare < 0) { |
goto cleanup; /* FALSE */ |
} |
/* Bytes match (to shortest length), compare lengths */ |
if (length0 > length1) { |
local_result = TRUE; |
} |
break; |
case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ |
if (compare > 0) { |
goto cleanup; /* FALSE */ |
} |
if (compare < 0) { |
local_result = TRUE; |
goto cleanup; /* TRUE */ |
} |
/* Bytes match (to shortest length), compare lengths */ |
if (length0 < length1) { |
local_result = TRUE; |
} |
break; |
default: |
status = AE_AML_INTERNAL; |
break; |
} |
} |
cleanup: |
/* New object was created if implicit conversion performed - delete */ |
if (local_operand1 != operand1) { |
acpi_ut_remove_reference(local_operand1); |
} |
/* Return the logical result and status */ |
*logical_result = local_result; |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exmutex.c |
---|
0,0 → 1,502 |
/****************************************************************************** |
* |
* Module Name: exmutex - ASL Mutex Acquire/Release functions |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exmutex") |
/* Local prototypes */ |
static void |
acpi_ex_link_mutex(union acpi_operand_object *obj_desc, |
struct acpi_thread_state *thread); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_unlink_mutex |
* |
* PARAMETERS: obj_desc - The mutex to be unlinked |
* |
* RETURN: None |
* |
* DESCRIPTION: Remove a mutex from the "AcquiredMutex" list |
* |
******************************************************************************/ |
void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) |
{ |
struct acpi_thread_state *thread = obj_desc->mutex.owner_thread; |
if (!thread) { |
return; |
} |
/* Doubly linked list */ |
if (obj_desc->mutex.next) { |
(obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; |
} |
if (obj_desc->mutex.prev) { |
(obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; |
/* |
* Migrate the previous sync level associated with this mutex to |
* the previous mutex on the list so that it may be preserved. |
* This handles the case where several mutexes have been acquired |
* at the same level, but are not released in opposite order. |
*/ |
(obj_desc->mutex.prev)->mutex.original_sync_level = |
obj_desc->mutex.original_sync_level; |
} else { |
thread->acquired_mutex_list = obj_desc->mutex.next; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_link_mutex |
* |
* PARAMETERS: obj_desc - The mutex to be linked |
* thread - Current executing thread object |
* |
* RETURN: None |
* |
* DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk |
* |
******************************************************************************/ |
static void |
acpi_ex_link_mutex(union acpi_operand_object *obj_desc, |
struct acpi_thread_state *thread) |
{ |
union acpi_operand_object *list_head; |
list_head = thread->acquired_mutex_list; |
/* This object will be the first object in the list */ |
obj_desc->mutex.prev = NULL; |
obj_desc->mutex.next = list_head; |
/* Update old first object to point back to this object */ |
if (list_head) { |
list_head->mutex.prev = obj_desc; |
} |
/* Update list head */ |
thread->acquired_mutex_list = obj_desc; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_acquire_mutex_object |
* |
* PARAMETERS: timeout - Timeout in milliseconds |
* obj_desc - Mutex object |
* thread_id - Current thread state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common |
* path that supports multiple acquires by the same thread. |
* |
* MUTEX: Interpreter must be locked |
* |
* NOTE: This interface is called from three places: |
* 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator |
* 2) From acpi_ex_acquire_global_lock when an AML Field access requires the |
* global lock |
* 3) From the external interface, acpi_acquire_global_lock |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_acquire_mutex_object(u16 timeout, |
union acpi_operand_object *obj_desc, |
acpi_thread_id thread_id) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Support for multiple acquires by the owning thread */ |
if (obj_desc->mutex.thread_id == thread_id) { |
/* |
* The mutex is already owned by this thread, just increment the |
* acquisition depth |
*/ |
obj_desc->mutex.acquisition_depth++; |
return_ACPI_STATUS(AE_OK); |
} |
/* Acquire the mutex, wait if necessary. Special case for Global Lock */ |
if (obj_desc == acpi_gbl_global_lock_mutex) { |
status = acpi_ev_acquire_global_lock(timeout); |
} else { |
status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, |
timeout); |
} |
if (ACPI_FAILURE(status)) { |
/* Includes failure from a timeout on time_desc */ |
return_ACPI_STATUS(status); |
} |
/* Acquired the mutex: update mutex object */ |
obj_desc->mutex.thread_id = thread_id; |
obj_desc->mutex.acquisition_depth = 1; |
obj_desc->mutex.original_sync_level = 0; |
obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */ |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_acquire_mutex |
* |
* PARAMETERS: time_desc - Timeout integer |
* obj_desc - Mutex object |
* walk_state - Current method execution state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Acquire an AML mutex |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, |
union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex, obj_desc); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Must have a valid thread state struct */ |
if (!walk_state->thread) { |
ACPI_ERROR((AE_INFO, |
"Cannot acquire Mutex [%4.4s], null thread info", |
acpi_ut_get_node_name(obj_desc->mutex.node))); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* |
* Current sync level must be less than or equal to the sync level of the |
* mutex. This mechanism provides some deadlock prevention |
*/ |
if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { |
ACPI_ERROR((AE_INFO, |
"Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)", |
acpi_ut_get_node_name(obj_desc->mutex.node), |
walk_state->thread->current_sync_level)); |
return_ACPI_STATUS(AE_AML_MUTEX_ORDER); |
} |
status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value, |
obj_desc, |
walk_state->thread->thread_id); |
if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) { |
/* Save Thread object, original/current sync levels */ |
obj_desc->mutex.owner_thread = walk_state->thread; |
obj_desc->mutex.original_sync_level = |
walk_state->thread->current_sync_level; |
walk_state->thread->current_sync_level = |
obj_desc->mutex.sync_level; |
/* Link the mutex to the current thread for force-unlock at method exit */ |
acpi_ex_link_mutex(obj_desc, walk_state->thread); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_release_mutex_object |
* |
* PARAMETERS: obj_desc - The object descriptor for this op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Release a previously acquired Mutex, low level interface. |
* Provides a common path that supports multiple releases (after |
* previous multiple acquires) by the same thread. |
* |
* MUTEX: Interpreter must be locked |
* |
* NOTE: This interface is called from three places: |
* 1) From acpi_ex_release_mutex, via an AML Acquire() operator |
* 2) From acpi_ex_release_global_lock when an AML Field access requires the |
* global lock |
* 3) From the external interface, acpi_release_global_lock |
* |
******************************************************************************/ |
acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_release_mutex_object); |
if (obj_desc->mutex.acquisition_depth == 0) { |
return_ACPI_STATUS(AE_NOT_ACQUIRED); |
} |
/* Match multiple Acquires with multiple Releases */ |
obj_desc->mutex.acquisition_depth--; |
if (obj_desc->mutex.acquisition_depth != 0) { |
/* Just decrement the depth and return */ |
return_ACPI_STATUS(AE_OK); |
} |
if (obj_desc->mutex.owner_thread) { |
/* Unlink the mutex from the owner's list */ |
acpi_ex_unlink_mutex(obj_desc); |
obj_desc->mutex.owner_thread = NULL; |
} |
/* Release the mutex, special case for Global Lock */ |
if (obj_desc == acpi_gbl_global_lock_mutex) { |
status = acpi_ev_release_global_lock(); |
} else { |
acpi_os_release_mutex(obj_desc->mutex.os_mutex); |
} |
/* Clear mutex info */ |
obj_desc->mutex.thread_id = 0; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_release_mutex |
* |
* PARAMETERS: obj_desc - The object descriptor for this op |
* walk_state - Current method execution state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Release a previously acquired Mutex. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_release_mutex(union acpi_operand_object *obj_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
u8 previous_sync_level; |
struct acpi_thread_state *owner_thread; |
ACPI_FUNCTION_TRACE(ex_release_mutex); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
owner_thread = obj_desc->mutex.owner_thread; |
/* The mutex must have been previously acquired in order to release it */ |
if (!owner_thread) { |
ACPI_ERROR((AE_INFO, |
"Cannot release Mutex [%4.4s], not acquired", |
acpi_ut_get_node_name(obj_desc->mutex.node))); |
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); |
} |
/* Must have a valid thread ID */ |
if (!walk_state->thread) { |
ACPI_ERROR((AE_INFO, |
"Cannot release Mutex [%4.4s], null thread info", |
acpi_ut_get_node_name(obj_desc->mutex.node))); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* |
* The Mutex is owned, but this thread must be the owner. |
* Special case for Global Lock, any thread can release |
*/ |
if ((owner_thread->thread_id != walk_state->thread->thread_id) && |
(obj_desc != acpi_gbl_global_lock_mutex)) { |
ACPI_ERROR((AE_INFO, |
"Thread %u cannot release Mutex [%4.4s] acquired by thread %u", |
(u32)walk_state->thread->thread_id, |
acpi_ut_get_node_name(obj_desc->mutex.node), |
(u32)owner_thread->thread_id)); |
return_ACPI_STATUS(AE_AML_NOT_OWNER); |
} |
/* |
* The sync level of the mutex must be equal to the current sync level. In |
* other words, the current level means that at least one mutex at that |
* level is currently being held. Attempting to release a mutex of a |
* different level can only mean that the mutex ordering rule is being |
* violated. This behavior is clarified in ACPI 4.0 specification. |
*/ |
if (obj_desc->mutex.sync_level != owner_thread->current_sync_level) { |
ACPI_ERROR((AE_INFO, |
"Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u", |
acpi_ut_get_node_name(obj_desc->mutex.node), |
obj_desc->mutex.sync_level, |
walk_state->thread->current_sync_level)); |
return_ACPI_STATUS(AE_AML_MUTEX_ORDER); |
} |
/* |
* Get the previous sync_level from the head of the acquired mutex list. |
* This handles the case where several mutexes at the same level have been |
* acquired, but are not released in reverse order. |
*/ |
previous_sync_level = |
owner_thread->acquired_mutex_list->mutex.original_sync_level; |
status = acpi_ex_release_mutex_object(obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (obj_desc->mutex.acquisition_depth == 0) { |
/* Restore the previous sync_level */ |
owner_thread->current_sync_level = previous_sync_level; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_release_all_mutexes |
* |
* PARAMETERS: thread - Current executing thread object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Release all mutexes held by this thread |
* |
* NOTE: This function is called as the thread is exiting the interpreter. |
* Mutexes are not released when an individual control method is exited, but |
* only when the parent thread actually exits the interpreter. This allows one |
* method to acquire a mutex, and a different method to release it, as long as |
* this is performed underneath a single parent control method. |
* |
******************************************************************************/ |
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) |
{ |
union acpi_operand_object *next = thread->acquired_mutex_list; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_NAME(ex_release_all_mutexes); |
/* Traverse the list of owned mutexes, releasing each one */ |
while (next) { |
obj_desc = next; |
next = obj_desc->mutex.next; |
obj_desc->mutex.prev = NULL; |
obj_desc->mutex.next = NULL; |
obj_desc->mutex.acquisition_depth = 0; |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Force-releasing held mutex: %p\n", |
obj_desc)); |
/* Release the mutex, special case for Global Lock */ |
if (obj_desc == acpi_gbl_global_lock_mutex) { |
/* Ignore errors */ |
(void)acpi_ev_release_global_lock(); |
} else { |
acpi_os_release_mutex(obj_desc->mutex.os_mutex); |
} |
/* Mark mutex unowned */ |
obj_desc->mutex.owner_thread = NULL; |
obj_desc->mutex.thread_id = 0; |
/* Update Thread sync_level (Last mutex is the important one) */ |
thread->current_sync_level = |
obj_desc->mutex.original_sync_level; |
} |
} |
/drivers/acpi/acpica/exnames.c |
---|
0,0 → 1,435 |
/****************************************************************************** |
* |
* Module Name: exnames - interpreter/scanner name load/execute |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exnames") |
/* Local prototypes */ |
static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs); |
static acpi_status acpi_ex_name_segment(u8 **in_aml_address, char *name_string); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_allocate_name_string |
* |
* PARAMETERS: prefix_count - Count of parent levels. Special cases: |
* (-1)==root, 0==none |
* num_name_segs - count of 4-character name segments |
* |
* RETURN: A pointer to the allocated string segment. This segment must |
* be deleted by the caller. |
* |
* DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name |
* string is long enough, and set up prefix if any. |
* |
******************************************************************************/ |
static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs) |
{ |
char *temp_ptr; |
char *name_string; |
u32 size_needed; |
ACPI_FUNCTION_TRACE(ex_allocate_name_string); |
/* |
* Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix. |
* Also, one byte for the null terminator. |
* This may actually be somewhat longer than needed. |
*/ |
if (prefix_count == ACPI_UINT32_MAX) { |
/* Special case for root */ |
size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; |
} else { |
size_needed = |
prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; |
} |
/* |
* Allocate a buffer for the name. |
* This buffer must be deleted by the caller! |
*/ |
name_string = ACPI_ALLOCATE(size_needed); |
if (!name_string) { |
ACPI_ERROR((AE_INFO, |
"Could not allocate size %u", size_needed)); |
return_PTR(NULL); |
} |
temp_ptr = name_string; |
/* Set up Root or Parent prefixes if needed */ |
if (prefix_count == ACPI_UINT32_MAX) { |
*temp_ptr++ = AML_ROOT_PREFIX; |
} else { |
while (prefix_count--) { |
*temp_ptr++ = AML_PARENT_PREFIX; |
} |
} |
/* Set up Dual or Multi prefixes if needed */ |
if (num_name_segs > 2) { |
/* Set up multi prefixes */ |
*temp_ptr++ = AML_MULTI_NAME_PREFIX_OP; |
*temp_ptr++ = (char)num_name_segs; |
} else if (2 == num_name_segs) { |
/* Set up dual prefixes */ |
*temp_ptr++ = AML_DUAL_NAME_PREFIX; |
} |
/* |
* Terminate string following prefixes. acpi_ex_name_segment() will |
* append the segment(s) |
*/ |
*temp_ptr = 0; |
return_PTR(name_string); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_name_segment |
* |
* PARAMETERS: in_aml_address - Pointer to the name in the AML code |
* name_string - Where to return the name. The name is appended |
* to any existing string to form a namepath |
* |
* RETURN: Status |
* |
* DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream |
* |
******************************************************************************/ |
static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) |
{ |
char *aml_address = (void *)*in_aml_address; |
acpi_status status = AE_OK; |
u32 index; |
char char_buf[5]; |
ACPI_FUNCTION_TRACE(ex_name_segment); |
/* |
* If first character is a digit, then we know that we aren't looking at a |
* valid name segment |
*/ |
char_buf[0] = *aml_address; |
if ('0' <= char_buf[0] && char_buf[0] <= '9') { |
ACPI_ERROR((AE_INFO, "Invalid leading digit: %c", char_buf[0])); |
return_ACPI_STATUS(AE_CTRL_PENDING); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Bytes from stream:\n")); |
for (index = 0; |
(index < ACPI_NAME_SIZE) |
&& (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) { |
char_buf[index] = *aml_address++; |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index])); |
} |
/* Valid name segment */ |
if (index == 4) { |
/* Found 4 valid characters */ |
char_buf[4] = '\0'; |
if (name_string) { |
strcat(name_string, char_buf); |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Appended to - %s\n", name_string)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"No Name string - %s\n", char_buf)); |
} |
} else if (index == 0) { |
/* |
* First character was not a valid name character, |
* so we are looking at something other than a name. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Leading character is not alpha: %02Xh (not a name)\n", |
char_buf[0])); |
status = AE_CTRL_PENDING; |
} else { |
/* |
* Segment started with one or more valid characters, but fewer than |
* the required 4 |
*/ |
status = AE_AML_BAD_NAME; |
ACPI_ERROR((AE_INFO, |
"Bad character 0x%02x in name, at %p", |
*aml_address, aml_address)); |
} |
*in_aml_address = ACPI_CAST_PTR(u8, aml_address); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_get_name_string |
* |
* PARAMETERS: data_type - Object type to be associated with this |
* name |
* in_aml_address - Pointer to the namestring in the AML code |
* out_name_string - Where the namestring is returned |
* out_name_length - Length of the returned string |
* |
* RETURN: Status, namestring and length |
* |
* DESCRIPTION: Extract a full namepath from the AML byte stream, |
* including any prefixes. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_get_name_string(acpi_object_type data_type, |
u8 * in_aml_address, |
char **out_name_string, u32 * out_name_length) |
{ |
acpi_status status = AE_OK; |
u8 *aml_address = in_aml_address; |
char *name_string = NULL; |
u32 num_segments; |
u32 prefix_count = 0; |
u8 has_prefix = FALSE; |
ACPI_FUNCTION_TRACE_PTR(ex_get_name_string, aml_address); |
if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type || |
ACPI_TYPE_LOCAL_BANK_FIELD == data_type || |
ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) { |
/* Disallow prefixes for types associated with field_unit names */ |
name_string = acpi_ex_allocate_name_string(0, 1); |
if (!name_string) { |
status = AE_NO_MEMORY; |
} else { |
status = |
acpi_ex_name_segment(&aml_address, name_string); |
} |
} else { |
/* |
* data_type is not a field name. |
* Examine first character of name for root or parent prefix operators |
*/ |
switch (*aml_address) { |
case AML_ROOT_PREFIX: |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
"RootPrefix(\\) at %p\n", |
aml_address)); |
/* |
* Remember that we have a root_prefix -- |
* see comment in acpi_ex_allocate_name_string() |
*/ |
aml_address++; |
prefix_count = ACPI_UINT32_MAX; |
has_prefix = TRUE; |
break; |
case AML_PARENT_PREFIX: |
/* Increment past possibly multiple parent prefixes */ |
do { |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
"ParentPrefix (^) at %p\n", |
aml_address)); |
aml_address++; |
prefix_count++; |
} while (*aml_address == AML_PARENT_PREFIX); |
has_prefix = TRUE; |
break; |
default: |
/* Not a prefix character */ |
break; |
} |
/* Examine first character of name for name segment prefix operator */ |
switch (*aml_address) { |
case AML_DUAL_NAME_PREFIX: |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
"DualNamePrefix at %p\n", |
aml_address)); |
aml_address++; |
name_string = |
acpi_ex_allocate_name_string(prefix_count, 2); |
if (!name_string) { |
status = AE_NO_MEMORY; |
break; |
} |
/* Indicate that we processed a prefix */ |
has_prefix = TRUE; |
status = |
acpi_ex_name_segment(&aml_address, name_string); |
if (ACPI_SUCCESS(status)) { |
status = |
acpi_ex_name_segment(&aml_address, |
name_string); |
} |
break; |
case AML_MULTI_NAME_PREFIX_OP: |
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
"MultiNamePrefix at %p\n", |
aml_address)); |
/* Fetch count of segments remaining in name path */ |
aml_address++; |
num_segments = *aml_address; |
name_string = |
acpi_ex_allocate_name_string(prefix_count, |
num_segments); |
if (!name_string) { |
status = AE_NO_MEMORY; |
break; |
} |
/* Indicate that we processed a prefix */ |
aml_address++; |
has_prefix = TRUE; |
while (num_segments && |
(status = |
acpi_ex_name_segment(&aml_address, |
name_string)) == AE_OK) { |
num_segments--; |
} |
break; |
case 0: |
/* null_name valid as of 8-12-98 ASL/AML Grammar Update */ |
if (prefix_count == ACPI_UINT32_MAX) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"NameSeg is \"\\\" followed by NULL\n")); |
} |
/* Consume the NULL byte */ |
aml_address++; |
name_string = |
acpi_ex_allocate_name_string(prefix_count, 0); |
if (!name_string) { |
status = AE_NO_MEMORY; |
break; |
} |
break; |
default: |
/* Name segment string */ |
name_string = |
acpi_ex_allocate_name_string(prefix_count, 1); |
if (!name_string) { |
status = AE_NO_MEMORY; |
break; |
} |
status = |
acpi_ex_name_segment(&aml_address, name_string); |
break; |
} |
} |
if (AE_CTRL_PENDING == status && has_prefix) { |
/* Ran out of segments after processing a prefix */ |
ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string)); |
status = AE_AML_BAD_NAME; |
} |
if (ACPI_FAILURE(status)) { |
if (name_string) { |
ACPI_FREE(name_string); |
} |
return_ACPI_STATUS(status); |
} |
*out_name_string = name_string; |
*out_name_length = (u32) (aml_address - in_aml_address); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exoparg1.c |
---|
0,0 → 1,1072 |
/****************************************************************************** |
* |
* Module Name: exoparg1 - AML execution - opcodes with 1 argument |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exoparg1") |
/*! |
* Naming convention for AML interpreter execution routines. |
* |
* The routines that begin execution of AML opcodes are named with a common |
* convention based upon the number of arguments, the number of target operands, |
* and whether or not a value is returned: |
* |
* AcpiExOpcode_xA_yT_zR |
* |
* Where: |
* |
* xA - ARGUMENTS: The number of arguments (input operands) that are |
* required for this opcode type (0 through 6 args). |
* yT - TARGETS: The number of targets (output operands) that are required |
* for this opcode type (0, 1, or 2 targets). |
* zR - RETURN VALUE: Indicates whether this opcode type returns a value |
* as the function return (0 or 1). |
* |
* The AcpiExOpcode* functions are called via the Dispatcher component with |
* fully resolved operands. |
!*/ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_0A_0T_1R |
* |
* PARAMETERS: walk_state - Current state (contains AML opcode) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute operator with no operands, one return value |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *return_desc = NULL; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_0A_0T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Examine the AML opcode */ |
switch (walk_state->opcode) { |
case AML_TIMER_OP: /* Timer () */ |
/* Create a return object of type Integer */ |
return_desc = |
acpi_ut_create_integer_object(acpi_os_get_timer()); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
break; |
default: /* Unknown opcode */ |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
break; |
} |
cleanup: |
/* Delete return object on error */ |
if ((ACPI_FAILURE(status)) || walk_state->result_obj) { |
acpi_ut_remove_reference(return_desc); |
walk_state->result_obj = NULL; |
} else { |
/* Save the return value */ |
walk_state->result_obj = return_desc; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_1A_0T_0R |
* |
* PARAMETERS: walk_state - Current state (contains AML opcode) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute Type 1 monadic operator with numeric operand on |
* object stack |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_0R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Examine the AML opcode */ |
switch (walk_state->opcode) { |
case AML_RELEASE_OP: /* Release (mutex_object) */ |
status = acpi_ex_release_mutex(operand[0], walk_state); |
break; |
case AML_RESET_OP: /* Reset (event_object) */ |
status = acpi_ex_system_reset_event(operand[0]); |
break; |
case AML_SIGNAL_OP: /* Signal (event_object) */ |
status = acpi_ex_system_signal_event(operand[0]); |
break; |
case AML_SLEEP_OP: /* Sleep (msec_time) */ |
status = acpi_ex_system_do_sleep(operand[0]->integer.value); |
break; |
case AML_STALL_OP: /* Stall (usec_time) */ |
status = |
acpi_ex_system_do_stall((u32) operand[0]->integer.value); |
break; |
case AML_UNLOAD_OP: /* Unload (Handle) */ |
status = acpi_ex_unload_table(operand[0]); |
break; |
default: /* Unknown opcode */ |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_1A_1T_0R |
* |
* PARAMETERS: walk_state - Current state (contains AML opcode) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute opcode with one argument, one target, and no |
* return value. |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object **operand = &walk_state->operands[0]; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_0R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Examine the AML opcode */ |
switch (walk_state->opcode) { |
case AML_LOAD_OP: |
status = acpi_ex_load_op(operand[0], operand[1], walk_state); |
break; |
default: /* Unknown opcode */ |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
cleanup: |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_1A_1T_1R |
* |
* PARAMETERS: walk_state - Current state (contains AML opcode) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute opcode with one argument, one target, and a |
* return value. |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *return_desc = NULL; |
union acpi_operand_object *return_desc2 = NULL; |
u32 temp32; |
u32 i; |
u64 power_of_ten; |
u64 digit; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Examine the AML opcode */ |
switch (walk_state->opcode) { |
case AML_BIT_NOT_OP: |
case AML_FIND_SET_LEFT_BIT_OP: |
case AML_FIND_SET_RIGHT_BIT_OP: |
case AML_FROM_BCD_OP: |
case AML_TO_BCD_OP: |
case AML_COND_REF_OF_OP: |
/* Create a return object of type Integer for these opcodes */ |
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
switch (walk_state->opcode) { |
case AML_BIT_NOT_OP: /* Not (Operand, Result) */ |
return_desc->integer.value = ~operand[0]->integer.value; |
break; |
case AML_FIND_SET_LEFT_BIT_OP: /* find_set_left_bit (Operand, Result) */ |
return_desc->integer.value = operand[0]->integer.value; |
/* |
* Acpi specification describes Integer type as a little |
* endian unsigned value, so this boundary condition is valid. |
*/ |
for (temp32 = 0; return_desc->integer.value && |
temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { |
return_desc->integer.value >>= 1; |
} |
return_desc->integer.value = temp32; |
break; |
case AML_FIND_SET_RIGHT_BIT_OP: /* find_set_right_bit (Operand, Result) */ |
return_desc->integer.value = operand[0]->integer.value; |
/* |
* The Acpi specification describes Integer type as a little |
* endian unsigned value, so this boundary condition is valid. |
*/ |
for (temp32 = 0; return_desc->integer.value && |
temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { |
return_desc->integer.value <<= 1; |
} |
/* Since the bit position is one-based, subtract from 33 (65) */ |
return_desc->integer.value = |
temp32 == |
0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32; |
break; |
case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ |
/* |
* The 64-bit ACPI integer can hold 16 4-bit BCD characters |
* (if table is 32-bit, integer can hold 8 BCD characters) |
* Convert each 4-bit BCD value |
*/ |
power_of_ten = 1; |
return_desc->integer.value = 0; |
digit = operand[0]->integer.value; |
/* Convert each BCD digit (each is one nybble wide) */ |
for (i = 0; |
(i < acpi_gbl_integer_nybble_width) && (digit > 0); |
i++) { |
/* Get the least significant 4-bit BCD digit */ |
temp32 = ((u32) digit) & 0xF; |
/* Check the range of the digit */ |
if (temp32 > 9) { |
ACPI_ERROR((AE_INFO, |
"BCD digit too large (not decimal): 0x%X", |
temp32)); |
status = AE_AML_NUMERIC_OVERFLOW; |
goto cleanup; |
} |
/* Sum the digit into the result with the current power of 10 */ |
return_desc->integer.value += |
(((u64) temp32) * power_of_ten); |
/* Shift to next BCD digit */ |
digit >>= 4; |
/* Next power of 10 */ |
power_of_ten *= 10; |
} |
break; |
case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */ |
return_desc->integer.value = 0; |
digit = operand[0]->integer.value; |
/* Each BCD digit is one nybble wide */ |
for (i = 0; |
(i < acpi_gbl_integer_nybble_width) && (digit > 0); |
i++) { |
(void)acpi_ut_short_divide(digit, 10, &digit, |
&temp32); |
/* |
* Insert the BCD digit that resides in the |
* remainder from above |
*/ |
return_desc->integer.value |= |
(((u64) temp32) << ACPI_MUL_4(i)); |
} |
/* Overflow if there is any data left in Digit */ |
if (digit > 0) { |
ACPI_ERROR((AE_INFO, |
"Integer too large to convert to BCD: 0x%8.8X%8.8X", |
ACPI_FORMAT_UINT64(operand[0]-> |
integer.value))); |
status = AE_AML_NUMERIC_OVERFLOW; |
goto cleanup; |
} |
break; |
case AML_COND_REF_OF_OP: /* cond_ref_of (source_object, Result) */ |
/* |
* This op is a little strange because the internal return value is |
* different than the return value stored in the result descriptor |
* (There are really two return values) |
*/ |
if ((struct acpi_namespace_node *)operand[0] == |
acpi_gbl_root_node) { |
/* |
* This means that the object does not exist in the namespace, |
* return FALSE |
*/ |
return_desc->integer.value = 0; |
goto cleanup; |
} |
/* Get the object reference, store it, and remove our reference */ |
status = acpi_ex_get_object_reference(operand[0], |
&return_desc2, |
walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
status = |
acpi_ex_store(return_desc2, operand[1], walk_state); |
acpi_ut_remove_reference(return_desc2); |
/* The object exists in the namespace, return TRUE */ |
return_desc->integer.value = ACPI_UINT64_MAX; |
goto cleanup; |
default: |
/* No other opcodes get here */ |
break; |
} |
break; |
case AML_STORE_OP: /* Store (Source, Target) */ |
/* |
* A store operand is typically a number, string, buffer or lvalue |
* Be careful about deleting the source object, |
* since the object itself may have been stored. |
*/ |
status = acpi_ex_store(operand[0], operand[1], walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* It is possible that the Store already produced a return object */ |
if (!walk_state->result_obj) { |
/* |
* Normally, we would remove a reference on the Operand[0] |
* parameter; But since it is being used as the internal return |
* object (meaning we would normally increment it), the two |
* cancel out, and we simply don't do anything. |
*/ |
walk_state->result_obj = operand[0]; |
walk_state->operands[0] = NULL; /* Prevent deletion */ |
} |
return_ACPI_STATUS(status); |
/* |
* ACPI 2.0 Opcodes |
*/ |
case AML_COPY_OP: /* Copy (Source, Target) */ |
status = |
acpi_ut_copy_iobject_to_iobject(operand[0], &return_desc, |
walk_state); |
break; |
case AML_TO_DECSTRING_OP: /* to_decimal_string (Data, Result) */ |
status = acpi_ex_convert_to_string(operand[0], &return_desc, |
ACPI_EXPLICIT_CONVERT_DECIMAL); |
if (return_desc == operand[0]) { |
/* No conversion performed, add ref to handle return value */ |
acpi_ut_add_reference(return_desc); |
} |
break; |
case AML_TO_HEXSTRING_OP: /* to_hex_string (Data, Result) */ |
status = acpi_ex_convert_to_string(operand[0], &return_desc, |
ACPI_EXPLICIT_CONVERT_HEX); |
if (return_desc == operand[0]) { |
/* No conversion performed, add ref to handle return value */ |
acpi_ut_add_reference(return_desc); |
} |
break; |
case AML_TO_BUFFER_OP: /* to_buffer (Data, Result) */ |
status = acpi_ex_convert_to_buffer(operand[0], &return_desc); |
if (return_desc == operand[0]) { |
/* No conversion performed, add ref to handle return value */ |
acpi_ut_add_reference(return_desc); |
} |
break; |
case AML_TO_INTEGER_OP: /* to_integer (Data, Result) */ |
status = acpi_ex_convert_to_integer(operand[0], &return_desc, |
ACPI_ANY_BASE); |
if (return_desc == operand[0]) { |
/* No conversion performed, add ref to handle return value */ |
acpi_ut_add_reference(return_desc); |
} |
break; |
case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */ |
case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */ |
/* These are two obsolete opcodes */ |
ACPI_ERROR((AE_INFO, |
"%s is obsolete and not implemented", |
acpi_ps_get_opcode_name(walk_state->opcode))); |
status = AE_SUPPORT; |
goto cleanup; |
default: /* Unknown opcode */ |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
if (ACPI_SUCCESS(status)) { |
/* Store the return value computed above into the target object */ |
status = acpi_ex_store(return_desc, operand[1], walk_state); |
} |
cleanup: |
/* Delete return object on error */ |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(return_desc); |
} |
/* Save return object on success */ |
else if (!walk_state->result_obj) { |
walk_state->result_obj = return_desc; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_1A_0T_1R |
* |
* PARAMETERS: walk_state - Current state (contains AML opcode) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute opcode with one argument, no target, and a return value |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *temp_desc; |
union acpi_operand_object *return_desc = NULL; |
acpi_status status = AE_OK; |
u32 type; |
u64 value; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Examine the AML opcode */ |
switch (walk_state->opcode) { |
case AML_LNOT_OP: /* LNot (Operand) */ |
return_desc = acpi_ut_create_integer_object((u64) 0); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* Set result to ONES (TRUE) if Value == 0. Note: |
* return_desc->Integer.Value is initially == 0 (FALSE) from above. |
*/ |
if (!operand[0]->integer.value) { |
return_desc->integer.value = ACPI_UINT64_MAX; |
} |
break; |
case AML_DECREMENT_OP: /* Decrement (Operand) */ |
case AML_INCREMENT_OP: /* Increment (Operand) */ |
/* |
* Create a new integer. Can't just get the base integer and |
* increment it because it may be an Arg or Field. |
*/ |
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* Since we are expecting a Reference operand, it can be either a |
* NS Node or an internal object. |
*/ |
temp_desc = operand[0]; |
if (ACPI_GET_DESCRIPTOR_TYPE(temp_desc) == |
ACPI_DESC_TYPE_OPERAND) { |
/* Internal reference object - prevent deletion */ |
acpi_ut_add_reference(temp_desc); |
} |
/* |
* Convert the Reference operand to an Integer (This removes a |
* reference on the Operand[0] object) |
* |
* NOTE: We use LNOT_OP here in order to force resolution of the |
* reference operand to an actual integer. |
*/ |
status = |
acpi_ex_resolve_operands(AML_LNOT_OP, &temp_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"While resolving operands for [%s]", |
acpi_ps_get_opcode_name(walk_state-> |
opcode))); |
goto cleanup; |
} |
/* |
* temp_desc is now guaranteed to be an Integer object -- |
* Perform the actual increment or decrement |
*/ |
if (walk_state->opcode == AML_INCREMENT_OP) { |
return_desc->integer.value = |
temp_desc->integer.value + 1; |
} else { |
return_desc->integer.value = |
temp_desc->integer.value - 1; |
} |
/* Finished with this Integer object */ |
acpi_ut_remove_reference(temp_desc); |
/* |
* Store the result back (indirectly) through the original |
* Reference object |
*/ |
status = acpi_ex_store(return_desc, operand[0], walk_state); |
break; |
case AML_TYPE_OP: /* object_type (source_object) */ |
/* |
* Note: The operand is not resolved at this point because we want to |
* get the associated object, not its value. For example, we don't |
* want to resolve a field_unit to its value, we want the actual |
* field_unit object. |
*/ |
/* Get the type of the base object */ |
status = |
acpi_ex_resolve_multiple(walk_state, operand[0], &type, |
NULL); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Allocate a descriptor to hold the type. */ |
return_desc = acpi_ut_create_integer_object((u64) type); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
break; |
case AML_SIZE_OF_OP: /* size_of (source_object) */ |
/* |
* Note: The operand is not resolved at this point because we want to |
* get the associated object, not its value. |
*/ |
/* Get the base object */ |
status = acpi_ex_resolve_multiple(walk_state, |
operand[0], &type, |
&temp_desc); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* |
* The type of the base object must be integer, buffer, string, or |
* package. All others are not supported. |
* |
* NOTE: Integer is not specifically supported by the ACPI spec, |
* but is supported implicitly via implicit operand conversion. |
* rather than bother with conversion, we just use the byte width |
* global (4 or 8 bytes). |
*/ |
switch (type) { |
case ACPI_TYPE_INTEGER: |
value = acpi_gbl_integer_byte_width; |
break; |
case ACPI_TYPE_STRING: |
value = temp_desc->string.length; |
break; |
case ACPI_TYPE_BUFFER: |
/* Buffer arguments may not be evaluated at this point */ |
status = acpi_ds_get_buffer_arguments(temp_desc); |
value = temp_desc->buffer.length; |
break; |
case ACPI_TYPE_PACKAGE: |
/* Package arguments may not be evaluated at this point */ |
status = acpi_ds_get_package_arguments(temp_desc); |
value = temp_desc->package.count; |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Operand must be Buffer/Integer/String/Package - found type %s", |
acpi_ut_get_type_name(type))); |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* |
* Now that we have the size of the object, create a result |
* object to hold the value |
*/ |
return_desc = acpi_ut_create_integer_object(value); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
break; |
case AML_REF_OF_OP: /* ref_of (source_object) */ |
status = |
acpi_ex_get_object_reference(operand[0], &return_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
break; |
case AML_DEREF_OF_OP: /* deref_of (obj_reference | String) */ |
/* Check for a method local or argument, or standalone String */ |
if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) == |
ACPI_DESC_TYPE_NAMED) { |
temp_desc = |
acpi_ns_get_attached_object((struct |
acpi_namespace_node *) |
operand[0]); |
if (temp_desc |
&& ((temp_desc->common.type == ACPI_TYPE_STRING) |
|| (temp_desc->common.type == |
ACPI_TYPE_LOCAL_REFERENCE))) { |
operand[0] = temp_desc; |
acpi_ut_add_reference(temp_desc); |
} else { |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
} else { |
switch ((operand[0])->common.type) { |
case ACPI_TYPE_LOCAL_REFERENCE: |
/* |
* This is a deref_of (local_x | arg_x) |
* |
* Must resolve/dereference the local/arg reference first |
*/ |
switch (operand[0]->reference.class) { |
case ACPI_REFCLASS_LOCAL: |
case ACPI_REFCLASS_ARG: |
/* Set Operand[0] to the value of the local/arg */ |
status = |
acpi_ds_method_data_get_value |
(operand[0]->reference.class, |
operand[0]->reference.value, |
walk_state, &temp_desc); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* |
* Delete our reference to the input object and |
* point to the object just retrieved |
*/ |
acpi_ut_remove_reference(operand[0]); |
operand[0] = temp_desc; |
break; |
case ACPI_REFCLASS_REFOF: |
/* Get the object to which the reference refers */ |
temp_desc = |
operand[0]->reference.object; |
acpi_ut_remove_reference(operand[0]); |
operand[0] = temp_desc; |
break; |
default: |
/* Must be an Index op - handled below */ |
break; |
} |
break; |
case ACPI_TYPE_STRING: |
break; |
default: |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) != |
ACPI_DESC_TYPE_NAMED) { |
if ((operand[0])->common.type == ACPI_TYPE_STRING) { |
/* |
* This is a deref_of (String). The string is a reference |
* to a named ACPI object. |
* |
* 1) Find the owning Node |
* 2) Dereference the node to an actual object. Could be a |
* Field, so we need to resolve the node to a value. |
*/ |
status = |
acpi_ns_get_node(walk_state->scope_info-> |
scope.node, |
operand[0]->string.pointer, |
ACPI_NS_SEARCH_PARENT, |
ACPI_CAST_INDIRECT_PTR |
(struct |
acpi_namespace_node, |
&return_desc)); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
status = |
acpi_ex_resolve_node_to_value |
(ACPI_CAST_INDIRECT_PTR |
(struct acpi_namespace_node, &return_desc), |
walk_state); |
goto cleanup; |
} |
} |
/* Operand[0] may have changed from the code above */ |
if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) == |
ACPI_DESC_TYPE_NAMED) { |
/* |
* This is a deref_of (object_reference) |
* Get the actual object from the Node (This is the dereference). |
* This case may only happen when a local_x or arg_x is |
* dereferenced above. |
*/ |
return_desc = acpi_ns_get_attached_object((struct |
acpi_namespace_node |
*) |
operand[0]); |
acpi_ut_add_reference(return_desc); |
} else { |
/* |
* This must be a reference object produced by either the |
* Index() or ref_of() operator |
*/ |
switch (operand[0]->reference.class) { |
case ACPI_REFCLASS_INDEX: |
/* |
* The target type for the Index operator must be |
* either a Buffer or a Package |
*/ |
switch (operand[0]->reference.target_type) { |
case ACPI_TYPE_BUFFER_FIELD: |
temp_desc = |
operand[0]->reference.object; |
/* |
* Create a new object that contains one element of the |
* buffer -- the element pointed to by the index. |
* |
* NOTE: index into a buffer is NOT a pointer to a |
* sub-buffer of the main buffer, it is only a pointer to a |
* single element (byte) of the buffer! |
* |
* Since we are returning the value of the buffer at the |
* indexed location, we don't need to add an additional |
* reference to the buffer itself. |
*/ |
return_desc = |
acpi_ut_create_integer_object((u64) |
temp_desc->buffer.pointer[operand[0]->reference.value]); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
break; |
case ACPI_TYPE_PACKAGE: |
/* |
* Return the referenced element of the package. We must |
* add another reference to the referenced object, however. |
*/ |
return_desc = |
*(operand[0]->reference.where); |
if (!return_desc) { |
/* |
* Element is NULL, do not allow the dereference. |
* This provides compatibility with other ACPI |
* implementations. |
*/ |
return_ACPI_STATUS |
(AE_AML_UNINITIALIZED_ELEMENT); |
} |
acpi_ut_add_reference(return_desc); |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown Index TargetType 0x%X in reference object %p", |
operand[0]->reference. |
target_type, operand[0])); |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
break; |
case ACPI_REFCLASS_REFOF: |
return_desc = operand[0]->reference.object; |
if (ACPI_GET_DESCRIPTOR_TYPE(return_desc) == |
ACPI_DESC_TYPE_NAMED) { |
return_desc = |
acpi_ns_get_attached_object((struct |
acpi_namespace_node |
*) |
return_desc); |
if (!return_desc) { |
break; |
} |
/* |
* June 2013: |
* buffer_fields/field_units require additional resolution |
*/ |
switch (return_desc->common.type) { |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
status = |
acpi_ex_read_data_from_field |
(walk_state, return_desc, |
&temp_desc); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
return_desc = temp_desc; |
break; |
default: |
/* Add another reference to the object */ |
acpi_ut_add_reference |
(return_desc); |
break; |
} |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown class in reference(%p) - 0x%2.2X", |
operand[0], |
operand[0]->reference.class)); |
status = AE_TYPE; |
goto cleanup; |
} |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
cleanup: |
/* Delete return object on error */ |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(return_desc); |
} |
/* Save return object on success */ |
else { |
walk_state->result_obj = return_desc; |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exoparg2.c |
---|
0,0 → 1,584 |
/****************************************************************************** |
* |
* Module Name: exoparg2 - AML execution - opcodes with 2 arguments |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "acinterp.h" |
#include "acevents.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exoparg2") |
/*! |
* Naming convention for AML interpreter execution routines. |
* |
* The routines that begin execution of AML opcodes are named with a common |
* convention based upon the number of arguments, the number of target operands, |
* and whether or not a value is returned: |
* |
* AcpiExOpcode_xA_yT_zR |
* |
* Where: |
* |
* xA - ARGUMENTS: The number of arguments (input operands) that are |
* required for this opcode type (1 through 6 args). |
* yT - TARGETS: The number of targets (output operands) that are required |
* for this opcode type (0, 1, or 2 targets). |
* zR - RETURN VALUE: Indicates whether this opcode type returns a value |
* as the function return (0 or 1). |
* |
* The AcpiExOpcode* functions are called via the Dispatcher component with |
* fully resolved operands. |
!*/ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_2A_0T_0R |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute opcode with two arguments, no target, and no return |
* value. |
* |
* ALLOCATION: Deletes both operands |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
struct acpi_namespace_node *node; |
u32 value; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_0R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Examine the opcode */ |
switch (walk_state->opcode) { |
case AML_NOTIFY_OP: /* Notify (notify_object, notify_value) */ |
/* The first operand is a namespace node */ |
node = (struct acpi_namespace_node *)operand[0]; |
/* Second value is the notify value */ |
value = (u32) operand[1]->integer.value; |
/* Are notifies allowed on this object? */ |
if (!acpi_ev_is_notify_object(node)) { |
ACPI_ERROR((AE_INFO, |
"Unexpected notify object type [%s]", |
acpi_ut_get_type_name(node->type))); |
status = AE_AML_OPERAND_TYPE; |
break; |
} |
/* |
* Dispatch the notify to the appropriate handler |
* NOTE: the request is queued for execution after this method |
* completes. The notify handlers are NOT invoked synchronously |
* from this thread -- because handlers may in turn run other |
* control methods. |
*/ |
status = acpi_ev_queue_notify_request(node, value); |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_2A_2T_1R |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets |
* and one implicit return value. |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *return_desc1 = NULL; |
union acpi_operand_object *return_desc2 = NULL; |
acpi_status status; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_2T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Execute the opcode */ |
switch (walk_state->opcode) { |
case AML_DIVIDE_OP: |
/* Divide (Dividend, Divisor, remainder_result quotient_result) */ |
return_desc1 = |
acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc1) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
return_desc2 = |
acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc2) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Quotient to return_desc1, remainder to return_desc2 */ |
status = acpi_ut_divide(operand[0]->integer.value, |
operand[1]->integer.value, |
&return_desc1->integer.value, |
&return_desc2->integer.value); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
/* Store the results to the target reference operands */ |
status = acpi_ex_store(return_desc2, operand[2], walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
status = acpi_ex_store(return_desc1, operand[3], walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
cleanup: |
/* |
* Since the remainder is not returned indirectly, remove a reference to |
* it. Only the quotient is returned indirectly. |
*/ |
acpi_ut_remove_reference(return_desc2); |
if (ACPI_FAILURE(status)) { |
/* Delete the return object */ |
acpi_ut_remove_reference(return_desc1); |
} |
/* Save return object (the remainder) on success */ |
else { |
walk_state->result_obj = return_desc1; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_2A_1T_1R |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute opcode with two arguments, one target, and a return |
* value. |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *return_desc = NULL; |
u64 index; |
acpi_status status = AE_OK; |
acpi_size length = 0; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Execute the opcode */ |
if (walk_state->op_info->flags & AML_MATH) { |
/* All simple math opcodes (add, etc.) */ |
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
return_desc->integer.value = |
acpi_ex_do_math_op(walk_state->opcode, |
operand[0]->integer.value, |
operand[1]->integer.value); |
goto store_result_to_target; |
} |
switch (walk_state->opcode) { |
case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ |
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* return_desc will contain the remainder */ |
status = acpi_ut_divide(operand[0]->integer.value, |
operand[1]->integer.value, |
NULL, &return_desc->integer.value); |
break; |
case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ |
status = acpi_ex_do_concatenate(operand[0], operand[1], |
&return_desc, walk_state); |
break; |
case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ |
/* |
* Input object is guaranteed to be a buffer at this point (it may have |
* been converted.) Copy the raw buffer data to a new object of |
* type String. |
*/ |
/* |
* Get the length of the new string. It is the smallest of: |
* 1) Length of the input buffer |
* 2) Max length as specified in the to_string operator |
* 3) Length of input buffer up to a zero byte (null terminator) |
* |
* NOTE: A length of zero is ok, and will create a zero-length, null |
* terminated string. |
*/ |
while ((length < operand[0]->buffer.length) && |
(length < operand[1]->integer.value) && |
(operand[0]->buffer.pointer[length])) { |
length++; |
} |
/* Allocate a new string object */ |
return_desc = acpi_ut_create_string_object(length); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* Copy the raw buffer data with no transform. |
* (NULL terminated already) |
*/ |
memcpy(return_desc->string.pointer, |
operand[0]->buffer.pointer, length); |
break; |
case AML_CONCAT_RES_OP: |
/* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ |
status = acpi_ex_concat_template(operand[0], operand[1], |
&return_desc, walk_state); |
break; |
case AML_INDEX_OP: /* Index (Source Index Result) */ |
/* Create the internal return object */ |
return_desc = |
acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Initialize the Index reference object */ |
index = operand[1]->integer.value; |
return_desc->reference.value = (u32) index; |
return_desc->reference.class = ACPI_REFCLASS_INDEX; |
/* |
* At this point, the Source operand is a String, Buffer, or Package. |
* Verify that the index is within range. |
*/ |
switch ((operand[0])->common.type) { |
case ACPI_TYPE_STRING: |
if (index >= operand[0]->string.length) { |
length = operand[0]->string.length; |
status = AE_AML_STRING_LIMIT; |
} |
return_desc->reference.target_type = |
ACPI_TYPE_BUFFER_FIELD; |
return_desc->reference.index_pointer = |
&(operand[0]->buffer.pointer[index]); |
break; |
case ACPI_TYPE_BUFFER: |
if (index >= operand[0]->buffer.length) { |
length = operand[0]->buffer.length; |
status = AE_AML_BUFFER_LIMIT; |
} |
return_desc->reference.target_type = |
ACPI_TYPE_BUFFER_FIELD; |
return_desc->reference.index_pointer = |
&(operand[0]->buffer.pointer[index]); |
break; |
case ACPI_TYPE_PACKAGE: |
if (index >= operand[0]->package.count) { |
length = operand[0]->package.count; |
status = AE_AML_PACKAGE_LIMIT; |
} |
return_desc->reference.target_type = ACPI_TYPE_PACKAGE; |
return_desc->reference.where = |
&operand[0]->package.elements[index]; |
break; |
default: |
status = AE_AML_INTERNAL; |
goto cleanup; |
} |
/* Failure means that the Index was beyond the end of the object */ |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Index (0x%X%8.8X) is beyond end of object (length 0x%X)", |
ACPI_FORMAT_UINT64(index), |
(u32)length)); |
goto cleanup; |
} |
/* |
* Save the target object and add a reference to it for the life |
* of the index |
*/ |
return_desc->reference.object = operand[0]; |
acpi_ut_add_reference(operand[0]); |
/* Store the reference to the Target */ |
status = acpi_ex_store(return_desc, operand[2], walk_state); |
/* Return the reference */ |
walk_state->result_obj = return_desc; |
goto cleanup; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
break; |
} |
store_result_to_target: |
if (ACPI_SUCCESS(status)) { |
/* |
* Store the result of the operation (which is now in return_desc) into |
* the Target descriptor. |
*/ |
status = acpi_ex_store(return_desc, operand[2], walk_state); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
if (!walk_state->result_obj) { |
walk_state->result_obj = return_desc; |
} |
} |
cleanup: |
/* Delete return object on error */ |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(return_desc); |
walk_state->result_obj = NULL; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_2A_0T_1R |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *return_desc = NULL; |
acpi_status status = AE_OK; |
u8 logical_result = FALSE; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
/* Create the internal return object */ |
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Execute the Opcode */ |
if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) { |
/* logical_op (Operand0, Operand1) */ |
status = acpi_ex_do_logical_numeric_op(walk_state->opcode, |
operand[0]->integer. |
value, |
operand[1]->integer. |
value, &logical_result); |
goto store_logical_result; |
} else if (walk_state->op_info->flags & AML_LOGICAL) { |
/* logical_op (Operand0, Operand1) */ |
status = acpi_ex_do_logical_op(walk_state->opcode, operand[0], |
operand[1], &logical_result); |
goto store_logical_result; |
} |
switch (walk_state->opcode) { |
case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */ |
status = |
acpi_ex_acquire_mutex(operand[1], operand[0], walk_state); |
if (status == AE_TIME) { |
logical_result = TRUE; /* TRUE = Acquire timed out */ |
status = AE_OK; |
} |
break; |
case AML_WAIT_OP: /* Wait (event_object, Timeout) */ |
status = acpi_ex_system_wait_event(operand[1], operand[0]); |
if (status == AE_TIME) { |
logical_result = TRUE; /* TRUE, Wait timed out */ |
status = AE_OK; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
store_logical_result: |
/* |
* Set return value to according to logical_result. logical TRUE (all ones) |
* Default is FALSE (zero) |
*/ |
if (logical_result) { |
return_desc->integer.value = ACPI_UINT64_MAX; |
} |
cleanup: |
/* Delete return object on error */ |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(return_desc); |
} |
/* Save return object on success */ |
else { |
walk_state->result_obj = return_desc; |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exoparg3.c |
---|
0,0 → 1,281 |
/****************************************************************************** |
* |
* Module Name: exoparg3 - AML execution - opcodes with 3 arguments |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "acparser.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exoparg3") |
/*! |
* Naming convention for AML interpreter execution routines. |
* |
* The routines that begin execution of AML opcodes are named with a common |
* convention based upon the number of arguments, the number of target operands, |
* and whether or not a value is returned: |
* |
* AcpiExOpcode_xA_yT_zR |
* |
* Where: |
* |
* xA - ARGUMENTS: The number of arguments (input operands) that are |
* required for this opcode type (1 through 6 args). |
* yT - TARGETS: The number of targets (output operands) that are required |
* for this opcode type (0, 1, or 2 targets). |
* zR - RETURN VALUE: Indicates whether this opcode type returns a value |
* as the function return (0 or 1). |
* |
* The AcpiExOpcode* functions are called via the Dispatcher component with |
* fully resolved operands. |
!*/ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_3A_0T_0R |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute Triadic operator (3 operands) |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
struct acpi_signal_fatal_info *fatal; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
switch (walk_state->opcode) { |
case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"FatalOp: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", |
(u32) operand[0]->integer.value, |
(u32) operand[1]->integer.value, |
(u32) operand[2]->integer.value)); |
fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info)); |
if (fatal) { |
fatal->type = (u32) operand[0]->integer.value; |
fatal->code = (u32) operand[1]->integer.value; |
fatal->argument = (u32) operand[2]->integer.value; |
} |
/* Always signal the OS! */ |
status = acpi_os_signal(ACPI_SIGNAL_FATAL, fatal); |
/* Might return while OS is shutting down, just continue */ |
ACPI_FREE(fatal); |
goto cleanup; |
case AML_EXTERNAL_OP: |
/* |
* If the interpreter sees this opcode, just ignore it. The External |
* op is intended for use by disassemblers in order to properly |
* disassemble control method invocations. The opcode or group of |
* opcodes should be surrounded by an "if (0)" clause to ensure that |
* AML interpreters never see the opcode. |
*/ |
status = AE_OK; |
goto cleanup; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
cleanup: |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_3A_1T_1R |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute Triadic operator (3 operands) |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *return_desc = NULL; |
char *buffer = NULL; |
acpi_status status = AE_OK; |
u64 index; |
acpi_size length; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
switch (walk_state->opcode) { |
case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ |
/* |
* Create the return object. The Source operand is guaranteed to be |
* either a String or a Buffer, so just use its type. |
*/ |
return_desc = acpi_ut_create_internal_object((operand[0])-> |
common.type); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Get the Integer values from the objects */ |
index = operand[1]->integer.value; |
length = (acpi_size) operand[2]->integer.value; |
/* |
* If the index is beyond the length of the String/Buffer, or if the |
* requested length is zero, return a zero-length String/Buffer |
*/ |
if (index >= operand[0]->string.length) { |
length = 0; |
} |
/* Truncate request if larger than the actual String/Buffer */ |
else if ((index + length) > operand[0]->string.length) { |
length = (acpi_size) operand[0]->string.length - |
(acpi_size) index; |
} |
/* Strings always have a sub-pointer, not so for buffers */ |
switch ((operand[0])->common.type) { |
case ACPI_TYPE_STRING: |
/* Always allocate a new buffer for the String */ |
buffer = ACPI_ALLOCATE_ZEROED((acpi_size) length + 1); |
if (!buffer) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
break; |
case ACPI_TYPE_BUFFER: |
/* If the requested length is zero, don't allocate a buffer */ |
if (length > 0) { |
/* Allocate a new buffer for the Buffer */ |
buffer = ACPI_ALLOCATE_ZEROED(length); |
if (!buffer) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
} |
break; |
default: /* Should not happen */ |
status = AE_AML_OPERAND_TYPE; |
goto cleanup; |
} |
if (buffer) { |
/* We have a buffer, copy the portion requested */ |
memcpy(buffer, operand[0]->string.pointer + index, |
length); |
} |
/* Set the length of the new String/Buffer */ |
return_desc->string.pointer = buffer; |
return_desc->string.length = (u32) length; |
/* Mark buffer initialized */ |
return_desc->buffer.flags |= AOPOBJ_DATA_VALID; |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
/* Store the result in the target */ |
status = acpi_ex_store(return_desc, operand[3], walk_state); |
cleanup: |
/* Delete return object on error */ |
if (ACPI_FAILURE(status) || walk_state->result_obj) { |
acpi_ut_remove_reference(return_desc); |
walk_state->result_obj = NULL; |
} |
/* Set the return object and exit */ |
else { |
walk_state->result_obj = return_desc; |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exoparg6.c |
---|
0,0 → 1,332 |
/****************************************************************************** |
* |
* Module Name: exoparg6 - AML execution - opcodes with 6 arguments |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "acparser.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exoparg6") |
/*! |
* Naming convention for AML interpreter execution routines. |
* |
* The routines that begin execution of AML opcodes are named with a common |
* convention based upon the number of arguments, the number of target operands, |
* and whether or not a value is returned: |
* |
* AcpiExOpcode_xA_yT_zR |
* |
* Where: |
* |
* xA - ARGUMENTS: The number of arguments (input operands) that are |
* required for this opcode type (1 through 6 args). |
* yT - TARGETS: The number of targets (output operands) that are required |
* for this opcode type (0, 1, or 2 targets). |
* zR - RETURN VALUE: Indicates whether this opcode type returns a value |
* as the function return (0 or 1). |
* |
* The AcpiExOpcode* functions are called via the Dispatcher component with |
* fully resolved operands. |
!*/ |
/* Local prototypes */ |
static u8 |
acpi_ex_do_match(u32 match_op, |
union acpi_operand_object *package_obj, |
union acpi_operand_object *match_obj); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_do_match |
* |
* PARAMETERS: match_op - The AML match operand |
* package_obj - Object from the target package |
* match_obj - Object to be matched |
* |
* RETURN: TRUE if the match is successful, FALSE otherwise |
* |
* DESCRIPTION: Implements the low-level match for the ASL Match operator. |
* Package elements will be implicitly converted to the type of |
* the match object (Integer/Buffer/String). |
* |
******************************************************************************/ |
static u8 |
acpi_ex_do_match(u32 match_op, |
union acpi_operand_object *package_obj, |
union acpi_operand_object *match_obj) |
{ |
u8 logical_result = TRUE; |
acpi_status status; |
/* |
* Note: Since the package_obj/match_obj ordering is opposite to that of |
* the standard logical operators, we have to reverse them when we call |
* do_logical_op in order to make the implicit conversion rules work |
* correctly. However, this means we have to flip the entire equation |
* also. A bit ugly perhaps, but overall, better than fussing the |
* parameters around at runtime, over and over again. |
* |
* Below, P[i] refers to the package element, M refers to the Match object. |
*/ |
switch (match_op) { |
case MATCH_MTR: |
/* Always true */ |
break; |
case MATCH_MEQ: |
/* |
* True if equal: (P[i] == M) |
* Change to: (M == P[i]) |
*/ |
status = |
acpi_ex_do_logical_op(AML_LEQUAL_OP, match_obj, package_obj, |
&logical_result); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
break; |
case MATCH_MLE: |
/* |
* True if less than or equal: (P[i] <= M) (P[i] not_greater than M) |
* Change to: (M >= P[i]) (M not_less than P[i]) |
*/ |
status = |
acpi_ex_do_logical_op(AML_LLESS_OP, match_obj, package_obj, |
&logical_result); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
logical_result = (u8) ! logical_result; |
break; |
case MATCH_MLT: |
/* |
* True if less than: (P[i] < M) |
* Change to: (M > P[i]) |
*/ |
status = |
acpi_ex_do_logical_op(AML_LGREATER_OP, match_obj, |
package_obj, &logical_result); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
break; |
case MATCH_MGE: |
/* |
* True if greater than or equal: (P[i] >= M) (P[i] not_less than M) |
* Change to: (M <= P[i]) (M not_greater than P[i]) |
*/ |
status = |
acpi_ex_do_logical_op(AML_LGREATER_OP, match_obj, |
package_obj, &logical_result); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
logical_result = (u8) ! logical_result; |
break; |
case MATCH_MGT: |
/* |
* True if greater than: (P[i] > M) |
* Change to: (M < P[i]) |
*/ |
status = |
acpi_ex_do_logical_op(AML_LLESS_OP, match_obj, package_obj, |
&logical_result); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
break; |
default: |
/* Undefined */ |
return (FALSE); |
} |
return (logical_result); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_opcode_6A_0T_1R |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute opcode with 6 arguments, no target, and a return value |
* |
******************************************************************************/ |
acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) |
{ |
union acpi_operand_object **operand = &walk_state->operands[0]; |
union acpi_operand_object *return_desc = NULL; |
acpi_status status = AE_OK; |
u64 index; |
union acpi_operand_object *this_element; |
ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R, |
acpi_ps_get_opcode_name(walk_state->opcode)); |
switch (walk_state->opcode) { |
case AML_MATCH_OP: |
/* |
* Match (search_pkg[0], match_op1[1], match_obj1[2], |
* match_op2[3], match_obj2[4], start_index[5]) |
*/ |
/* Validate both Match Term Operators (MTR, MEQ, etc.) */ |
if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) || |
(operand[3]->integer.value > MAX_MATCH_OPERATOR)) { |
ACPI_ERROR((AE_INFO, "Match operator out of range")); |
status = AE_AML_OPERAND_VALUE; |
goto cleanup; |
} |
/* Get the package start_index, validate against the package length */ |
index = operand[5]->integer.value; |
if (index >= operand[0]->package.count) { |
ACPI_ERROR((AE_INFO, |
"Index (0x%8.8X%8.8X) beyond package end (0x%X)", |
ACPI_FORMAT_UINT64(index), |
operand[0]->package.count)); |
status = AE_AML_PACKAGE_LIMIT; |
goto cleanup; |
} |
/* Create an integer for the return value */ |
/* Default return value is ACPI_UINT64_MAX if no match found */ |
return_desc = acpi_ut_create_integer_object(ACPI_UINT64_MAX); |
if (!return_desc) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* |
* Examine each element until a match is found. Both match conditions |
* must be satisfied for a match to occur. Within the loop, |
* "continue" signifies that the current element does not match |
* and the next should be examined. |
* |
* Upon finding a match, the loop will terminate via "break" at |
* the bottom. If it terminates "normally", match_value will be |
* ACPI_UINT64_MAX (Ones) (its initial value) indicating that no |
* match was found. |
*/ |
for (; index < operand[0]->package.count; index++) { |
/* Get the current package element */ |
this_element = operand[0]->package.elements[index]; |
/* Treat any uninitialized (NULL) elements as non-matching */ |
if (!this_element) { |
continue; |
} |
/* |
* Both match conditions must be satisfied. Execution of a continue |
* (proceed to next iteration of enclosing for loop) signifies a |
* non-match. |
*/ |
if (!acpi_ex_do_match((u32) operand[1]->integer.value, |
this_element, operand[2])) { |
continue; |
} |
if (!acpi_ex_do_match((u32) operand[3]->integer.value, |
this_element, operand[4])) { |
continue; |
} |
/* Match found: Index is the return value */ |
return_desc->integer.value = index; |
break; |
} |
break; |
case AML_LOAD_TABLE_OP: |
status = acpi_ex_load_table_op(walk_state, &return_desc); |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
walk_state->opcode)); |
status = AE_AML_BAD_OPCODE; |
goto cleanup; |
} |
cleanup: |
/* Delete return object on error */ |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(return_desc); |
} |
/* Save return object on success */ |
else { |
walk_state->result_obj = return_desc; |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exprep.c |
---|
0,0 → 1,630 |
/****************************************************************************** |
* |
* Module Name: exprep - ACPI AML (p-code) execution - field prep utilities |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#include "acdispat.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exprep") |
/* Local prototypes */ |
static u32 |
acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, |
u8 field_flags, u32 * return_byte_alignment); |
#ifdef ACPI_UNDER_DEVELOPMENT |
static u32 |
acpi_ex_generate_access(u32 field_bit_offset, |
u32 field_bit_length, u32 region_length); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_generate_access |
* |
* PARAMETERS: field_bit_offset - Start of field within parent region/buffer |
* field_bit_length - Length of field in bits |
* region_length - Length of parent in bytes |
* |
* RETURN: Field granularity (8, 16, 32 or 64) and |
* byte_alignment (1, 2, 3, or 4) |
* |
* DESCRIPTION: Generate an optimal access width for fields defined with the |
* any_acc keyword. |
* |
* NOTE: Need to have the region_length in order to check for boundary |
* conditions (end-of-region). However, the region_length is a deferred |
* operation. Therefore, to complete this implementation, the generation |
* of this access width must be deferred until the region length has |
* been evaluated. |
* |
******************************************************************************/ |
static u32 |
acpi_ex_generate_access(u32 field_bit_offset, |
u32 field_bit_length, u32 region_length) |
{ |
u32 field_byte_length; |
u32 field_byte_offset; |
u32 field_byte_end_offset; |
u32 access_byte_width; |
u32 field_start_offset; |
u32 field_end_offset; |
u32 minimum_access_width = 0xFFFFFFFF; |
u32 minimum_accesses = 0xFFFFFFFF; |
u32 accesses; |
ACPI_FUNCTION_TRACE(ex_generate_access); |
/* Round Field start offset and length to "minimal" byte boundaries */ |
field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8)); |
field_byte_end_offset = ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + |
field_bit_offset, 8)); |
field_byte_length = field_byte_end_offset - field_byte_offset; |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Bit length %u, Bit offset %u\n", |
field_bit_length, field_bit_offset)); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Byte Length %u, Byte Offset %u, End Offset %u\n", |
field_byte_length, field_byte_offset, |
field_byte_end_offset)); |
/* |
* Iterative search for the maximum access width that is both aligned |
* and does not go beyond the end of the region |
* |
* Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes) |
*/ |
for (access_byte_width = 1; access_byte_width <= 8; |
access_byte_width <<= 1) { |
/* |
* 1) Round end offset up to next access boundary and make sure that |
* this does not go beyond the end of the parent region. |
* 2) When the Access width is greater than the field_byte_length, we |
* are done. (This does not optimize for the perfectly aligned |
* case yet). |
*/ |
if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <= |
region_length) { |
field_start_offset = |
ACPI_ROUND_DOWN(field_byte_offset, |
access_byte_width) / |
access_byte_width; |
field_end_offset = |
ACPI_ROUND_UP((field_byte_length + |
field_byte_offset), |
access_byte_width) / |
access_byte_width; |
accesses = field_end_offset - field_start_offset; |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"AccessWidth %u end is within region\n", |
access_byte_width)); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Field Start %u, Field End %u -- requires %u accesses\n", |
field_start_offset, field_end_offset, |
accesses)); |
/* Single access is optimal */ |
if (accesses <= 1) { |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Entire field can be accessed with one operation of size %u\n", |
access_byte_width)); |
return_VALUE(access_byte_width); |
} |
/* |
* Fits in the region, but requires more than one read/write. |
* try the next wider access on next iteration |
*/ |
if (accesses < minimum_accesses) { |
minimum_accesses = accesses; |
minimum_access_width = access_byte_width; |
} |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"AccessWidth %u end is NOT within region\n", |
access_byte_width)); |
if (access_byte_width == 1) { |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Field goes beyond end-of-region!\n")); |
/* Field does not fit in the region at all */ |
return_VALUE(0); |
} |
/* |
* This width goes beyond the end-of-region, back off to |
* previous access |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Backing off to previous optimal access width of %u\n", |
minimum_access_width)); |
return_VALUE(minimum_access_width); |
} |
} |
/* |
* Could not read/write field with one operation, |
* just use max access width |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Cannot access field in one operation, using width 8\n")); |
return_VALUE(8); |
} |
#endif /* ACPI_UNDER_DEVELOPMENT */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_decode_field_access |
* |
* PARAMETERS: obj_desc - Field object |
* field_flags - Encoded fieldflags (contains access bits) |
* return_byte_alignment - Where the byte alignment is returned |
* |
* RETURN: Field granularity (8, 16, 32 or 64) and |
* byte_alignment (1, 2, 3, or 4) |
* |
* DESCRIPTION: Decode the access_type bits of a field definition. |
* |
******************************************************************************/ |
static u32 |
acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, |
u8 field_flags, u32 * return_byte_alignment) |
{ |
u32 access; |
u32 byte_alignment; |
u32 bit_length; |
ACPI_FUNCTION_TRACE(ex_decode_field_access); |
access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK); |
switch (access) { |
case AML_FIELD_ACCESS_ANY: |
#ifdef ACPI_UNDER_DEVELOPMENT |
byte_alignment = |
acpi_ex_generate_access(obj_desc->common_field. |
start_field_bit_offset, |
obj_desc->common_field.bit_length, |
0xFFFFFFFF |
/* Temp until we pass region_length as parameter */ |
); |
bit_length = byte_alignment * 8; |
#endif |
byte_alignment = 1; |
bit_length = 8; |
break; |
case AML_FIELD_ACCESS_BYTE: |
case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */ |
byte_alignment = 1; |
bit_length = 8; |
break; |
case AML_FIELD_ACCESS_WORD: |
byte_alignment = 2; |
bit_length = 16; |
break; |
case AML_FIELD_ACCESS_DWORD: |
byte_alignment = 4; |
bit_length = 32; |
break; |
case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ |
byte_alignment = 8; |
bit_length = 64; |
break; |
default: |
/* Invalid field access type */ |
ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access)); |
return_UINT32(0); |
} |
if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { |
/* |
* buffer_field access can be on any byte boundary, so the |
* byte_alignment is always 1 byte -- regardless of any byte_alignment |
* implied by the field access type. |
*/ |
byte_alignment = 1; |
} |
*return_byte_alignment = byte_alignment; |
return_UINT32(bit_length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_prep_common_field_object |
* |
* PARAMETERS: obj_desc - The field object |
* field_flags - Access, lock_rule, and update_rule. |
* The format of a field_flag is described |
* in the ACPI specification |
* field_attribute - Special attributes (not used) |
* field_bit_position - Field start position |
* field_bit_length - Field length in number of bits |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize the areas of the field object that are common |
* to the various types of fields. Note: This is very "sensitive" |
* code because we are solving the general case for field |
* alignment. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, |
u8 field_flags, |
u8 field_attribute, |
u32 field_bit_position, u32 field_bit_length) |
{ |
u32 access_bit_width; |
u32 byte_alignment; |
u32 nearest_byte_address; |
ACPI_FUNCTION_TRACE(ex_prep_common_field_object); |
/* |
* Note: the structure being initialized is the |
* ACPI_COMMON_FIELD_INFO; No structure fields outside of the common |
* area are initialized by this procedure. |
*/ |
obj_desc->common_field.field_flags = field_flags; |
obj_desc->common_field.attribute = field_attribute; |
obj_desc->common_field.bit_length = field_bit_length; |
/* |
* Decode the access type so we can compute offsets. The access type gives |
* two pieces of information - the width of each field access and the |
* necessary byte_alignment (address granularity) of the access. |
* |
* For any_acc, the access_bit_width is the largest width that is both |
* necessary and possible in an attempt to access the whole field in one |
* I/O operation. However, for any_acc, the byte_alignment is always one |
* byte. |
* |
* For all Buffer Fields, the byte_alignment is always one byte. |
* |
* For all other access types (Byte, Word, Dword, Qword), the Bitwidth is |
* the same (equivalent) as the byte_alignment. |
*/ |
access_bit_width = acpi_ex_decode_field_access(obj_desc, field_flags, |
&byte_alignment); |
if (!access_bit_width) { |
return_ACPI_STATUS(AE_AML_OPERAND_VALUE); |
} |
/* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */ |
obj_desc->common_field.access_byte_width = (u8) |
ACPI_DIV_8(access_bit_width); |
/* |
* base_byte_offset is the address of the start of the field within the |
* region. It is the byte address of the first *datum* (field-width data |
* unit) of the field. (i.e., the first datum that contains at least the |
* first *bit* of the field.) |
* |
* Note: byte_alignment is always either equal to the access_bit_width or 8 |
* (Byte access), and it defines the addressing granularity of the parent |
* region or buffer. |
*/ |
nearest_byte_address = |
ACPI_ROUND_BITS_DOWN_TO_BYTES(field_bit_position); |
obj_desc->common_field.base_byte_offset = (u32) |
ACPI_ROUND_DOWN(nearest_byte_address, byte_alignment); |
/* |
* start_field_bit_offset is the offset of the first bit of the field within |
* a field datum. |
*/ |
obj_desc->common_field.start_field_bit_offset = (u8) |
(field_bit_position - |
ACPI_MUL_8(obj_desc->common_field.base_byte_offset)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_prep_field_value |
* |
* PARAMETERS: info - Contains all field creation info |
* |
* RETURN: Status |
* |
* DESCRIPTION: Construct an object of type union acpi_operand_object with a |
* subtype of def_field and connect it to the parent Node. |
* |
******************************************************************************/ |
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *second_desc = NULL; |
acpi_status status; |
u32 access_byte_width; |
u32 type; |
ACPI_FUNCTION_TRACE(ex_prep_field_value); |
/* Parameter validation */ |
if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { |
if (!info->region_node) { |
ACPI_ERROR((AE_INFO, "Null RegionNode")); |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
type = acpi_ns_get_type(info->region_node); |
if (type != ACPI_TYPE_REGION) { |
ACPI_ERROR((AE_INFO, |
"Needed Region, found type 0x%X (%s)", type, |
acpi_ut_get_type_name(type))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
} |
/* Allocate a new field object */ |
obj_desc = acpi_ut_create_internal_object(info->field_type); |
if (!obj_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Initialize areas of the object that are common to all fields */ |
obj_desc->common_field.node = info->field_node; |
status = acpi_ex_prep_common_field_object(obj_desc, |
info->field_flags, |
info->attribute, |
info->field_bit_position, |
info->field_bit_length); |
if (ACPI_FAILURE(status)) { |
acpi_ut_delete_object_desc(obj_desc); |
return_ACPI_STATUS(status); |
} |
/* Initialize areas of the object that are specific to the field type */ |
switch (info->field_type) { |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
obj_desc->field.region_obj = |
acpi_ns_get_attached_object(info->region_node); |
/* Fields specific to generic_serial_bus fields */ |
obj_desc->field.access_length = info->access_length; |
if (info->connection_node) { |
second_desc = info->connection_node->object; |
if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { |
status = |
acpi_ds_get_buffer_arguments(second_desc); |
if (ACPI_FAILURE(status)) { |
acpi_ut_delete_object_desc(obj_desc); |
return_ACPI_STATUS(status); |
} |
} |
obj_desc->field.resource_buffer = |
second_desc->buffer.pointer; |
obj_desc->field.resource_length = |
(u16)second_desc->buffer.length; |
} else if (info->resource_buffer) { |
obj_desc->field.resource_buffer = info->resource_buffer; |
obj_desc->field.resource_length = info->resource_length; |
} |
obj_desc->field.pin_number_index = info->pin_number_index; |
/* Allow full data read from EC address space */ |
if ((obj_desc->field.region_obj->region.space_id == |
ACPI_ADR_SPACE_EC) |
&& (obj_desc->common_field.bit_length > 8)) { |
access_byte_width = |
ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field. |
bit_length); |
/* Maximum byte width supported is 255 */ |
if (access_byte_width < 256) { |
obj_desc->common_field.access_byte_width = |
(u8)access_byte_width; |
} |
} |
/* An additional reference for the container */ |
acpi_ut_add_reference(obj_desc->field.region_obj); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", |
obj_desc->field.start_field_bit_offset, |
obj_desc->field.base_byte_offset, |
obj_desc->field.access_byte_width, |
obj_desc->field.region_obj)); |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
obj_desc->bank_field.value = info->bank_value; |
obj_desc->bank_field.region_obj = |
acpi_ns_get_attached_object(info->region_node); |
obj_desc->bank_field.bank_obj = |
acpi_ns_get_attached_object(info->register_node); |
/* An additional reference for the attached objects */ |
acpi_ut_add_reference(obj_desc->bank_field.region_obj); |
acpi_ut_add_reference(obj_desc->bank_field.bank_obj); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", |
obj_desc->bank_field.start_field_bit_offset, |
obj_desc->bank_field.base_byte_offset, |
obj_desc->field.access_byte_width, |
obj_desc->bank_field.region_obj, |
obj_desc->bank_field.bank_obj)); |
/* |
* Remember location in AML stream of the field unit |
* opcode and operands -- since the bank_value |
* operands must be evaluated. |
*/ |
second_desc = obj_desc->common.next_object; |
second_desc->extra.aml_start = |
ACPI_CAST_PTR(union acpi_parse_object, |
info->data_register_node)->named.data; |
second_desc->extra.aml_length = |
ACPI_CAST_PTR(union acpi_parse_object, |
info->data_register_node)->named.length; |
break; |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
/* Get the Index and Data registers */ |
obj_desc->index_field.index_obj = |
acpi_ns_get_attached_object(info->register_node); |
obj_desc->index_field.data_obj = |
acpi_ns_get_attached_object(info->data_register_node); |
if (!obj_desc->index_field.data_obj |
|| !obj_desc->index_field.index_obj) { |
ACPI_ERROR((AE_INFO, |
"Null Index Object during field prep")); |
acpi_ut_delete_object_desc(obj_desc); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* An additional reference for the attached objects */ |
acpi_ut_add_reference(obj_desc->index_field.data_obj); |
acpi_ut_add_reference(obj_desc->index_field.index_obj); |
/* |
* April 2006: Changed to match MS behavior |
* |
* The value written to the Index register is the byte offset of the |
* target field in units of the granularity of the index_field |
* |
* Previously, the value was calculated as an index in terms of the |
* width of the Data register, as below: |
* |
* obj_desc->index_field.Value = (u32) |
* (Info->field_bit_position / ACPI_MUL_8 ( |
* obj_desc->Field.access_byte_width)); |
* |
* February 2006: Tried value as a byte offset: |
* obj_desc->index_field.Value = (u32) |
* ACPI_DIV_8 (Info->field_bit_position); |
*/ |
obj_desc->index_field.value = |
(u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), |
obj_desc->index_field. |
access_byte_width); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", |
obj_desc->index_field.start_field_bit_offset, |
obj_desc->index_field.base_byte_offset, |
obj_desc->index_field.value, |
obj_desc->field.access_byte_width, |
obj_desc->index_field.index_obj, |
obj_desc->index_field.data_obj)); |
break; |
default: |
/* No other types should get here */ |
break; |
} |
/* |
* Store the constructed descriptor (obj_desc) into the parent Node, |
* preserving the current type of that named_obj. |
*/ |
status = acpi_ns_attach_object(info->field_node, obj_desc, |
acpi_ns_get_type(info->field_node)); |
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
"Set NamedObj %p [%4.4s], ObjDesc %p\n", |
info->field_node, |
acpi_ut_get_node_name(info->field_node), obj_desc)); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exregion.c |
---|
0,0 → 1,536 |
/****************************************************************************** |
* |
* Module Name: exregion - ACPI default op_region (address space) handlers |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exregion") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_memory_space_handler |
* |
* PARAMETERS: function - Read or Write operation |
* address - Where in the space to read or write |
* bit_width - Field width in bits (8, 16, or 32) |
* value - Pointer to in or out value |
* handler_context - Pointer to Handler's context |
* region_context - Pointer to context specific to the |
* accessed region |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handler for the System Memory address space (Op Region) |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_system_memory_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context) |
{ |
acpi_status status = AE_OK; |
void *logical_addr_ptr = NULL; |
struct acpi_mem_space_context *mem_info = region_context; |
u32 length; |
acpi_size map_length; |
acpi_size page_boundary_map_length; |
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED |
u32 remainder; |
#endif |
ACPI_FUNCTION_TRACE(ex_system_memory_space_handler); |
/* Validate and translate the bit width */ |
switch (bit_width) { |
case 8: |
length = 1; |
break; |
case 16: |
length = 2; |
break; |
case 32: |
length = 4; |
break; |
case 64: |
length = 8; |
break; |
default: |
ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u", |
bit_width)); |
return_ACPI_STATUS(AE_AML_OPERAND_VALUE); |
} |
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED |
/* |
* Hardware does not support non-aligned data transfers, we must verify |
* the request. |
*/ |
(void)acpi_ut_short_divide((u64) address, length, NULL, &remainder); |
if (remainder != 0) { |
return_ACPI_STATUS(AE_AML_ALIGNMENT); |
} |
#endif |
/* |
* Does the request fit into the cached memory mapping? |
* Is 1) Address below the current mapping? OR |
* 2) Address beyond the current mapping? |
*/ |
if ((address < mem_info->mapped_physical_address) || |
(((u64) address + length) > ((u64) |
mem_info->mapped_physical_address + |
mem_info->mapped_length))) { |
/* |
* The request cannot be resolved by the current memory mapping; |
* Delete the existing mapping and create a new one. |
*/ |
if (mem_info->mapped_length) { |
/* Valid mapping, delete it */ |
acpi_os_unmap_memory(mem_info->mapped_logical_address, |
mem_info->mapped_length); |
} |
/* |
* October 2009: Attempt to map from the requested address to the |
* end of the region. However, we will never map more than one |
* page, nor will we cross a page boundary. |
*/ |
map_length = (acpi_size) |
((mem_info->address + mem_info->length) - address); |
/* |
* If mapping the entire remaining portion of the region will cross |
* a page boundary, just map up to the page boundary, do not cross. |
* On some systems, crossing a page boundary while mapping regions |
* can cause warnings if the pages have different attributes |
* due to resource management. |
* |
* This has the added benefit of constraining a single mapping to |
* one page, which is similar to the original code that used a 4k |
* maximum window. |
*/ |
page_boundary_map_length = (acpi_size) |
(ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address); |
if (page_boundary_map_length == 0) { |
page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE; |
} |
if (map_length > page_boundary_map_length) { |
map_length = page_boundary_map_length; |
} |
/* Create a new mapping starting at the address given */ |
mem_info->mapped_logical_address = |
acpi_os_map_memory(address, map_length); |
if (!mem_info->mapped_logical_address) { |
ACPI_ERROR((AE_INFO, |
"Could not map memory at 0x%8.8X%8.8X, size %u", |
ACPI_FORMAT_UINT64(address), |
(u32)map_length)); |
mem_info->mapped_length = 0; |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Save the physical address and mapping size */ |
mem_info->mapped_physical_address = address; |
mem_info->mapped_length = map_length; |
} |
/* |
* Generate a logical pointer corresponding to the address we want to |
* access |
*/ |
logical_addr_ptr = mem_info->mapped_logical_address + |
((u64) address - (u64) mem_info->mapped_physical_address); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n", |
bit_width, function, ACPI_FORMAT_UINT64(address))); |
/* |
* Perform the memory read or write |
* |
* Note: For machines that do not support non-aligned transfers, the target |
* address was checked for alignment above. We do not attempt to break the |
* transfer up into smaller (byte-size) chunks because the AML specifically |
* asked for a transfer width that the hardware may require. |
*/ |
switch (function) { |
case ACPI_READ: |
*value = 0; |
switch (bit_width) { |
case 8: |
*value = (u64)ACPI_GET8(logical_addr_ptr); |
break; |
case 16: |
*value = (u64)ACPI_GET16(logical_addr_ptr); |
break; |
case 32: |
*value = (u64)ACPI_GET32(logical_addr_ptr); |
break; |
case 64: |
*value = (u64)ACPI_GET64(logical_addr_ptr); |
break; |
default: |
/* bit_width was already validated */ |
break; |
} |
break; |
case ACPI_WRITE: |
switch (bit_width) { |
case 8: |
ACPI_SET8(logical_addr_ptr, *value); |
break; |
case 16: |
ACPI_SET16(logical_addr_ptr, *value); |
break; |
case 32: |
ACPI_SET32(logical_addr_ptr, *value); |
break; |
case 64: |
ACPI_SET64(logical_addr_ptr, *value); |
break; |
default: |
/* bit_width was already validated */ |
break; |
} |
break; |
default: |
status = AE_BAD_PARAMETER; |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_io_space_handler |
* |
* PARAMETERS: function - Read or Write operation |
* address - Where in the space to read or write |
* bit_width - Field width in bits (8, 16, or 32) |
* value - Pointer to in or out value |
* handler_context - Pointer to Handler's context |
* region_context - Pointer to context specific to the |
* accessed region |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handler for the System IO address space (Op Region) |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_system_io_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context) |
{ |
acpi_status status = AE_OK; |
u32 value32; |
ACPI_FUNCTION_TRACE(ex_system_io_space_handler); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"System-IO (width %u) R/W %u Address=%8.8X%8.8X\n", |
bit_width, function, ACPI_FORMAT_UINT64(address))); |
/* Decode the function parameter */ |
switch (function) { |
case ACPI_READ: |
status = acpi_hw_read_port((acpi_io_address) address, |
&value32, bit_width); |
*value = value32; |
break; |
case ACPI_WRITE: |
status = acpi_hw_write_port((acpi_io_address) address, |
(u32) * value, bit_width); |
break; |
default: |
status = AE_BAD_PARAMETER; |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_pci_config_space_handler |
* |
* PARAMETERS: function - Read or Write operation |
* address - Where in the space to read or write |
* bit_width - Field width in bits (8, 16, or 32) |
* value - Pointer to in or out value |
* handler_context - Pointer to Handler's context |
* region_context - Pointer to context specific to the |
* accessed region |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handler for the PCI Config address space (Op Region) |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_pci_config_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context) |
{ |
acpi_status status = AE_OK; |
struct acpi_pci_id *pci_id; |
u16 pci_register; |
ACPI_FUNCTION_TRACE(ex_pci_config_space_handler); |
/* |
* The arguments to acpi_os(Read|Write)pci_configuration are: |
* |
* pci_segment is the PCI bus segment range 0-31 |
* pci_bus is the PCI bus number range 0-255 |
* pci_device is the PCI device number range 0-31 |
* pci_function is the PCI device function number |
* pci_register is the Config space register range 0-255 bytes |
* |
* value - input value for write, output address for read |
* |
*/ |
pci_id = (struct acpi_pci_id *)region_context; |
pci_register = (u16) (u32) address; |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Pci-Config %u (%u) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n", |
function, bit_width, pci_id->segment, pci_id->bus, |
pci_id->device, pci_id->function, pci_register)); |
switch (function) { |
case ACPI_READ: |
*value = 0; |
status = acpi_os_read_pci_configuration(pci_id, pci_register, |
value, bit_width); |
break; |
case ACPI_WRITE: |
status = acpi_os_write_pci_configuration(pci_id, pci_register, |
*value, bit_width); |
break; |
default: |
status = AE_BAD_PARAMETER; |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_cmos_space_handler |
* |
* PARAMETERS: function - Read or Write operation |
* address - Where in the space to read or write |
* bit_width - Field width in bits (8, 16, or 32) |
* value - Pointer to in or out value |
* handler_context - Pointer to Handler's context |
* region_context - Pointer to context specific to the |
* accessed region |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handler for the CMOS address space (Op Region) |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_cmos_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_cmos_space_handler); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_pci_bar_space_handler |
* |
* PARAMETERS: function - Read or Write operation |
* address - Where in the space to read or write |
* bit_width - Field width in bits (8, 16, or 32) |
* value - Pointer to in or out value |
* handler_context - Pointer to Handler's context |
* region_context - Pointer to context specific to the |
* accessed region |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handler for the PCI bar_target address space (Op Region) |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_pci_bar_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_data_table_space_handler |
* |
* PARAMETERS: function - Read or Write operation |
* address - Where in the space to read or write |
* bit_width - Field width in bits (8, 16, or 32) |
* value - Pointer to in or out value |
* handler_context - Pointer to Handler's context |
* region_context - Pointer to context specific to the |
* accessed region |
* |
* RETURN: Status |
* |
* DESCRIPTION: Handler for the Data Table address space (Op Region) |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_data_table_space_handler(u32 function, |
acpi_physical_address address, |
u32 bit_width, |
u64 *value, |
void *handler_context, void *region_context) |
{ |
ACPI_FUNCTION_TRACE(ex_data_table_space_handler); |
/* |
* Perform the memory read or write. The bit_width was already |
* validated. |
*/ |
switch (function) { |
case ACPI_READ: |
memcpy(ACPI_CAST_PTR(char, value), |
ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width)); |
break; |
case ACPI_WRITE: |
memcpy(ACPI_PHYSADDR_TO_PTR(address), |
ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width)); |
break; |
default: |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/exresnte.c |
---|
0,0 → 1,279 |
/****************************************************************************** |
* |
* Module Name: exresnte - AML Interpreter object resolution |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exresnte") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_resolve_node_to_value |
* |
* PARAMETERS: object_ptr - Pointer to a location that contains |
* a pointer to a NS node, and will receive a |
* pointer to the resolved object. |
* walk_state - Current state. Valid only if executing AML |
* code. NULL if simply resolving an object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Resolve a Namespace node to a valued object |
* |
* Note: for some of the data types, the pointer attached to the Node |
* can be either a pointer to an actual internal object or a pointer into the |
* AML stream itself. These types are currently: |
* |
* ACPI_TYPE_INTEGER |
* ACPI_TYPE_STRING |
* ACPI_TYPE_BUFFER |
* ACPI_TYPE_MUTEX |
* ACPI_TYPE_PACKAGE |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *source_desc; |
union acpi_operand_object *obj_desc = NULL; |
struct acpi_namespace_node *node; |
acpi_object_type entry_type; |
ACPI_FUNCTION_TRACE(ex_resolve_node_to_value); |
/* |
* The stack pointer points to a struct acpi_namespace_node (Node). Get the |
* object that is attached to the Node. |
*/ |
node = *object_ptr; |
source_desc = acpi_ns_get_attached_object(node); |
entry_type = acpi_ns_get_type((acpi_handle) node); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Entry=%p SourceDesc=%p [%s]\n", |
node, source_desc, |
acpi_ut_get_type_name(entry_type))); |
if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) || |
(entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
/* There is always exactly one level of indirection */ |
node = ACPI_CAST_PTR(struct acpi_namespace_node, node->object); |
source_desc = acpi_ns_get_attached_object(node); |
entry_type = acpi_ns_get_type((acpi_handle) node); |
*object_ptr = node; |
} |
/* |
* Several object types require no further processing: |
* 1) Device/Thermal objects don't have a "real" subobject, return the Node |
* 2) Method locals and arguments have a pseudo-Node |
* 3) 10/2007: Added method type to assist with Package construction. |
*/ |
if ((entry_type == ACPI_TYPE_DEVICE) || |
(entry_type == ACPI_TYPE_THERMAL) || |
(entry_type == ACPI_TYPE_METHOD) || |
(node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) { |
return_ACPI_STATUS(AE_OK); |
} |
if (!source_desc) { |
ACPI_ERROR((AE_INFO, "No object attached to node [%4.4s] %p", |
node->name.ascii, node)); |
return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); |
} |
/* |
* Action is based on the type of the Node, which indicates the type |
* of the attached object or pointer |
*/ |
switch (entry_type) { |
case ACPI_TYPE_PACKAGE: |
if (source_desc->common.type != ACPI_TYPE_PACKAGE) { |
ACPI_ERROR((AE_INFO, "Object not a Package, type %s", |
acpi_ut_get_object_type_name(source_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
status = acpi_ds_get_package_arguments(source_desc); |
if (ACPI_SUCCESS(status)) { |
/* Return an additional reference to the object */ |
obj_desc = source_desc; |
acpi_ut_add_reference(obj_desc); |
} |
break; |
case ACPI_TYPE_BUFFER: |
if (source_desc->common.type != ACPI_TYPE_BUFFER) { |
ACPI_ERROR((AE_INFO, "Object not a Buffer, type %s", |
acpi_ut_get_object_type_name(source_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
status = acpi_ds_get_buffer_arguments(source_desc); |
if (ACPI_SUCCESS(status)) { |
/* Return an additional reference to the object */ |
obj_desc = source_desc; |
acpi_ut_add_reference(obj_desc); |
} |
break; |
case ACPI_TYPE_STRING: |
if (source_desc->common.type != ACPI_TYPE_STRING) { |
ACPI_ERROR((AE_INFO, "Object not a String, type %s", |
acpi_ut_get_object_type_name(source_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* Return an additional reference to the object */ |
obj_desc = source_desc; |
acpi_ut_add_reference(obj_desc); |
break; |
case ACPI_TYPE_INTEGER: |
if (source_desc->common.type != ACPI_TYPE_INTEGER) { |
ACPI_ERROR((AE_INFO, "Object not a Integer, type %s", |
acpi_ut_get_object_type_name(source_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* Return an additional reference to the object */ |
obj_desc = source_desc; |
acpi_ut_add_reference(obj_desc); |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"FieldRead Node=%p SourceDesc=%p Type=%X\n", |
node, source_desc, entry_type)); |
status = |
acpi_ex_read_data_from_field(walk_state, source_desc, |
&obj_desc); |
break; |
/* For these objects, just return the object attached to the Node */ |
case ACPI_TYPE_MUTEX: |
case ACPI_TYPE_POWER: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_EVENT: |
case ACPI_TYPE_REGION: |
/* Return an additional reference to the object */ |
obj_desc = source_desc; |
acpi_ut_add_reference(obj_desc); |
break; |
/* TYPE_ANY is untyped, and thus there is no object associated with it */ |
case ACPI_TYPE_ANY: |
ACPI_ERROR((AE_INFO, |
"Untyped entry %p, no attached object!", node)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ |
case ACPI_TYPE_LOCAL_REFERENCE: |
switch (source_desc->reference.class) { |
case ACPI_REFCLASS_TABLE: /* This is a ddb_handle */ |
case ACPI_REFCLASS_REFOF: |
case ACPI_REFCLASS_INDEX: |
/* Return an additional reference to the object */ |
obj_desc = source_desc; |
acpi_ut_add_reference(obj_desc); |
break; |
default: |
/* No named references are allowed here */ |
ACPI_ERROR((AE_INFO, |
"Unsupported Reference type 0x%X", |
source_desc->reference.class)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
break; |
default: |
/* Default case is for unknown types */ |
ACPI_ERROR((AE_INFO, |
"Node %p - Unknown object type 0x%X", |
node, entry_type)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} /* switch (entry_type) */ |
/* Return the object descriptor */ |
*object_ptr = (void *)obj_desc; |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exresolv.c |
---|
0,0 → 1,559 |
/****************************************************************************** |
* |
* Module Name: exresolv - AML Interpreter object resolution |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exresolv") |
/* Local prototypes */ |
static acpi_status |
acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, |
struct acpi_walk_state *walk_state); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_resolve_to_value |
* |
* PARAMETERS: **stack_ptr - Points to entry on obj_stack, which can |
* be either an (union acpi_operand_object *) |
* or an acpi_handle. |
* walk_state - Current method state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert Reference objects to values |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ex_resolve_to_value, stack_ptr); |
if (!stack_ptr || !*stack_ptr) { |
ACPI_ERROR((AE_INFO, "Internal - null pointer")); |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
/* |
* The entity pointed to by the stack_ptr can be either |
* 1) A valid union acpi_operand_object, or |
* 2) A struct acpi_namespace_node (named_obj) |
*/ |
if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_OPERAND) { |
status = acpi_ex_resolve_object_to_value(stack_ptr, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (!*stack_ptr) { |
ACPI_ERROR((AE_INFO, "Internal - null pointer")); |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
} |
/* |
* Object on the stack may have changed if acpi_ex_resolve_object_to_value() |
* was called (i.e., we can't use an _else_ here.) |
*/ |
if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_NAMED) { |
status = |
acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR |
(struct acpi_namespace_node, |
stack_ptr), walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_resolve_object_to_value |
* |
* PARAMETERS: stack_ptr - Pointer to an internal object |
* walk_state - Current method state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Retrieve the value from an internal object. The Reference type |
* uses the associated AML opcode to determine the value. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *stack_desc; |
union acpi_operand_object *obj_desc = NULL; |
u8 ref_type; |
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value); |
stack_desc = *stack_ptr; |
/* This is an object of type union acpi_operand_object */ |
switch (stack_desc->common.type) { |
case ACPI_TYPE_LOCAL_REFERENCE: |
ref_type = stack_desc->reference.class; |
switch (ref_type) { |
case ACPI_REFCLASS_LOCAL: |
case ACPI_REFCLASS_ARG: |
/* |
* Get the local from the method's state info |
* Note: this increments the local's object reference count |
*/ |
status = acpi_ds_method_data_get_value(ref_type, |
stack_desc-> |
reference.value, |
walk_state, |
&obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Arg/Local %X] ValueObj is %p\n", |
stack_desc->reference.value, |
obj_desc)); |
/* |
* Now we can delete the original Reference Object and |
* replace it with the resolved value |
*/ |
acpi_ut_remove_reference(stack_desc); |
*stack_ptr = obj_desc; |
break; |
case ACPI_REFCLASS_INDEX: |
switch (stack_desc->reference.target_type) { |
case ACPI_TYPE_BUFFER_FIELD: |
/* Just return - do not dereference */ |
break; |
case ACPI_TYPE_PACKAGE: |
/* If method call or copy_object - do not dereference */ |
if ((walk_state->opcode == |
AML_INT_METHODCALL_OP) |
|| (walk_state->opcode == AML_COPY_OP)) { |
break; |
} |
/* Otherwise, dereference the package_index to a package element */ |
obj_desc = *stack_desc->reference.where; |
if (obj_desc) { |
/* |
* Valid object descriptor, copy pointer to return value |
* (i.e., dereference the package index) |
* Delete the ref object, increment the returned object |
*/ |
acpi_ut_add_reference(obj_desc); |
*stack_ptr = obj_desc; |
} else { |
/* |
* A NULL object descriptor means an uninitialized element of |
* the package, can't dereference it |
*/ |
ACPI_ERROR((AE_INFO, |
"Attempt to dereference an Index to NULL package element Idx=%p", |
stack_desc)); |
status = AE_AML_UNINITIALIZED_ELEMENT; |
} |
break; |
default: |
/* Invalid reference object */ |
ACPI_ERROR((AE_INFO, |
"Unknown TargetType 0x%X in Index/Reference object %p", |
stack_desc->reference.target_type, |
stack_desc)); |
status = AE_AML_INTERNAL; |
break; |
} |
break; |
case ACPI_REFCLASS_REFOF: |
case ACPI_REFCLASS_DEBUG: |
case ACPI_REFCLASS_TABLE: |
/* Just leave the object as-is, do not dereference */ |
break; |
case ACPI_REFCLASS_NAME: /* Reference to a named object */ |
/* Dereference the name */ |
if ((stack_desc->reference.node->type == |
ACPI_TYPE_DEVICE) |
|| (stack_desc->reference.node->type == |
ACPI_TYPE_THERMAL)) { |
/* These node types do not have 'real' subobjects */ |
*stack_ptr = (void *)stack_desc->reference.node; |
} else { |
/* Get the object pointed to by the namespace node */ |
*stack_ptr = |
(stack_desc->reference.node)->object; |
acpi_ut_add_reference(*stack_ptr); |
} |
acpi_ut_remove_reference(stack_desc); |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown Reference type 0x%X in %p", |
ref_type, stack_desc)); |
status = AE_AML_INTERNAL; |
break; |
} |
break; |
case ACPI_TYPE_BUFFER: |
status = acpi_ds_get_buffer_arguments(stack_desc); |
break; |
case ACPI_TYPE_PACKAGE: |
status = acpi_ds_get_package_arguments(stack_desc); |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"FieldRead SourceDesc=%p Type=%X\n", |
stack_desc, stack_desc->common.type)); |
status = |
acpi_ex_read_data_from_field(walk_state, stack_desc, |
&obj_desc); |
/* Remove a reference to the original operand, then override */ |
acpi_ut_remove_reference(*stack_ptr); |
*stack_ptr = (void *)obj_desc; |
break; |
default: |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_resolve_multiple |
* |
* PARAMETERS: walk_state - Current state (contains AML opcode) |
* operand - Starting point for resolution |
* return_type - Where the object type is returned |
* return_desc - Where the resolved object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Return the base object and type. Traverse a reference list if |
* necessary to get to the base object. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, |
union acpi_operand_object *operand, |
acpi_object_type * return_type, |
union acpi_operand_object **return_desc) |
{ |
union acpi_operand_object *obj_desc = ACPI_CAST_PTR(void, operand); |
struct acpi_namespace_node *node = |
ACPI_CAST_PTR(struct acpi_namespace_node, operand); |
acpi_object_type type; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_ex_resolve_multiple); |
/* Operand can be either a namespace node or an operand descriptor */ |
switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
case ACPI_DESC_TYPE_OPERAND: |
type = obj_desc->common.type; |
break; |
case ACPI_DESC_TYPE_NAMED: |
type = ((struct acpi_namespace_node *)obj_desc)->type; |
obj_desc = acpi_ns_get_attached_object(node); |
/* If we had an Alias node, use the attached object for type info */ |
if (type == ACPI_TYPE_LOCAL_ALIAS) { |
type = ((struct acpi_namespace_node *)obj_desc)->type; |
obj_desc = |
acpi_ns_get_attached_object((struct |
acpi_namespace_node *) |
obj_desc); |
} |
if (!obj_desc) { |
ACPI_ERROR((AE_INFO, |
"[%4.4s] Node is unresolved or uninitialized", |
acpi_ut_get_node_name(node))); |
return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); |
} |
break; |
default: |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* If type is anything other than a reference, we are done */ |
if (type != ACPI_TYPE_LOCAL_REFERENCE) { |
goto exit; |
} |
/* |
* For reference objects created via the ref_of, Index, or Load/load_table |
* operators, we need to get to the base object (as per the ACPI |
* specification of the object_type and size_of operators). This means |
* traversing the list of possibly many nested references. |
*/ |
while (obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) { |
switch (obj_desc->reference.class) { |
case ACPI_REFCLASS_REFOF: |
case ACPI_REFCLASS_NAME: |
/* Dereference the reference pointer */ |
if (obj_desc->reference.class == ACPI_REFCLASS_REFOF) { |
node = obj_desc->reference.object; |
} else { /* AML_INT_NAMEPATH_OP */ |
node = obj_desc->reference.node; |
} |
/* All "References" point to a NS node */ |
if (ACPI_GET_DESCRIPTOR_TYPE(node) != |
ACPI_DESC_TYPE_NAMED) { |
ACPI_ERROR((AE_INFO, |
"Not a namespace node %p [%s]", |
node, |
acpi_ut_get_descriptor_name(node))); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* Get the attached object */ |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
/* No object, use the NS node type */ |
type = acpi_ns_get_type(node); |
goto exit; |
} |
/* Check for circular references */ |
if (obj_desc == operand) { |
return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE); |
} |
break; |
case ACPI_REFCLASS_INDEX: |
/* Get the type of this reference (index into another object) */ |
type = obj_desc->reference.target_type; |
if (type != ACPI_TYPE_PACKAGE) { |
goto exit; |
} |
/* |
* The main object is a package, we want to get the type |
* of the individual package element that is referenced by |
* the index. |
* |
* This could of course in turn be another reference object. |
*/ |
obj_desc = *(obj_desc->reference.where); |
if (!obj_desc) { |
/* NULL package elements are allowed */ |
type = 0; /* Uninitialized */ |
goto exit; |
} |
break; |
case ACPI_REFCLASS_TABLE: |
type = ACPI_TYPE_DDB_HANDLE; |
goto exit; |
case ACPI_REFCLASS_LOCAL: |
case ACPI_REFCLASS_ARG: |
if (return_desc) { |
status = |
acpi_ds_method_data_get_value(obj_desc-> |
reference. |
class, |
obj_desc-> |
reference. |
value, |
walk_state, |
&obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_ut_remove_reference(obj_desc); |
} else { |
status = |
acpi_ds_method_data_get_node(obj_desc-> |
reference. |
class, |
obj_desc-> |
reference. |
value, |
walk_state, |
&node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
type = ACPI_TYPE_ANY; |
goto exit; |
} |
} |
break; |
case ACPI_REFCLASS_DEBUG: |
/* The Debug Object is of type "DebugObject" */ |
type = ACPI_TYPE_DEBUG_OBJECT; |
goto exit; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown Reference Class 0x%2.2X", |
obj_desc->reference.class)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
} |
/* |
* Now we are guaranteed to have an object that has not been created |
* via the ref_of or Index operators. |
*/ |
type = obj_desc->common.type; |
exit: |
/* Convert internal types to external types */ |
switch (type) { |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
type = ACPI_TYPE_FIELD_UNIT; |
break; |
case ACPI_TYPE_LOCAL_SCOPE: |
/* Per ACPI Specification, Scope is untyped */ |
type = ACPI_TYPE_ANY; |
break; |
default: |
/* No change to Type required */ |
break; |
} |
*return_type = type; |
if (return_desc) { |
*return_desc = obj_desc; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/exresop.c |
---|
0,0 → 1,703 |
/****************************************************************************** |
* |
* Module Name: exresop - AML Interpreter operand/object resolution |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acparser.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exresop") |
/* Local prototypes */ |
static acpi_status |
acpi_ex_check_object_type(acpi_object_type type_needed, |
acpi_object_type this_type, void *object); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_check_object_type |
* |
* PARAMETERS: type_needed Object type needed |
* this_type Actual object type |
* Object Object pointer |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check required type against actual type |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_check_object_type(acpi_object_type type_needed, |
acpi_object_type this_type, void *object) |
{ |
ACPI_FUNCTION_ENTRY(); |
if (type_needed == ACPI_TYPE_ANY) { |
/* All types OK, so we don't perform any typechecks */ |
return (AE_OK); |
} |
if (type_needed == ACPI_TYPE_LOCAL_REFERENCE) { |
/* |
* Allow the AML "Constant" opcodes (Zero, One, etc.) to be reference |
* objects and thus allow them to be targets. (As per the ACPI |
* specification, a store to a constant is a noop.) |
*/ |
if ((this_type == ACPI_TYPE_INTEGER) && |
(((union acpi_operand_object *)object)->common. |
flags & AOPOBJ_AML_CONSTANT)) { |
return (AE_OK); |
} |
} |
if (type_needed != this_type) { |
ACPI_ERROR((AE_INFO, |
"Needed type [%s], found [%s] %p", |
acpi_ut_get_type_name(type_needed), |
acpi_ut_get_type_name(this_type), object)); |
return (AE_AML_OPERAND_TYPE); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_resolve_operands |
* |
* PARAMETERS: opcode - Opcode being interpreted |
* stack_ptr - Pointer to the operand stack to be |
* resolved |
* walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert multiple input operands to the types required by the |
* target operator. |
* |
* Each 5-bit group in arg_types represents one required |
* operand and indicates the required Type. The corresponding operand |
* will be converted to the required type if possible, otherwise we |
* abort with an exception. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_resolve_operands(u16 opcode, |
union acpi_operand_object ** stack_ptr, |
struct acpi_walk_state * walk_state) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status = AE_OK; |
u8 object_type; |
u32 arg_types; |
const struct acpi_opcode_info *op_info; |
u32 this_arg_type; |
acpi_object_type type_needed; |
u16 target_op = 0; |
ACPI_FUNCTION_TRACE_U32(ex_resolve_operands, opcode); |
op_info = acpi_ps_get_opcode_info(opcode); |
if (op_info->class == AML_CLASS_UNKNOWN) { |
return_ACPI_STATUS(AE_AML_BAD_OPCODE); |
} |
arg_types = op_info->runtime_args; |
if (arg_types == ARGI_INVALID_OPCODE) { |
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", opcode)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Opcode %X [%s] RequiredOperandTypes=%8.8X\n", |
opcode, op_info->name, arg_types)); |
/* |
* Normal exit is with (arg_types == 0) at end of argument list. |
* Function will return an exception from within the loop upon |
* finding an entry which is not (or cannot be converted |
* to) the required type; if stack underflows; or upon |
* finding a NULL stack entry (which should not happen). |
*/ |
while (GET_CURRENT_ARG_TYPE(arg_types)) { |
if (!stack_ptr || !*stack_ptr) { |
ACPI_ERROR((AE_INFO, "Null stack entry at %p", |
stack_ptr)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* Extract useful items */ |
obj_desc = *stack_ptr; |
/* Decode the descriptor type */ |
switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
case ACPI_DESC_TYPE_NAMED: |
/* Namespace Node */ |
object_type = |
((struct acpi_namespace_node *)obj_desc)->type; |
/* |
* Resolve an alias object. The construction of these objects |
* guarantees that there is only one level of alias indirection; |
* thus, the attached object is always the aliased namespace node |
*/ |
if (object_type == ACPI_TYPE_LOCAL_ALIAS) { |
obj_desc = |
acpi_ns_get_attached_object((struct |
acpi_namespace_node |
*)obj_desc); |
*stack_ptr = obj_desc; |
object_type = |
((struct acpi_namespace_node *)obj_desc)-> |
type; |
} |
break; |
case ACPI_DESC_TYPE_OPERAND: |
/* ACPI internal object */ |
object_type = obj_desc->common.type; |
/* Check for bad acpi_object_type */ |
if (!acpi_ut_valid_object_type(object_type)) { |
ACPI_ERROR((AE_INFO, |
"Bad operand object type [0x%X]", |
object_type)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) { |
/* Validate the Reference */ |
switch (obj_desc->reference.class) { |
case ACPI_REFCLASS_DEBUG: |
target_op = AML_DEBUG_OP; |
/*lint -fallthrough */ |
case ACPI_REFCLASS_ARG: |
case ACPI_REFCLASS_LOCAL: |
case ACPI_REFCLASS_INDEX: |
case ACPI_REFCLASS_REFOF: |
case ACPI_REFCLASS_TABLE: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */ |
case ACPI_REFCLASS_NAME: /* Reference to a named object */ |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Operand is a Reference, Class [%s] %2.2X\n", |
acpi_ut_get_reference_name |
(obj_desc), |
obj_desc->reference. |
class)); |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unknown Reference Class 0x%2.2X in %p", |
obj_desc->reference.class, |
obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
} |
break; |
default: |
/* Invalid descriptor */ |
ACPI_ERROR((AE_INFO, "Invalid descriptor %p [%s]", |
obj_desc, |
acpi_ut_get_descriptor_name(obj_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* Get one argument type, point to the next */ |
this_arg_type = GET_CURRENT_ARG_TYPE(arg_types); |
INCREMENT_ARG_LIST(arg_types); |
/* |
* Handle cases where the object does not need to be |
* resolved to a value |
*/ |
switch (this_arg_type) { |
case ARGI_REF_OR_STRING: /* Can be a String or Reference */ |
if ((ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == |
ACPI_DESC_TYPE_OPERAND) |
&& (obj_desc->common.type == ACPI_TYPE_STRING)) { |
/* |
* String found - the string references a named object and |
* must be resolved to a node |
*/ |
goto next_operand; |
} |
/* |
* Else not a string - fall through to the normal Reference |
* case below |
*/ |
/*lint -fallthrough */ |
case ARGI_REFERENCE: /* References: */ |
case ARGI_INTEGER_REF: |
case ARGI_OBJECT_REF: |
case ARGI_DEVICE_REF: |
case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ |
case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ |
case ARGI_SIMPLE_TARGET: /* Name, Local, or arg - no implicit conversion */ |
case ARGI_STORE_TARGET: |
/* |
* Need an operand of type ACPI_TYPE_LOCAL_REFERENCE |
* A Namespace Node is OK as-is |
*/ |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == |
ACPI_DESC_TYPE_NAMED) { |
goto next_operand; |
} |
status = |
acpi_ex_check_object_type(ACPI_TYPE_LOCAL_REFERENCE, |
object_type, obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
goto next_operand; |
case ARGI_DATAREFOBJ: /* Store operator only */ |
/* |
* We don't want to resolve index_op reference objects during |
* a store because this would be an implicit de_ref_of operation. |
* Instead, we just want to store the reference object. |
* -- All others must be resolved below. |
*/ |
if ((opcode == AML_STORE_OP) && |
((*stack_ptr)->common.type == |
ACPI_TYPE_LOCAL_REFERENCE) |
&& ((*stack_ptr)->reference.class == |
ACPI_REFCLASS_INDEX)) { |
goto next_operand; |
} |
break; |
default: |
/* All cases covered above */ |
break; |
} |
/* |
* Resolve this object to a value |
*/ |
status = acpi_ex_resolve_to_value(stack_ptr, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get the resolved object */ |
obj_desc = *stack_ptr; |
/* |
* Check the resulting object (value) type |
*/ |
switch (this_arg_type) { |
/* |
* For the simple cases, only one type of resolved object |
* is allowed |
*/ |
case ARGI_MUTEX: |
/* Need an operand of type ACPI_TYPE_MUTEX */ |
type_needed = ACPI_TYPE_MUTEX; |
break; |
case ARGI_EVENT: |
/* Need an operand of type ACPI_TYPE_EVENT */ |
type_needed = ACPI_TYPE_EVENT; |
break; |
case ARGI_PACKAGE: /* Package */ |
/* Need an operand of type ACPI_TYPE_PACKAGE */ |
type_needed = ACPI_TYPE_PACKAGE; |
break; |
case ARGI_ANYTYPE: |
/* Any operand type will do */ |
type_needed = ACPI_TYPE_ANY; |
break; |
case ARGI_DDBHANDLE: |
/* Need an operand of type ACPI_TYPE_DDB_HANDLE */ |
type_needed = ACPI_TYPE_LOCAL_REFERENCE; |
break; |
/* |
* The more complex cases allow multiple resolved object types |
*/ |
case ARGI_INTEGER: |
/* |
* Need an operand of type ACPI_TYPE_INTEGER, |
* But we can implicitly convert from a STRING or BUFFER |
* aka - "Implicit Source Operand Conversion" |
*/ |
status = |
acpi_ex_convert_to_integer(obj_desc, stack_ptr, 16); |
if (ACPI_FAILURE(status)) { |
if (status == AE_TYPE) { |
ACPI_ERROR((AE_INFO, |
"Needed [Integer/String/Buffer], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
return_ACPI_STATUS(status); |
} |
if (obj_desc != *stack_ptr) { |
acpi_ut_remove_reference(obj_desc); |
} |
goto next_operand; |
case ARGI_BUFFER: |
/* |
* Need an operand of type ACPI_TYPE_BUFFER, |
* But we can implicitly convert from a STRING or INTEGER |
* aka - "Implicit Source Operand Conversion" |
*/ |
status = acpi_ex_convert_to_buffer(obj_desc, stack_ptr); |
if (ACPI_FAILURE(status)) { |
if (status == AE_TYPE) { |
ACPI_ERROR((AE_INFO, |
"Needed [Integer/String/Buffer], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
return_ACPI_STATUS(status); |
} |
if (obj_desc != *stack_ptr) { |
acpi_ut_remove_reference(obj_desc); |
} |
goto next_operand; |
case ARGI_STRING: |
/* |
* Need an operand of type ACPI_TYPE_STRING, |
* But we can implicitly convert from a BUFFER or INTEGER |
* aka - "Implicit Source Operand Conversion" |
*/ |
status = acpi_ex_convert_to_string(obj_desc, stack_ptr, |
ACPI_IMPLICIT_CONVERT_HEX); |
if (ACPI_FAILURE(status)) { |
if (status == AE_TYPE) { |
ACPI_ERROR((AE_INFO, |
"Needed [Integer/String/Buffer], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
return_ACPI_STATUS(status); |
} |
if (obj_desc != *stack_ptr) { |
acpi_ut_remove_reference(obj_desc); |
} |
goto next_operand; |
case ARGI_COMPUTEDATA: |
/* Need an operand of type INTEGER, STRING or BUFFER */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
/* Valid operand */ |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Needed [Integer/String/Buffer], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
goto next_operand; |
case ARGI_BUFFER_OR_STRING: |
/* Need an operand of type STRING or BUFFER */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
/* Valid operand */ |
break; |
case ACPI_TYPE_INTEGER: |
/* Highest priority conversion is to type Buffer */ |
status = |
acpi_ex_convert_to_buffer(obj_desc, |
stack_ptr); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (obj_desc != *stack_ptr) { |
acpi_ut_remove_reference(obj_desc); |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Needed [Integer/String/Buffer], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
goto next_operand; |
case ARGI_DATAOBJECT: |
/* |
* ARGI_DATAOBJECT is only used by the size_of operator. |
* Need a buffer, string, package, or ref_of reference. |
* |
* The only reference allowed here is a direct reference to |
* a namespace node. |
*/ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_PACKAGE: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_LOCAL_REFERENCE: |
/* Valid operand */ |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Needed [Buffer/String/Package/Reference], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
goto next_operand; |
case ARGI_COMPLEXOBJ: |
/* Need a buffer or package or (ACPI 2.0) String */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_PACKAGE: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
/* Valid operand */ |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Needed [Buffer/String/Package], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
goto next_operand; |
case ARGI_REGION_OR_BUFFER: /* Used by Load() only */ |
/* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_REGION: |
/* Valid operand */ |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Needed [Region/Buffer], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
goto next_operand; |
case ARGI_DATAREFOBJ: |
/* Used by the Store() operator only */ |
switch (obj_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_PACKAGE: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REFERENCE: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
case ACPI_TYPE_DDB_HANDLE: |
/* Valid operand */ |
break; |
default: |
if (acpi_gbl_enable_interpreter_slack) { |
/* |
* Enable original behavior of Store(), allowing any and all |
* objects as the source operand. The ACPI spec does not |
* allow this, however. |
*/ |
break; |
} |
if (target_op == AML_DEBUG_OP) { |
/* Allow store of any object to the Debug object */ |
break; |
} |
ACPI_ERROR((AE_INFO, |
"Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p", |
acpi_ut_get_object_type_name |
(obj_desc), obj_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
goto next_operand; |
default: |
/* Unknown type */ |
ACPI_ERROR((AE_INFO, |
"Internal - Unknown ARGI (required operand) type 0x%X", |
this_arg_type)); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* Make sure that the original object was resolved to the |
* required object type (Simple cases only). |
*/ |
status = acpi_ex_check_object_type(type_needed, |
(*stack_ptr)->common.type, |
*stack_ptr); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
next_operand: |
/* |
* If more operands needed, decrement stack_ptr to point |
* to next operand on stack |
*/ |
if (GET_CURRENT_ARG_TYPE(arg_types)) { |
stack_ptr--; |
} |
} |
ACPI_DUMP_OPERANDS(walk_state->operands, |
acpi_ps_get_opcode_name(opcode), |
walk_state->num_operands); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exstore.c |
---|
0,0 → 1,619 |
/****************************************************************************** |
* |
* Module Name: exstore - AML Interpreter object store support |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exstore") |
/* Local prototypes */ |
static acpi_status |
acpi_ex_store_object_to_index(union acpi_operand_object *val_desc, |
union acpi_operand_object *dest_desc, |
struct acpi_walk_state *walk_state); |
static acpi_status |
acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc, |
struct acpi_namespace_node *node, |
struct acpi_walk_state *walk_state); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_store |
* |
* PARAMETERS: *source_desc - Value to be stored |
* *dest_desc - Where to store it. Must be an NS node |
* or union acpi_operand_object of type |
* Reference; |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Store the value described by source_desc into the location |
* described by dest_desc. Called by various interpreter |
* functions to store the result of an operation into |
* the destination operand -- not just simply the actual "Store" |
* ASL operator. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_store(union acpi_operand_object *source_desc, |
union acpi_operand_object *dest_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *ref_desc = dest_desc; |
ACPI_FUNCTION_TRACE_PTR(ex_store, dest_desc); |
/* Validate parameters */ |
if (!source_desc || !dest_desc) { |
ACPI_ERROR((AE_INFO, "Null parameter")); |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
/* dest_desc can be either a namespace node or an ACPI object */ |
if (ACPI_GET_DESCRIPTOR_TYPE(dest_desc) == ACPI_DESC_TYPE_NAMED) { |
/* |
* Dest is a namespace node, |
* Storing an object into a Named node. |
*/ |
status = acpi_ex_store_object_to_node(source_desc, |
(struct |
acpi_namespace_node *) |
dest_desc, walk_state, |
ACPI_IMPLICIT_CONVERSION); |
return_ACPI_STATUS(status); |
} |
/* Destination object must be a Reference or a Constant object */ |
switch (dest_desc->common.type) { |
case ACPI_TYPE_LOCAL_REFERENCE: |
break; |
case ACPI_TYPE_INTEGER: |
/* Allow stores to Constants -- a Noop as per ACPI spec */ |
if (dest_desc->common.flags & AOPOBJ_AML_CONSTANT) { |
return_ACPI_STATUS(AE_OK); |
} |
/*lint -fallthrough */ |
default: |
/* Destination is not a Reference object */ |
ACPI_ERROR((AE_INFO, |
"Target is not a Reference or Constant object - [%s] %p", |
acpi_ut_get_object_type_name(dest_desc), |
dest_desc)); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* |
* Examine the Reference class. These cases are handled: |
* |
* 1) Store to Name (Change the object associated with a name) |
* 2) Store to an indexed area of a Buffer or Package |
* 3) Store to a Method Local or Arg |
* 4) Store to the debug object |
*/ |
switch (ref_desc->reference.class) { |
case ACPI_REFCLASS_REFOF: |
/* Storing an object into a Name "container" */ |
status = acpi_ex_store_object_to_node(source_desc, |
ref_desc->reference. |
object, walk_state, |
ACPI_IMPLICIT_CONVERSION); |
break; |
case ACPI_REFCLASS_INDEX: |
/* Storing to an Index (pointer into a packager or buffer) */ |
status = |
acpi_ex_store_object_to_index(source_desc, ref_desc, |
walk_state); |
break; |
case ACPI_REFCLASS_LOCAL: |
case ACPI_REFCLASS_ARG: |
/* Store to a method local/arg */ |
status = |
acpi_ds_store_object_to_local(ref_desc->reference.class, |
ref_desc->reference.value, |
source_desc, walk_state); |
break; |
case ACPI_REFCLASS_DEBUG: |
/* |
* Storing to the Debug object causes the value stored to be |
* displayed and otherwise has no effect -- see ACPI Specification |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"**** Write to Debug Object: Object %p [%s] ****:\n\n", |
source_desc, |
acpi_ut_get_object_type_name(source_desc))); |
ACPI_DEBUG_OBJECT(source_desc, 0, 0); |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown Reference Class 0x%2.2X", |
ref_desc->reference.class)); |
ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_INFO); |
status = AE_AML_INTERNAL; |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_store_object_to_index |
* |
* PARAMETERS: *source_desc - Value to be stored |
* *dest_desc - Named object to receive the value |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Store the object to indexed Buffer or Package element |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, |
union acpi_operand_object *index_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *new_desc; |
u8 value = 0; |
u32 i; |
ACPI_FUNCTION_TRACE(ex_store_object_to_index); |
/* |
* Destination must be a reference pointer, and |
* must point to either a buffer or a package |
*/ |
switch (index_desc->reference.target_type) { |
case ACPI_TYPE_PACKAGE: |
/* |
* Storing to a package element. Copy the object and replace |
* any existing object with the new object. No implicit |
* conversion is performed. |
* |
* The object at *(index_desc->Reference.Where) is the |
* element within the package that is to be modified. |
* The parent package object is at index_desc->Reference.Object |
*/ |
obj_desc = *(index_desc->reference.where); |
if (source_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE && |
source_desc->reference.class == ACPI_REFCLASS_TABLE) { |
/* This is a DDBHandle, just add a reference to it */ |
acpi_ut_add_reference(source_desc); |
new_desc = source_desc; |
} else { |
/* Normal object, copy it */ |
status = |
acpi_ut_copy_iobject_to_iobject(source_desc, |
&new_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
if (obj_desc) { |
/* Decrement reference count by the ref count of the parent package */ |
for (i = 0; i < ((union acpi_operand_object *) |
index_desc->reference.object)->common. |
reference_count; i++) { |
acpi_ut_remove_reference(obj_desc); |
} |
} |
*(index_desc->reference.where) = new_desc; |
/* Increment ref count by the ref count of the parent package-1 */ |
for (i = 1; i < ((union acpi_operand_object *) |
index_desc->reference.object)->common. |
reference_count; i++) { |
acpi_ut_add_reference(new_desc); |
} |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
/* |
* Store into a Buffer or String (not actually a real buffer_field) |
* at a location defined by an Index. |
* |
* The first 8-bit element of the source object is written to the |
* 8-bit Buffer location defined by the Index destination object, |
* according to the ACPI 2.0 specification. |
*/ |
/* |
* Make sure the target is a Buffer or String. An error should |
* not happen here, since the reference_object was constructed |
* by the INDEX_OP code. |
*/ |
obj_desc = index_desc->reference.object; |
if ((obj_desc->common.type != ACPI_TYPE_BUFFER) && |
(obj_desc->common.type != ACPI_TYPE_STRING)) { |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* |
* The assignment of the individual elements will be slightly |
* different for each source type. |
*/ |
switch (source_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
/* Use the least-significant byte of the integer */ |
value = (u8) (source_desc->integer.value); |
break; |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_STRING: |
/* Note: Takes advantage of common string/buffer fields */ |
value = source_desc->buffer.pointer[0]; |
break; |
default: |
/* All other types are invalid */ |
ACPI_ERROR((AE_INFO, |
"Source must be type [Integer/Buffer/String], found [%s]", |
acpi_ut_get_object_type_name(source_desc))); |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* Store the source value into the target buffer byte */ |
obj_desc->buffer.pointer[index_desc->reference.value] = value; |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Target is not of type [Package/BufferField]")); |
status = AE_AML_TARGET_TYPE; |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_store_object_to_node |
* |
* PARAMETERS: source_desc - Value to be stored |
* node - Named object to receive the value |
* walk_state - Current walk state |
* implicit_conversion - Perform implicit conversion (yes/no) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Store the object to the named object. |
* |
* The assignment of an object to a named object is handled here. |
* The value passed in will replace the current value (if any) |
* with the input value. |
* |
* When storing into an object the data is converted to the |
* target object type then stored in the object. This means |
* that the target object type (for an initialized target) will |
* not be changed by a store operation. A copy_object can change |
* the target type, however. |
* |
* The implicit_conversion flag is set to NO/FALSE only when |
* storing to an arg_x -- as per the rules of the ACPI spec. |
* |
* Assumes parameters are already validated. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, |
struct acpi_namespace_node *node, |
struct acpi_walk_state *walk_state, |
u8 implicit_conversion) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *target_desc; |
union acpi_operand_object *new_desc; |
acpi_object_type target_type; |
ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_node, source_desc); |
/* Get current type of the node, and object attached to Node */ |
target_type = acpi_ns_get_type(node); |
target_desc = acpi_ns_get_attached_object(node); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p [%s] to node %p [%s]\n", |
source_desc, |
acpi_ut_get_object_type_name(source_desc), node, |
acpi_ut_get_type_name(target_type))); |
/* Only limited target types possible for everything except copy_object */ |
if (walk_state->opcode != AML_COPY_OP) { |
/* |
* Only copy_object allows all object types to be overwritten. For |
* target_ref(s), there are restrictions on the object types that |
* are allowed. |
* |
* Allowable operations/typing for Store: |
* |
* 1) Simple Store |
* Integer --> Integer (Named/Local/Arg) |
* String --> String (Named/Local/Arg) |
* Buffer --> Buffer (Named/Local/Arg) |
* Package --> Package (Named/Local/Arg) |
* |
* 2) Store with implicit conversion |
* Integer --> String or Buffer (Named) |
* String --> Integer or Buffer (Named) |
* Buffer --> Integer or String (Named) |
*/ |
switch (target_type) { |
case ACPI_TYPE_PACKAGE: |
/* |
* Here, can only store a package to an existing package. |
* Storing a package to a Local/Arg is OK, and handled |
* elsewhere. |
*/ |
if (walk_state->opcode == AML_STORE_OP) { |
if (source_desc->common.type != |
ACPI_TYPE_PACKAGE) { |
ACPI_ERROR((AE_INFO, |
"Cannot assign type [%s] to [Package] " |
"(source must be type Pkg)", |
acpi_ut_get_object_type_name |
(source_desc))); |
return_ACPI_STATUS(AE_AML_TARGET_TYPE); |
} |
break; |
} |
/* Fallthrough */ |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_EVENT: |
case ACPI_TYPE_MUTEX: |
case ACPI_TYPE_REGION: |
case ACPI_TYPE_POWER: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_THERMAL: |
ACPI_ERROR((AE_INFO, |
"Target must be [Buffer/Integer/String/Reference], found [%s] (%4.4s)", |
acpi_ut_get_type_name(node->type), |
node->name.ascii)); |
return_ACPI_STATUS(AE_AML_TARGET_TYPE); |
default: |
break; |
} |
} |
/* |
* Resolve the source object to an actual value |
* (If it is a reference object) |
*/ |
status = acpi_ex_resolve_object(&source_desc, target_type, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Do the actual store operation */ |
switch (target_type) { |
/* |
* The simple data types all support implicit source operand |
* conversion before the store. |
*/ |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) { |
/* |
* However, copy_object and Stores to arg_x do not perform |
* an implicit conversion, as per the ACPI specification. |
* A direct store is performed instead. |
*/ |
status = acpi_ex_store_direct_to_node(source_desc, node, |
walk_state); |
break; |
} |
/* Store with implicit source operand conversion support */ |
status = |
acpi_ex_store_object_to_object(source_desc, target_desc, |
&new_desc, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (new_desc != target_desc) { |
/* |
* Store the new new_desc as the new value of the Name, and set |
* the Name's type to that of the value being stored in it. |
* source_desc reference count is incremented by attach_object. |
* |
* Note: This may change the type of the node if an explicit |
* store has been performed such that the node/object type |
* has been changed. |
*/ |
status = acpi_ns_attach_object(node, new_desc, |
new_desc->common.type); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Store type [%s] into [%s] via Convert/Attach\n", |
acpi_ut_get_object_type_name |
(source_desc), |
acpi_ut_get_object_type_name |
(new_desc))); |
} |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
/* |
* For all fields, always write the source data to the target |
* field. Any required implicit source operand conversion is |
* performed in the function below as necessary. Note, field |
* objects must retain their original type permanently. |
*/ |
status = acpi_ex_write_data_to_field(source_desc, target_desc, |
&walk_state->result_obj); |
break; |
default: |
/* |
* copy_object operator: No conversions for all other types. |
* Instead, directly store a copy of the source object. |
* |
* This is the ACPI spec-defined behavior for the copy_object |
* operator. (Note, for this default case, all normal |
* Store/Target operations exited above with an error). |
*/ |
status = acpi_ex_store_direct_to_node(source_desc, node, |
walk_state); |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_store_direct_to_node |
* |
* PARAMETERS: source_desc - Value to be stored |
* node - Named object to receive the value |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: "Store" an object directly to a node. This involves a copy |
* and an attach. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc, |
struct acpi_namespace_node *node, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
union acpi_operand_object *new_desc; |
ACPI_FUNCTION_TRACE(ex_store_direct_to_node); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Storing [%s] (%p) directly into node [%s] (%p)" |
" with no implicit conversion\n", |
acpi_ut_get_object_type_name(source_desc), |
source_desc, acpi_ut_get_type_name(node->type), |
node)); |
/* Copy the source object to a new object */ |
status = |
acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Attach the new object to the node */ |
status = acpi_ns_attach_object(node, new_desc, new_desc->common.type); |
acpi_ut_remove_reference(new_desc); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exstoren.c |
---|
0,0 → 1,295 |
/****************************************************************************** |
* |
* Module Name: exstoren - AML Interpreter object store support, |
* Store to Node (namespace object) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exstoren") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_resolve_object |
* |
* PARAMETERS: source_desc_ptr - Pointer to the source object |
* target_type - Current type of the target |
* walk_state - Current walk state |
* |
* RETURN: Status, resolved object in source_desc_ptr. |
* |
* DESCRIPTION: Resolve an object. If the object is a reference, dereference |
* it and return the actual object in the source_desc_ptr. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, |
acpi_object_type target_type, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object *source_desc = *source_desc_ptr; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_resolve_object); |
/* Ensure we have a Target that can be stored to */ |
switch (target_type) { |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
/* |
* These cases all require only Integers or values that |
* can be converted to Integers (Strings or Buffers) |
*/ |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
/* |
* Stores into a Field/Region or into a Integer/Buffer/String |
* are all essentially the same. This case handles the |
* "interchangeable" types Integer, String, and Buffer. |
*/ |
if (source_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) { |
/* Resolve a reference object first */ |
status = |
acpi_ex_resolve_to_value(source_desc_ptr, |
walk_state); |
if (ACPI_FAILURE(status)) { |
break; |
} |
} |
/* For copy_object, no further validation necessary */ |
if (walk_state->opcode == AML_COPY_OP) { |
break; |
} |
/* Must have a Integer, Buffer, or String */ |
if ((source_desc->common.type != ACPI_TYPE_INTEGER) && |
(source_desc->common.type != ACPI_TYPE_BUFFER) && |
(source_desc->common.type != ACPI_TYPE_STRING) && |
!((source_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && |
(source_desc->reference.class == ACPI_REFCLASS_TABLE))) { |
/* Conversion successful but still not a valid type */ |
ACPI_ERROR((AE_INFO, |
"Cannot assign type [%s] to [%s] (must be type Int/Str/Buf)", |
acpi_ut_get_object_type_name(source_desc), |
acpi_ut_get_type_name(target_type))); |
status = AE_AML_OPERAND_TYPE; |
} |
break; |
case ACPI_TYPE_LOCAL_ALIAS: |
case ACPI_TYPE_LOCAL_METHOD_ALIAS: |
/* |
* All aliases should have been resolved earlier, during the |
* operand resolution phase. |
*/ |
ACPI_ERROR((AE_INFO, "Store into an unresolved Alias object")); |
status = AE_AML_INTERNAL; |
break; |
case ACPI_TYPE_PACKAGE: |
default: |
/* |
* All other types than Alias and the various Fields come here, |
* including the untyped case - ACPI_TYPE_ANY. |
*/ |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_store_object_to_object |
* |
* PARAMETERS: source_desc - Object to store |
* dest_desc - Object to receive a copy of the source |
* new_desc - New object if dest_desc is obsoleted |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: "Store" an object to another object. This may include |
* converting the source type to the target type (implicit |
* conversion), and a copy of the value of the source to |
* the target. |
* |
* The Assignment of an object to another (not named) object |
* is handled here. |
* The Source passed in will replace the current value (if any) |
* with the input value. |
* |
* When storing into an object the data is converted to the |
* target object type then stored in the object. This means |
* that the target object type (for an initialized target) will |
* not be changed by a store operation. |
* |
* This module allows destination types of Number, String, |
* Buffer, and Package. |
* |
* Assumes parameters are already validated. NOTE: source_desc |
* resolution (from a reference object) must be performed by |
* the caller if necessary. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_store_object_to_object(union acpi_operand_object *source_desc, |
union acpi_operand_object *dest_desc, |
union acpi_operand_object **new_desc, |
struct acpi_walk_state *walk_state) |
{ |
union acpi_operand_object *actual_src_desc; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_object, source_desc); |
actual_src_desc = source_desc; |
if (!dest_desc) { |
/* |
* There is no destination object (An uninitialized node or |
* package element), so we can simply copy the source object |
* creating a new destination object |
*/ |
status = |
acpi_ut_copy_iobject_to_iobject(actual_src_desc, new_desc, |
walk_state); |
return_ACPI_STATUS(status); |
} |
if (source_desc->common.type != dest_desc->common.type) { |
/* |
* The source type does not match the type of the destination. |
* Perform the "implicit conversion" of the source to the current type |
* of the target as per the ACPI specification. |
* |
* If no conversion performed, actual_src_desc = source_desc. |
* Otherwise, actual_src_desc is a temporary object to hold the |
* converted object. |
*/ |
status = acpi_ex_convert_to_target_type(dest_desc->common.type, |
source_desc, |
&actual_src_desc, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (source_desc == actual_src_desc) { |
/* |
* No conversion was performed. Return the source_desc as the |
* new object. |
*/ |
*new_desc = source_desc; |
return_ACPI_STATUS(AE_OK); |
} |
} |
/* |
* We now have two objects of identical types, and we can perform a |
* copy of the *value* of the source object. |
*/ |
switch (dest_desc->common.type) { |
case ACPI_TYPE_INTEGER: |
dest_desc->integer.value = actual_src_desc->integer.value; |
/* Truncate value if we are executing from a 32-bit ACPI table */ |
(void)acpi_ex_truncate_for32bit_table(dest_desc); |
break; |
case ACPI_TYPE_STRING: |
status = |
acpi_ex_store_string_to_string(actual_src_desc, dest_desc); |
break; |
case ACPI_TYPE_BUFFER: |
status = |
acpi_ex_store_buffer_to_buffer(actual_src_desc, dest_desc); |
break; |
case ACPI_TYPE_PACKAGE: |
status = |
acpi_ut_copy_iobject_to_iobject(actual_src_desc, &dest_desc, |
walk_state); |
break; |
default: |
/* |
* All other types come here. |
*/ |
ACPI_WARNING((AE_INFO, "Store into type [%s] not implemented", |
acpi_ut_get_object_type_name(dest_desc))); |
status = AE_NOT_IMPLEMENTED; |
break; |
} |
if (actual_src_desc != source_desc) { |
/* Delete the intermediate (temporary) source object */ |
acpi_ut_remove_reference(actual_src_desc); |
} |
*new_desc = dest_desc; |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/exstorob.c |
---|
0,0 → 1,220 |
/****************************************************************************** |
* |
* Module Name: exstorob - AML Interpreter object store support, store to object |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exstorob") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_store_buffer_to_buffer |
* |
* PARAMETERS: source_desc - Source object to copy |
* target_desc - Destination object of the copy |
* |
* RETURN: Status |
* |
* DESCRIPTION: Copy a buffer object to another buffer object. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, |
union acpi_operand_object *target_desc) |
{ |
u32 length; |
u8 *buffer; |
ACPI_FUNCTION_TRACE_PTR(ex_store_buffer_to_buffer, source_desc); |
/* If Source and Target are the same, just return */ |
if (source_desc == target_desc) { |
return_ACPI_STATUS(AE_OK); |
} |
/* We know that source_desc is a buffer by now */ |
buffer = ACPI_CAST_PTR(u8, source_desc->buffer.pointer); |
length = source_desc->buffer.length; |
/* |
* If target is a buffer of length zero or is a static buffer, |
* allocate a new buffer of the proper length |
*/ |
if ((target_desc->buffer.length == 0) || |
(target_desc->common.flags & AOPOBJ_STATIC_POINTER)) { |
target_desc->buffer.pointer = ACPI_ALLOCATE(length); |
if (!target_desc->buffer.pointer) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
target_desc->buffer.length = length; |
} |
/* Copy source buffer to target buffer */ |
if (length <= target_desc->buffer.length) { |
/* Clear existing buffer and copy in the new one */ |
memset(target_desc->buffer.pointer, 0, |
target_desc->buffer.length); |
memcpy(target_desc->buffer.pointer, buffer, length); |
#ifdef ACPI_OBSOLETE_BEHAVIOR |
/* |
* NOTE: ACPI versions up to 3.0 specified that the buffer must be |
* truncated if the string is smaller than the buffer. However, "other" |
* implementations of ACPI never did this and thus became the defacto |
* standard. ACPI 3.0A changes this behavior such that the buffer |
* is no longer truncated. |
*/ |
/* |
* OBSOLETE BEHAVIOR: |
* If the original source was a string, we must truncate the buffer, |
* according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer |
* copy must not truncate the original buffer. |
*/ |
if (original_src_type == ACPI_TYPE_STRING) { |
/* Set the new length of the target */ |
target_desc->buffer.length = length; |
} |
#endif |
} else { |
/* Truncate the source, copy only what will fit */ |
memcpy(target_desc->buffer.pointer, buffer, |
target_desc->buffer.length); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Truncating source buffer from %X to %X\n", |
length, target_desc->buffer.length)); |
} |
/* Copy flags */ |
target_desc->buffer.flags = source_desc->buffer.flags; |
target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_store_string_to_string |
* |
* PARAMETERS: source_desc - Source object to copy |
* target_desc - Destination object of the copy |
* |
* RETURN: Status |
* |
* DESCRIPTION: Copy a String object to another String object |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, |
union acpi_operand_object *target_desc) |
{ |
u32 length; |
u8 *buffer; |
ACPI_FUNCTION_TRACE_PTR(ex_store_string_to_string, source_desc); |
/* If Source and Target are the same, just return */ |
if (source_desc == target_desc) { |
return_ACPI_STATUS(AE_OK); |
} |
/* We know that source_desc is a string by now */ |
buffer = ACPI_CAST_PTR(u8, source_desc->string.pointer); |
length = source_desc->string.length; |
/* |
* Replace existing string value if it will fit and the string |
* pointer is not a static pointer (part of an ACPI table) |
*/ |
if ((length < target_desc->string.length) && |
(!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) { |
/* |
* String will fit in existing non-static buffer. |
* Clear old string and copy in the new one |
*/ |
memset(target_desc->string.pointer, 0, |
(acpi_size) target_desc->string.length + 1); |
memcpy(target_desc->string.pointer, buffer, length); |
} else { |
/* |
* Free the current buffer, then allocate a new buffer |
* large enough to hold the value |
*/ |
if (target_desc->string.pointer && |
(!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) { |
/* Only free if not a pointer into the DSDT */ |
ACPI_FREE(target_desc->string.pointer); |
} |
target_desc->string.pointer = ACPI_ALLOCATE_ZEROED((acpi_size) |
length + 1); |
if (!target_desc->string.pointer) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER; |
memcpy(target_desc->string.pointer, buffer, length); |
} |
/* Set the new target length */ |
target_desc->string.length = length; |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/exsystem.c |
---|
0,0 → 1,310 |
/****************************************************************************** |
* |
* Module Name: exsystem - Interface to OS services |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exsystem") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_wait_semaphore |
* |
* PARAMETERS: semaphore - Semaphore to wait on |
* timeout - Max time to wait |
* |
* RETURN: Status |
* |
* DESCRIPTION: Implements a semaphore wait with a check to see if the |
* semaphore is available immediately. If it is not, the |
* interpreter is released before waiting. |
* |
******************************************************************************/ |
acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ex_system_wait_semaphore); |
status = acpi_os_wait_semaphore(semaphore, 1, ACPI_DO_NOT_WAIT); |
if (ACPI_SUCCESS(status)) { |
return_ACPI_STATUS(status); |
} |
if (status == AE_TIME) { |
/* We must wait, so unlock the interpreter */ |
acpi_ex_exit_interpreter(); |
status = acpi_os_wait_semaphore(semaphore, 1, timeout); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"*** Thread awake after blocking, %s\n", |
acpi_format_exception(status))); |
/* Reacquire the interpreter */ |
acpi_ex_enter_interpreter(); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_wait_mutex |
* |
* PARAMETERS: mutex - Mutex to wait on |
* timeout - Max time to wait |
* |
* RETURN: Status |
* |
* DESCRIPTION: Implements a mutex wait with a check to see if the |
* mutex is available immediately. If it is not, the |
* interpreter is released before waiting. |
* |
******************************************************************************/ |
acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ex_system_wait_mutex); |
status = acpi_os_acquire_mutex(mutex, ACPI_DO_NOT_WAIT); |
if (ACPI_SUCCESS(status)) { |
return_ACPI_STATUS(status); |
} |
if (status == AE_TIME) { |
/* We must wait, so unlock the interpreter */ |
acpi_ex_exit_interpreter(); |
status = acpi_os_acquire_mutex(mutex, timeout); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"*** Thread awake after blocking, %s\n", |
acpi_format_exception(status))); |
/* Reacquire the interpreter */ |
acpi_ex_enter_interpreter(); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_do_stall |
* |
* PARAMETERS: how_long - The amount of time to stall, |
* in microseconds |
* |
* RETURN: Status |
* |
* DESCRIPTION: Suspend running thread for specified amount of time. |
* Note: ACPI specification requires that Stall() does not |
* relinquish the processor, and delays longer than 100 usec |
* should use Sleep() instead. We allow stalls up to 255 usec |
* for compatibility with other interpreters and existing BIOSs. |
* |
******************************************************************************/ |
acpi_status acpi_ex_system_do_stall(u32 how_long) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_ENTRY(); |
if (how_long > 255) { /* 255 microseconds */ |
/* |
* Longer than 255 usec, this is an error |
* |
* (ACPI specifies 100 usec as max, but this gives some slack in |
* order to support existing BIOSs) |
*/ |
ACPI_ERROR((AE_INFO, "Time parameter is too large (%u)", |
how_long)); |
status = AE_AML_OPERAND_VALUE; |
} else { |
acpi_os_stall(how_long); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_do_sleep |
* |
* PARAMETERS: how_long - The amount of time to sleep, |
* in milliseconds |
* |
* RETURN: None |
* |
* DESCRIPTION: Sleep the running thread for specified amount of time. |
* |
******************************************************************************/ |
acpi_status acpi_ex_system_do_sleep(u64 how_long) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Since this thread will sleep, we must release the interpreter */ |
acpi_ex_exit_interpreter(); |
/* |
* For compatibility with other ACPI implementations and to prevent |
* accidental deep sleeps, limit the sleep time to something reasonable. |
*/ |
if (how_long > ACPI_MAX_SLEEP) { |
how_long = ACPI_MAX_SLEEP; |
} |
acpi_os_sleep(how_long); |
/* And now we must get the interpreter again */ |
acpi_ex_enter_interpreter(); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_signal_event |
* |
* PARAMETERS: obj_desc - The object descriptor for this op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Provides an access point to perform synchronization operations |
* within the AML. |
* |
******************************************************************************/ |
acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_system_signal_event); |
if (obj_desc) { |
status = |
acpi_os_signal_semaphore(obj_desc->event.os_semaphore, 1); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_wait_event |
* |
* PARAMETERS: time_desc - The 'time to delay' object descriptor |
* obj_desc - The object descriptor for this op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Provides an access point to perform synchronization operations |
* within the AML. This operation is a request to wait for an |
* event. |
* |
******************************************************************************/ |
acpi_status |
acpi_ex_system_wait_event(union acpi_operand_object *time_desc, |
union acpi_operand_object *obj_desc) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ex_system_wait_event); |
if (obj_desc) { |
status = |
acpi_ex_system_wait_semaphore(obj_desc->event.os_semaphore, |
(u16) time_desc->integer. |
value); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_system_reset_event |
* |
* PARAMETERS: obj_desc - The object descriptor for this op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Reset an event to a known state. |
* |
******************************************************************************/ |
acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc) |
{ |
acpi_status status = AE_OK; |
acpi_semaphore temp_semaphore; |
ACPI_FUNCTION_ENTRY(); |
/* |
* We are going to simply delete the existing semaphore and |
* create a new one! |
*/ |
status = |
acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore); |
if (ACPI_SUCCESS(status)) { |
(void)acpi_os_delete_semaphore(obj_desc->event.os_semaphore); |
obj_desc->event.os_semaphore = temp_semaphore; |
} |
return (status); |
} |
/drivers/acpi/acpica/exutils.c |
---|
0,0 → 1,438 |
/****************************************************************************** |
* |
* Module Name: exutils - interpreter/scanner utilities |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
/* |
* DEFINE_AML_GLOBALS is tested in amlcode.h |
* to determine whether certain global names should be "defined" or only |
* "declared" in the current compilation. This enhances maintainability |
* by enabling a single header file to embody all knowledge of the names |
* in question. |
* |
* Exactly one module of any executable should #define DEFINE_GLOBALS |
* before #including the header files which use this convention. The |
* names in question will be defined and initialized in that module, |
* and declared as extern in all other modules which #include those |
* header files. |
*/ |
#define DEFINE_AML_GLOBALS |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_EXECUTER |
ACPI_MODULE_NAME("exutils") |
/* Local prototypes */ |
static u32 acpi_ex_digits_needed(u64 value, u32 base); |
#ifndef ACPI_NO_METHOD_EXECUTION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_enter_interpreter |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Enter the interpreter execution region. Failure to enter |
* the interpreter region is a fatal system error. Used in |
* conjunction with exit_interpreter. |
* |
******************************************************************************/ |
void acpi_ex_enter_interpreter(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ex_enter_interpreter); |
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not acquire AML Interpreter mutex")); |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_exit_interpreter |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Exit the interpreter execution region. This is the top level |
* routine used to exit the interpreter when all processing has |
* been completed, or when the method blocks. |
* |
* Cases where the interpreter is unlocked internally: |
* 1) Method will be blocked on a Sleep() AML opcode |
* 2) Method will be blocked on an Acquire() AML opcode |
* 3) Method will be blocked on a Wait() AML opcode |
* 4) Method will be blocked to acquire the global lock |
* 5) Method will be blocked waiting to execute a serialized control |
* method that is currently executing |
* 6) About to invoke a user-installed opregion handler |
* |
******************************************************************************/ |
void acpi_ex_exit_interpreter(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ex_exit_interpreter); |
status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not release AML Interpreter mutex")); |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_truncate_for32bit_table |
* |
* PARAMETERS: obj_desc - Object to be truncated |
* |
* RETURN: TRUE if a truncation was performed, FALSE otherwise. |
* |
* DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is |
* 32-bit, as determined by the revision of the DSDT. |
* |
******************************************************************************/ |
u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* |
* Object must be a valid number and we must be executing |
* a control method. Object could be NS node for AML_INT_NAMEPATH_OP. |
*/ |
if ((!obj_desc) || |
(ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) || |
(obj_desc->common.type != ACPI_TYPE_INTEGER)) { |
return (FALSE); |
} |
if ((acpi_gbl_integer_byte_width == 4) && |
(obj_desc->integer.value > (u64)ACPI_UINT32_MAX)) { |
/* |
* We are executing in a 32-bit ACPI table. |
* Truncate the value to 32 bits by zeroing out the upper 32-bit field |
*/ |
obj_desc->integer.value &= (u64)ACPI_UINT32_MAX; |
return (TRUE); |
} |
return (FALSE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_acquire_global_lock |
* |
* PARAMETERS: field_flags - Flags with Lock rule: |
* always_lock or never_lock |
* |
* RETURN: None |
* |
* DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field |
* flags specifiy that it is to be obtained before field access. |
* |
******************************************************************************/ |
void acpi_ex_acquire_global_lock(u32 field_flags) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ex_acquire_global_lock); |
/* Only use the lock if the always_lock bit is set */ |
if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) { |
return_VOID; |
} |
/* Attempt to get the global lock, wait forever */ |
status = acpi_ex_acquire_mutex_object(ACPI_WAIT_FOREVER, |
acpi_gbl_global_lock_mutex, |
acpi_os_get_thread_id()); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not acquire Global Lock")); |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_release_global_lock |
* |
* PARAMETERS: field_flags - Flags with Lock rule: |
* always_lock or never_lock |
* |
* RETURN: None |
* |
* DESCRIPTION: Release the ACPI hardware Global Lock |
* |
******************************************************************************/ |
void acpi_ex_release_global_lock(u32 field_flags) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ex_release_global_lock); |
/* Only use the lock if the always_lock bit is set */ |
if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) { |
return_VOID; |
} |
/* Release the global lock */ |
status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex); |
if (ACPI_FAILURE(status)) { |
/* Report the error, but there isn't much else we can do */ |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not release Global Lock")); |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_digits_needed |
* |
* PARAMETERS: value - Value to be represented |
* base - Base of representation |
* |
* RETURN: The number of digits. |
* |
* DESCRIPTION: Calculate the number of digits needed to represent the Value |
* in the given Base (Radix) |
* |
******************************************************************************/ |
static u32 acpi_ex_digits_needed(u64 value, u32 base) |
{ |
u32 num_digits; |
u64 current_value; |
ACPI_FUNCTION_TRACE(ex_digits_needed); |
/* u64 is unsigned, so we don't worry about a '-' prefix */ |
if (value == 0) { |
return_UINT32(1); |
} |
current_value = value; |
num_digits = 0; |
/* Count the digits in the requested base */ |
while (current_value) { |
(void)acpi_ut_short_divide(current_value, base, ¤t_value, |
NULL); |
num_digits++; |
} |
return_UINT32(num_digits); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_eisa_id_to_string |
* |
* PARAMETERS: compressed_id - EISAID to be converted |
* out_string - Where to put the converted string (8 bytes) |
* |
* RETURN: None |
* |
* DESCRIPTION: Convert a numeric EISAID to string representation. Return |
* buffer must be large enough to hold the string. The string |
* returned is always exactly of length ACPI_EISAID_STRING_SIZE |
* (includes null terminator). The EISAID is always 32 bits. |
* |
******************************************************************************/ |
void acpi_ex_eisa_id_to_string(char *out_string, u64 compressed_id) |
{ |
u32 swapped_id; |
ACPI_FUNCTION_ENTRY(); |
/* The EISAID should be a 32-bit integer */ |
if (compressed_id > ACPI_UINT32_MAX) { |
ACPI_WARNING((AE_INFO, |
"Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating", |
ACPI_FORMAT_UINT64(compressed_id))); |
} |
/* Swap ID to big-endian to get contiguous bits */ |
swapped_id = acpi_ut_dword_byte_swap((u32)compressed_id); |
/* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */ |
out_string[0] = |
(char)(0x40 + (((unsigned long)swapped_id >> 26) & 0x1F)); |
out_string[1] = (char)(0x40 + ((swapped_id >> 21) & 0x1F)); |
out_string[2] = (char)(0x40 + ((swapped_id >> 16) & 0x1F)); |
out_string[3] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 12); |
out_string[4] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 8); |
out_string[5] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 4); |
out_string[6] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 0); |
out_string[7] = 0; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_integer_to_string |
* |
* PARAMETERS: out_string - Where to put the converted string. At least |
* 21 bytes are needed to hold the largest |
* possible 64-bit integer. |
* value - Value to be converted |
* |
* RETURN: None, string |
* |
* DESCRIPTION: Convert a 64-bit integer to decimal string representation. |
* Assumes string buffer is large enough to hold the string. The |
* largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1). |
* |
******************************************************************************/ |
void acpi_ex_integer_to_string(char *out_string, u64 value) |
{ |
u32 count; |
u32 digits_needed; |
u32 remainder; |
ACPI_FUNCTION_ENTRY(); |
digits_needed = acpi_ex_digits_needed(value, 10); |
out_string[digits_needed] = 0; |
for (count = digits_needed; count > 0; count--) { |
(void)acpi_ut_short_divide(value, 10, &value, &remainder); |
out_string[count - 1] = (char)('0' + remainder); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ex_pci_cls_to_string |
* |
* PARAMETERS: out_string - Where to put the converted string (7 bytes) |
* PARAMETERS: class_code - PCI class code to be converted (3 bytes) |
* |
* RETURN: None |
* |
* DESCRIPTION: Convert 3-bytes PCI class code to string representation. |
* Return buffer must be large enough to hold the string. The |
* string returned is always exactly of length |
* ACPI_PCICLS_STRING_SIZE (includes null terminator). |
* |
******************************************************************************/ |
void acpi_ex_pci_cls_to_string(char *out_string, u8 class_code[3]) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* All 3 bytes are hexadecimal */ |
out_string[0] = acpi_ut_hex_to_ascii_char((u64)class_code[0], 4); |
out_string[1] = acpi_ut_hex_to_ascii_char((u64)class_code[0], 0); |
out_string[2] = acpi_ut_hex_to_ascii_char((u64)class_code[1], 4); |
out_string[3] = acpi_ut_hex_to_ascii_char((u64)class_code[1], 0); |
out_string[4] = acpi_ut_hex_to_ascii_char((u64)class_code[2], 4); |
out_string[5] = acpi_ut_hex_to_ascii_char((u64)class_code[2], 0); |
out_string[6] = 0; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_is_valid_space_id |
* |
* PARAMETERS: space_id - ID to be validated |
* |
* RETURN: TRUE if valid/supported ID. |
* |
* DESCRIPTION: Validate an operation region space_ID. |
* |
******************************************************************************/ |
u8 acpi_is_valid_space_id(u8 space_id) |
{ |
if ((space_id >= ACPI_NUM_PREDEFINED_REGIONS) && |
(space_id < ACPI_USER_REGION_BEGIN) && |
(space_id != ACPI_ADR_SPACE_DATA_TABLE) && |
(space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { |
return (FALSE); |
} |
return (TRUE); |
} |
#endif |
/drivers/acpi/acpica/hwacpi.c |
---|
0,0 → 1,181 |
/****************************************************************************** |
* |
* Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwacpi") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_set_mode |
* |
* PARAMETERS: mode - SYS_MODE_ACPI or SYS_MODE_LEGACY |
* |
* RETURN: Status |
* |
* DESCRIPTION: Transitions the system into the requested mode. |
* |
******************************************************************************/ |
acpi_status acpi_hw_set_mode(u32 mode) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_set_mode); |
/* If the Hardware Reduced flag is set, machine is always in acpi mode */ |
if (acpi_gbl_reduced_hardware) { |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero, |
* system does not support mode transition. |
*/ |
if (!acpi_gbl_FADT.smi_command) { |
ACPI_ERROR((AE_INFO, |
"No SMI_CMD in FADT, mode transition failed")); |
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); |
} |
/* |
* ACPI 2.0 clarified the meaning of ACPI_ENABLE and ACPI_DISABLE |
* in FADT: If it is zero, enabling or disabling is not supported. |
* As old systems may have used zero for mode transition, |
* we make sure both the numbers are zero to determine these |
* transitions are not supported. |
*/ |
if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) { |
ACPI_ERROR((AE_INFO, |
"No ACPI mode transition supported in this system " |
"(enable/disable both zero)")); |
return_ACPI_STATUS(AE_OK); |
} |
switch (mode) { |
case ACPI_SYS_MODE_ACPI: |
/* BIOS should have disabled ALL fixed and GP events */ |
status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, |
(u32) acpi_gbl_FADT.acpi_enable, 8); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Attempting to enable ACPI mode\n")); |
break; |
case ACPI_SYS_MODE_LEGACY: |
/* |
* BIOS should clear all fixed status bits and restore fixed event |
* enable bits to default |
*/ |
status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, |
(u32)acpi_gbl_FADT.acpi_disable, 8); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Attempting to enable Legacy (non-ACPI) mode\n")); |
break; |
default: |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not write ACPI mode change")); |
return_ACPI_STATUS(status); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_get_mode |
* |
* PARAMETERS: none |
* |
* RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY |
* |
* DESCRIPTION: Return current operating state of system. Determined by |
* querying the SCI_EN bit. |
* |
******************************************************************************/ |
u32 acpi_hw_get_mode(void) |
{ |
acpi_status status; |
u32 value; |
ACPI_FUNCTION_TRACE(hw_get_mode); |
/* If the Hardware Reduced flag is set, machine is always in acpi mode */ |
if (acpi_gbl_reduced_hardware) { |
return_UINT32(ACPI_SYS_MODE_ACPI); |
} |
/* |
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero, |
* system does not support mode transition. |
*/ |
if (!acpi_gbl_FADT.smi_command) { |
return_UINT32(ACPI_SYS_MODE_ACPI); |
} |
status = acpi_read_bit_register(ACPI_BITREG_SCI_ENABLE, &value); |
if (ACPI_FAILURE(status)) { |
return_UINT32(ACPI_SYS_MODE_LEGACY); |
} |
if (value) { |
return_UINT32(ACPI_SYS_MODE_ACPI); |
} else { |
return_UINT32(ACPI_SYS_MODE_LEGACY); |
} |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/hwesleep.c |
---|
0,0 → 1,243 |
/****************************************************************************** |
* |
* Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the |
* extended FADT-V5 sleep registers. |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include <linux/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwesleep") |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_execute_sleep_method |
* |
* PARAMETERS: method_pathname - Pathname of method to execute |
* integer_argument - Argument to pass to the method |
* |
* RETURN: None |
* |
* DESCRIPTION: Execute a sleep/wake related method with one integer argument |
* and no return value. |
* |
******************************************************************************/ |
void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument) |
{ |
struct acpi_object_list arg_list; |
union acpi_object arg; |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_execute_sleep_method); |
/* One argument, integer_argument; No return value expected */ |
arg_list.count = 1; |
arg_list.pointer = &arg; |
arg.type = ACPI_TYPE_INTEGER; |
arg.integer.value = (u64)integer_argument; |
status = acpi_evaluate_object(NULL, method_pathname, &arg_list, NULL); |
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
ACPI_EXCEPTION((AE_INFO, status, "While executing method %s", |
method_pathname)); |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_extended_sleep |
* |
* PARAMETERS: sleep_state - Which sleep state to enter |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enter a system sleep state via the extended FADT sleep |
* registers (V5 FADT). |
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
* |
******************************************************************************/ |
acpi_status acpi_hw_extended_sleep(u8 sleep_state) |
{ |
acpi_status status; |
u8 sleep_type_value; |
u64 sleep_status; |
ACPI_FUNCTION_TRACE(hw_extended_sleep); |
/* Extended sleep registers must be valid */ |
if (!acpi_gbl_FADT.sleep_control.address || |
!acpi_gbl_FADT.sleep_status.address) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Clear wake status (WAK_STS) */ |
status = |
acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_gbl_system_awake_and_running = FALSE; |
/* Flush caches, as per ACPI specification */ |
ACPI_FLUSH_CPU_CACHE(); |
status = acpi_os_prepare_extended_sleep(sleep_state, |
acpi_gbl_sleep_type_a, |
acpi_gbl_sleep_type_b); |
if (ACPI_SKIP(status)) |
return_ACPI_STATUS(AE_OK); |
if (ACPI_FAILURE(status)) |
return_ACPI_STATUS(status); |
/* |
* Set the SLP_TYP and SLP_EN bits. |
* |
* Note: We only use the first value returned by the \_Sx method |
* (acpi_gbl_sleep_type_a) - As per ACPI specification. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_INIT, |
"Entering sleep state [S%u]\n", sleep_state)); |
sleep_type_value = |
((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & |
ACPI_X_SLEEP_TYPE_MASK); |
status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), |
&acpi_gbl_FADT.sleep_control); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Wait for transition back to Working State */ |
do { |
status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_extended_wake_prep |
* |
* PARAMETERS: sleep_state - Which sleep state we just exited |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform first part of OS-independent ACPI cleanup after |
* a sleep. Called with interrupts ENABLED. |
* |
******************************************************************************/ |
acpi_status acpi_hw_extended_wake_prep(u8 sleep_state) |
{ |
acpi_status status; |
u8 sleep_type_value; |
ACPI_FUNCTION_TRACE(hw_extended_wake_prep); |
status = acpi_get_sleep_type_data(ACPI_STATE_S0, |
&acpi_gbl_sleep_type_a, |
&acpi_gbl_sleep_type_b); |
if (ACPI_SUCCESS(status)) { |
sleep_type_value = |
((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & |
ACPI_X_SLEEP_TYPE_MASK); |
(void)acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), |
&acpi_gbl_FADT.sleep_control); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_extended_wake |
* |
* PARAMETERS: sleep_state - Which sleep state we just exited |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep |
* Called with interrupts ENABLED. |
* |
******************************************************************************/ |
acpi_status acpi_hw_extended_wake(u8 sleep_state) |
{ |
ACPI_FUNCTION_TRACE(hw_extended_wake); |
/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ |
acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; |
/* Execute the wake methods */ |
acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING); |
acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state); |
/* |
* Some BIOS code assumes that WAK_STS will be cleared on resume |
* and use it to determine whether the system is rebooting or |
* resuming. Clear WAK_STS for compatibility. |
*/ |
(void)acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status); |
acpi_gbl_system_awake_and_running = TRUE; |
acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/hwgpe.c |
---|
0,0 → 1,535 |
/****************************************************************************** |
* |
* Module Name: hwgpe - Low level GPE enable/disable/clear functions |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwgpe") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/* Local prototypes */ |
static acpi_status |
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *context); |
static acpi_status |
acpi_hw_gpe_enable_write(u8 enable_mask, |
struct acpi_gpe_register_info *gpe_register_info); |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_get_gpe_register_bit |
* |
* PARAMETERS: gpe_event_info - Info block for the GPE |
* |
* RETURN: Register mask with a one in the GPE bit position |
* |
* DESCRIPTION: Compute the register mask for this GPE. One bit is set in the |
* correct position for the input GPE. |
* |
******************************************************************************/ |
u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info) |
{ |
return ((u32)1 << |
(gpe_event_info->gpe_number - |
gpe_event_info->register_info->base_gpe_number)); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_low_set_gpe |
* |
* PARAMETERS: gpe_event_info - Info block for the GPE to be disabled |
* action - Enable or disable |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable or disable a single GPE in the parent enable register. |
* The enable_mask field of the involved GPE register must be |
* updated by the caller if necessary. |
* |
******************************************************************************/ |
acpi_status |
acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) |
{ |
struct acpi_gpe_register_info *gpe_register_info; |
acpi_status status; |
u32 enable_mask; |
u32 register_bit; |
ACPI_FUNCTION_ENTRY(); |
/* Get the info block for the entire GPE register */ |
gpe_register_info = gpe_event_info->register_info; |
if (!gpe_register_info) { |
return (AE_NOT_EXIST); |
} |
/* Get current value of the enable register that contains this GPE */ |
status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Set or clear just the bit that corresponds to this GPE */ |
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
switch (action) { |
case ACPI_GPE_CONDITIONAL_ENABLE: |
/* Only enable if the corresponding enable_mask bit is set */ |
if (!(register_bit & gpe_register_info->enable_mask)) { |
return (AE_BAD_PARAMETER); |
} |
/*lint -fallthrough */ |
case ACPI_GPE_ENABLE: |
ACPI_SET_BIT(enable_mask, register_bit); |
break; |
case ACPI_GPE_DISABLE: |
ACPI_CLEAR_BIT(enable_mask, register_bit); |
break; |
default: |
ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action)); |
return (AE_BAD_PARAMETER); |
} |
/* Write the updated enable mask */ |
status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); |
return (status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_clear_gpe |
* |
* PARAMETERS: gpe_event_info - Info block for the GPE to be cleared |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clear the status bit for a single GPE. |
* |
******************************************************************************/ |
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) |
{ |
struct acpi_gpe_register_info *gpe_register_info; |
acpi_status status; |
u32 register_bit; |
ACPI_FUNCTION_ENTRY(); |
/* Get the info block for the entire GPE register */ |
gpe_register_info = gpe_event_info->register_info; |
if (!gpe_register_info) { |
return (AE_NOT_EXIST); |
} |
/* |
* Write a one to the appropriate bit in the status register to |
* clear this GPE. |
*/ |
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
status = acpi_hw_write(register_bit, |
&gpe_register_info->status_address); |
return (status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_get_gpe_status |
* |
* PARAMETERS: gpe_event_info - Info block for the GPE to queried |
* event_status - Where the GPE status is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Return the status of a single GPE. |
* |
******************************************************************************/ |
acpi_status |
acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, |
acpi_event_status *event_status) |
{ |
u32 in_byte; |
u32 register_bit; |
struct acpi_gpe_register_info *gpe_register_info; |
acpi_event_status local_event_status = 0; |
acpi_status status; |
ACPI_FUNCTION_ENTRY(); |
if (!event_status) { |
return (AE_BAD_PARAMETER); |
} |
/* GPE currently handled? */ |
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != |
ACPI_GPE_DISPATCH_NONE) { |
local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER; |
} |
/* Get the info block for the entire GPE register */ |
gpe_register_info = gpe_event_info->register_info; |
/* Get the register bitmask for this GPE */ |
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
/* GPE currently enabled? (enabled for runtime?) */ |
if (register_bit & gpe_register_info->enable_for_run) { |
local_event_status |= ACPI_EVENT_FLAG_ENABLED; |
} |
/* GPE enabled for wake? */ |
if (register_bit & gpe_register_info->enable_for_wake) { |
local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED; |
} |
/* GPE currently enabled (enable bit == 1)? */ |
status = acpi_hw_read(&in_byte, &gpe_register_info->enable_address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (register_bit & in_byte) { |
local_event_status |= ACPI_EVENT_FLAG_ENABLE_SET; |
} |
/* GPE currently active (status bit == 1)? */ |
status = acpi_hw_read(&in_byte, &gpe_register_info->status_address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (register_bit & in_byte) { |
local_event_status |= ACPI_EVENT_FLAG_STATUS_SET; |
} |
/* Set return value */ |
(*event_status) = local_event_status; |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_gpe_enable_write |
* |
* PARAMETERS: enable_mask - Bit mask to write to the GPE register |
* gpe_register_info - Gpe Register info |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write the enable mask byte to the given GPE register. |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_gpe_enable_write(u8 enable_mask, |
struct acpi_gpe_register_info *gpe_register_info) |
{ |
acpi_status status; |
gpe_register_info->enable_mask = enable_mask; |
status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); |
return (status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_disable_gpe_block |
* |
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info |
* gpe_block - Gpe Block info |
* |
* RETURN: Status |
* |
* DESCRIPTION: Disable all GPEs within a single GPE block |
* |
******************************************************************************/ |
acpi_status |
acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, void *context) |
{ |
u32 i; |
acpi_status status; |
/* Examine each GPE Register within the block */ |
for (i = 0; i < gpe_block->register_count; i++) { |
/* Disable all GPEs in this register */ |
status = |
acpi_hw_gpe_enable_write(0x00, |
&gpe_block->register_info[i]); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_clear_gpe_block |
* |
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info |
* gpe_block - Gpe Block info |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clear status bits for all GPEs within a single GPE block |
* |
******************************************************************************/ |
acpi_status |
acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, void *context) |
{ |
u32 i; |
acpi_status status; |
/* Examine each GPE Register within the block */ |
for (i = 0; i < gpe_block->register_count; i++) { |
/* Clear status on all GPEs in this register */ |
status = |
acpi_hw_write(0xFF, |
&gpe_block->register_info[i].status_address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_enable_runtime_gpe_block |
* |
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info |
* gpe_block - Gpe Block info |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes |
* combination wake/run GPEs. |
* |
******************************************************************************/ |
acpi_status |
acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info * gpe_block, |
void *context) |
{ |
u32 i; |
acpi_status status; |
struct acpi_gpe_register_info *gpe_register_info; |
/* NOTE: assumes that all GPEs are currently disabled */ |
/* Examine each GPE Register within the block */ |
for (i = 0; i < gpe_block->register_count; i++) { |
gpe_register_info = &gpe_block->register_info[i]; |
if (!gpe_register_info->enable_for_run) { |
continue; |
} |
/* Enable all "runtime" GPEs in this register */ |
status = |
acpi_hw_gpe_enable_write(gpe_register_info->enable_for_run, |
gpe_register_info); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_enable_wakeup_gpe_block |
* |
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info |
* gpe_block - Gpe Block info |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes |
* combination wake/run GPEs. |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
struct acpi_gpe_block_info *gpe_block, |
void *context) |
{ |
u32 i; |
acpi_status status; |
struct acpi_gpe_register_info *gpe_register_info; |
/* Examine each GPE Register within the block */ |
for (i = 0; i < gpe_block->register_count; i++) { |
gpe_register_info = &gpe_block->register_info[i]; |
/* |
* Enable all "wake" GPEs in this register and disable the |
* remaining ones. |
*/ |
status = |
acpi_hw_gpe_enable_write(gpe_register_info->enable_for_wake, |
gpe_register_info); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_disable_all_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Disable and clear all GPEs in all GPE blocks |
* |
******************************************************************************/ |
acpi_status acpi_hw_disable_all_gpes(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_disable_all_gpes); |
status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); |
status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); |
return_ACPI_STATUS(status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_enable_all_runtime_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks |
* |
******************************************************************************/ |
acpi_status acpi_hw_enable_all_runtime_gpes(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes); |
status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL); |
return_ACPI_STATUS(status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_enable_all_wakeup_gpes |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks |
* |
******************************************************************************/ |
acpi_status acpi_hw_enable_all_wakeup_gpes(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes); |
status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL); |
return_ACPI_STATUS(status); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/hwpci.c |
---|
0,0 → 1,420 |
/******************************************************************************* |
* |
* Module Name: hwpci - Obtain PCI bus, device, and function numbers |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("hwpci") |
/* PCI configuration space values */ |
#define PCI_CFG_HEADER_TYPE_REG 0x0E |
#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 |
#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 |
/* PCI header values */ |
#define PCI_HEADER_TYPE_MASK 0x7F |
#define PCI_TYPE_BRIDGE 0x01 |
#define PCI_TYPE_CARDBUS_BRIDGE 0x02 |
typedef struct acpi_pci_device { |
acpi_handle device; |
struct acpi_pci_device *next; |
} acpi_pci_device; |
/* Local prototypes */ |
static acpi_status |
acpi_hw_build_pci_list(acpi_handle root_pci_device, |
acpi_handle pci_region, |
struct acpi_pci_device **return_list_head); |
static acpi_status |
acpi_hw_process_pci_list(struct acpi_pci_id *pci_id, |
struct acpi_pci_device *list_head); |
static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head); |
static acpi_status |
acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id, |
acpi_handle pci_device, |
u16 *bus_number, u8 *is_bridge); |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_derive_pci_id |
* |
* PARAMETERS: pci_id - Initial values for the PCI ID. May be |
* modified by this function. |
* root_pci_device - A handle to a PCI device object. This |
* object must be a PCI Root Bridge having a |
* _HID value of either PNP0A03 or PNP0A08 |
* pci_region - A handle to a PCI configuration space |
* Operation Region being initialized |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function derives a full PCI ID for a PCI device, |
* consisting of a Segment number, Bus number, Device number, |
* and function code. |
* |
* The PCI hardware dynamically configures PCI bus numbers |
* depending on the bus topology discovered during system |
* initialization. This function is invoked during configuration |
* of a PCI_Config Operation Region in order to (possibly) update |
* the Bus/Device/Function numbers in the pci_id with the actual |
* values as determined by the hardware and operating system |
* configuration. |
* |
* The pci_id parameter is initially populated during the Operation |
* Region initialization. This function is then called, and is |
* will make any necessary modifications to the Bus, Device, or |
* Function number PCI ID subfields as appropriate for the |
* current hardware and OS configuration. |
* |
* NOTE: Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id |
* interface since this feature is OS-independent. This module |
* specifically avoids any use of recursion by building a local |
* temporary device list. |
* |
******************************************************************************/ |
acpi_status |
acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id, |
acpi_handle root_pci_device, acpi_handle pci_region) |
{ |
acpi_status status; |
struct acpi_pci_device *list_head; |
ACPI_FUNCTION_TRACE(hw_derive_pci_id); |
if (!pci_id) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Build a list of PCI devices, from pci_region up to root_pci_device */ |
status = |
acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head); |
if (ACPI_SUCCESS(status)) { |
/* Walk the list, updating the PCI device/function/bus numbers */ |
status = acpi_hw_process_pci_list(pci_id, list_head); |
/* Delete the list */ |
acpi_hw_delete_pci_list(list_head); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_build_pci_list |
* |
* PARAMETERS: root_pci_device - A handle to a PCI device object. This |
* object is guaranteed to be a PCI Root |
* Bridge having a _HID value of either |
* PNP0A03 or PNP0A08 |
* pci_region - A handle to the PCI configuration space |
* Operation Region |
* return_list_head - Where the PCI device list is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Builds a list of devices from the input PCI region up to the |
* Root PCI device for this namespace subtree. |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_build_pci_list(acpi_handle root_pci_device, |
acpi_handle pci_region, |
struct acpi_pci_device **return_list_head) |
{ |
acpi_handle current_device; |
acpi_handle parent_device; |
acpi_status status; |
struct acpi_pci_device *list_element; |
/* |
* Ascend namespace branch until the root_pci_device is reached, building |
* a list of device nodes. Loop will exit when either the PCI device is |
* found, or the root of the namespace is reached. |
*/ |
*return_list_head = NULL; |
current_device = pci_region; |
while (1) { |
status = acpi_get_parent(current_device, &parent_device); |
if (ACPI_FAILURE(status)) { |
/* Must delete the list before exit */ |
acpi_hw_delete_pci_list(*return_list_head); |
return (status); |
} |
/* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ |
if (parent_device == root_pci_device) { |
return (AE_OK); |
} |
list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device)); |
if (!list_element) { |
/* Must delete the list before exit */ |
acpi_hw_delete_pci_list(*return_list_head); |
return (AE_NO_MEMORY); |
} |
/* Put new element at the head of the list */ |
list_element->next = *return_list_head; |
list_element->device = parent_device; |
*return_list_head = list_element; |
current_device = parent_device; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_process_pci_list |
* |
* PARAMETERS: pci_id - Initial values for the PCI ID. May be |
* modified by this function. |
* list_head - Device list created by |
* acpi_hw_build_pci_list |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walk downward through the PCI device list, getting the device |
* info for each, via the PCI configuration space and updating |
* the PCI ID as necessary. Deletes the list during traversal. |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_process_pci_list(struct acpi_pci_id *pci_id, |
struct acpi_pci_device *list_head) |
{ |
acpi_status status = AE_OK; |
struct acpi_pci_device *info; |
u16 bus_number; |
u8 is_bridge = TRUE; |
ACPI_FUNCTION_NAME(hw_process_pci_list); |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", |
pci_id->segment, pci_id->bus, pci_id->device, |
pci_id->function)); |
bus_number = pci_id->bus; |
/* |
* Descend down the namespace tree, collecting PCI device, function, |
* and bus numbers. bus_number is only important for PCI bridges. |
* Algorithm: As we descend the tree, use the last valid PCI device, |
* function, and bus numbers that are discovered, and assign them |
* to the PCI ID for the target device. |
*/ |
info = list_head; |
while (info) { |
status = acpi_hw_get_pci_device_info(pci_id, info->device, |
&bus_number, &is_bridge); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
info = info->next; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
"Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " |
"Status %X BusNumber %X IsBridge %X\n", |
pci_id->segment, pci_id->bus, pci_id->device, |
pci_id->function, status, bus_number, is_bridge)); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_delete_pci_list |
* |
* PARAMETERS: list_head - Device list created by |
* acpi_hw_build_pci_list |
* |
* RETURN: None |
* |
* DESCRIPTION: Free the entire PCI list. |
* |
******************************************************************************/ |
static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head) |
{ |
struct acpi_pci_device *next; |
struct acpi_pci_device *previous; |
next = list_head; |
while (next) { |
previous = next; |
next = previous->next; |
ACPI_FREE(previous); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_get_pci_device_info |
* |
* PARAMETERS: pci_id - Initial values for the PCI ID. May be |
* modified by this function. |
* pci_device - Handle for the PCI device object |
* bus_number - Where a PCI bridge bus number is returned |
* is_bridge - Return value, indicates if this PCI |
* device is a PCI bridge |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get the device info for a single PCI device object. Get the |
* _ADR (contains PCI device and function numbers), and for PCI |
* bridge devices, get the bus number from PCI configuration |
* space. |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id, |
acpi_handle pci_device, |
u16 *bus_number, u8 *is_bridge) |
{ |
acpi_status status; |
acpi_object_type object_type; |
u64 return_value; |
u64 pci_value; |
/* We only care about objects of type Device */ |
status = acpi_get_type(pci_device, &object_type); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (object_type != ACPI_TYPE_DEVICE) { |
return (AE_OK); |
} |
/* We need an _ADR. Ignore device if not present */ |
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, |
pci_device, &return_value); |
if (ACPI_FAILURE(status)) { |
return (AE_OK); |
} |
/* |
* From _ADR, get the PCI Device and Function and |
* update the PCI ID. |
*/ |
pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value)); |
pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value)); |
/* |
* If the previous device was a bridge, use the previous |
* device bus number |
*/ |
if (*is_bridge) { |
pci_id->bus = *bus_number; |
} |
/* |
* Get the bus numbers from PCI Config space: |
* |
* First, get the PCI header_type |
*/ |
*is_bridge = FALSE; |
status = acpi_os_read_pci_configuration(pci_id, |
PCI_CFG_HEADER_TYPE_REG, |
&pci_value, 8); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */ |
pci_value &= PCI_HEADER_TYPE_MASK; |
if ((pci_value != PCI_TYPE_BRIDGE) && |
(pci_value != PCI_TYPE_CARDBUS_BRIDGE)) { |
return (AE_OK); |
} |
/* Bridge: Get the Primary bus_number */ |
status = acpi_os_read_pci_configuration(pci_id, |
PCI_CFG_PRIMARY_BUS_NUMBER_REG, |
&pci_value, 8); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
*is_bridge = TRUE; |
pci_id->bus = (u16)pci_value; |
/* Bridge: Get the Secondary bus_number */ |
status = acpi_os_read_pci_configuration(pci_id, |
PCI_CFG_SECONDARY_BUS_NUMBER_REG, |
&pci_value, 8); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
*bus_number = (u16)pci_value; |
return (AE_OK); |
} |
/drivers/acpi/acpica/hwregs.c |
---|
0,0 → 1,668 |
/******************************************************************************* |
* |
* Module Name: hwregs - Read/write access functions for the various ACPI |
* control and status registers. |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwregs") |
#if (!ACPI_REDUCED_HARDWARE) |
/* Local Prototypes */ |
static acpi_status |
acpi_hw_read_multiple(u32 *value, |
struct acpi_generic_address *register_a, |
struct acpi_generic_address *register_b); |
static acpi_status |
acpi_hw_write_multiple(u32 value, |
struct acpi_generic_address *register_a, |
struct acpi_generic_address *register_b); |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_validate_register |
* |
* PARAMETERS: reg - GAS register structure |
* max_bit_width - Max bit_width supported (32 or 64) |
* address - Pointer to where the gas->address |
* is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Validate the contents of a GAS register. Checks the GAS |
* pointer, Address, space_id, bit_width, and bit_offset. |
* |
******************************************************************************/ |
acpi_status |
acpi_hw_validate_register(struct acpi_generic_address *reg, |
u8 max_bit_width, u64 *address) |
{ |
/* Must have a valid pointer to a GAS structure */ |
if (!reg) { |
return (AE_BAD_PARAMETER); |
} |
/* |
* Copy the target address. This handles possible alignment issues. |
* Address must not be null. A null address also indicates an optional |
* ACPI register that is not supported, so no error message. |
*/ |
ACPI_MOVE_64_TO_64(address, ®->address); |
if (!(*address)) { |
return (AE_BAD_ADDRESS); |
} |
/* Validate the space_ID */ |
if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && |
(reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { |
ACPI_ERROR((AE_INFO, |
"Unsupported address space: 0x%X", reg->space_id)); |
return (AE_SUPPORT); |
} |
/* Validate the bit_width */ |
if ((reg->bit_width != 8) && |
(reg->bit_width != 16) && |
(reg->bit_width != 32) && (reg->bit_width != max_bit_width)) { |
ACPI_ERROR((AE_INFO, |
"Unsupported register bit width: 0x%X", |
reg->bit_width)); |
return (AE_SUPPORT); |
} |
/* Validate the bit_offset. Just a warning for now. */ |
if (reg->bit_offset != 0) { |
ACPI_WARNING((AE_INFO, |
"Unsupported register bit offset: 0x%X", |
reg->bit_offset)); |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_read |
* |
* PARAMETERS: value - Where the value is returned |
* reg - GAS register structure |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read from either memory or IO space. This is a 32-bit max |
* version of acpi_read, used internally since the overhead of |
* 64-bit values is not needed. |
* |
* LIMITATIONS: <These limitations also apply to acpi_hw_write> |
* bit_width must be exactly 8, 16, or 32. |
* space_ID must be system_memory or system_IO. |
* bit_offset and access_width are currently ignored, as there has |
* not been a need to implement these. |
* |
******************************************************************************/ |
acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) |
{ |
u64 address; |
u64 value64; |
acpi_status status; |
ACPI_FUNCTION_NAME(hw_read); |
/* Validate contents of the GAS register */ |
status = acpi_hw_validate_register(reg, 32, &address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Initialize entire 32-bit return value to zero */ |
*value = 0; |
/* |
* Two address spaces supported: Memory or IO. PCI_Config is |
* not supported here because the GAS structure is insufficient |
*/ |
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
status = acpi_os_read_memory((acpi_physical_address) |
address, &value64, reg->bit_width); |
*value = (u32)value64; |
} else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ |
status = acpi_hw_read_port((acpi_io_address) |
address, value, reg->bit_width); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", |
*value, reg->bit_width, ACPI_FORMAT_UINT64(address), |
acpi_ut_get_region_name(reg->space_id))); |
return (status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_write |
* |
* PARAMETERS: value - Value to be written |
* reg - GAS register structure |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write to either memory or IO space. This is a 32-bit max |
* version of acpi_write, used internally since the overhead of |
* 64-bit values is not needed. |
* |
******************************************************************************/ |
acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) |
{ |
u64 address; |
acpi_status status; |
ACPI_FUNCTION_NAME(hw_write); |
/* Validate contents of the GAS register */ |
status = acpi_hw_validate_register(reg, 32, &address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* Two address spaces supported: Memory or IO. PCI_Config is |
* not supported here because the GAS structure is insufficient |
*/ |
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
status = acpi_os_write_memory((acpi_physical_address) |
address, (u64)value, |
reg->bit_width); |
} else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ |
status = acpi_hw_write_port((acpi_io_address) |
address, value, reg->bit_width); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", |
value, reg->bit_width, ACPI_FORMAT_UINT64(address), |
acpi_ut_get_region_name(reg->space_id))); |
return (status); |
} |
#if (!ACPI_REDUCED_HARDWARE) |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_clear_acpi_status |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Clears all fixed and general purpose status bits |
* |
******************************************************************************/ |
acpi_status acpi_hw_clear_acpi_status(void) |
{ |
acpi_status status; |
acpi_cpu_flags lock_flags = 0; |
ACPI_FUNCTION_TRACE(hw_clear_acpi_status); |
ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", |
ACPI_BITMASK_ALL_FIXED_STATUS, |
ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); |
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); |
/* Clear the fixed events in PM1 A/B */ |
status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, |
ACPI_BITMASK_ALL_FIXED_STATUS); |
acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Clear the GPE Bits in all GPE registers in all GPE blocks */ |
status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); |
exit: |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_get_bit_register_info |
* |
* PARAMETERS: register_id - Index of ACPI Register to access |
* |
* RETURN: The bitmask to be used when accessing the register |
* |
* DESCRIPTION: Map register_id into a register bitmask. |
* |
******************************************************************************/ |
struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) |
{ |
ACPI_FUNCTION_ENTRY(); |
if (register_id > ACPI_BITREG_MAX) { |
ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: 0x%X", |
register_id)); |
return (NULL); |
} |
return (&acpi_gbl_bit_register_info[register_id]); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_write_pm1_control |
* |
* PARAMETERS: pm1a_control - Value to be written to PM1A control |
* pm1b_control - Value to be written to PM1B control |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write the PM1 A/B control registers. These registers are |
* different than than the PM1 A/B status and enable registers |
* in that different values can be written to the A/B registers. |
* Most notably, the SLP_TYP bits can be different, as per the |
* values returned from the _Sx predefined methods. |
* |
******************************************************************************/ |
acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_write_pm1_control); |
status = |
acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (acpi_gbl_FADT.xpm1b_control_block.address) { |
status = |
acpi_hw_write(pm1b_control, |
&acpi_gbl_FADT.xpm1b_control_block); |
} |
return_ACPI_STATUS(status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_register_read |
* |
* PARAMETERS: register_id - ACPI Register ID |
* return_value - Where the register value is returned |
* |
* RETURN: Status and the value read. |
* |
* DESCRIPTION: Read from the specified ACPI register |
* |
******************************************************************************/ |
acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value) |
{ |
u32 value = 0; |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_register_read); |
switch (register_id) { |
case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ |
status = acpi_hw_read_multiple(&value, |
&acpi_gbl_xpm1a_status, |
&acpi_gbl_xpm1b_status); |
break; |
case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ |
status = acpi_hw_read_multiple(&value, |
&acpi_gbl_xpm1a_enable, |
&acpi_gbl_xpm1b_enable); |
break; |
case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ |
status = acpi_hw_read_multiple(&value, |
&acpi_gbl_FADT. |
xpm1a_control_block, |
&acpi_gbl_FADT. |
xpm1b_control_block); |
/* |
* Zero the write-only bits. From the ACPI specification, "Hardware |
* Write-Only Bits": "Upon reads to registers with write-only bits, |
* software masks out all write-only bits." |
*/ |
value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; |
break; |
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ |
status = |
acpi_hw_read(&value, &acpi_gbl_FADT.xpm2_control_block); |
break; |
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ |
status = acpi_hw_read(&value, &acpi_gbl_FADT.xpm_timer_block); |
break; |
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ |
status = |
acpi_hw_read_port(acpi_gbl_FADT.smi_command, &value, 8); |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id)); |
status = AE_BAD_PARAMETER; |
break; |
} |
if (ACPI_SUCCESS(status)) { |
*return_value = value; |
} |
return_ACPI_STATUS(status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_register_write |
* |
* PARAMETERS: register_id - ACPI Register ID |
* value - The value to write |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write to the specified ACPI register |
* |
* NOTE: In accordance with the ACPI specification, this function automatically |
* preserves the value of the following bits, meaning that these bits cannot be |
* changed via this interface: |
* |
* PM1_CONTROL[0] = SCI_EN |
* PM1_CONTROL[9] |
* PM1_STATUS[11] |
* |
* ACPI References: |
* 1) Hardware Ignored Bits: When software writes to a register with ignored |
* bit fields, it preserves the ignored bit fields |
* 2) SCI_EN: OSPM always preserves this bit position |
* |
******************************************************************************/ |
acpi_status acpi_hw_register_write(u32 register_id, u32 value) |
{ |
acpi_status status; |
u32 read_value; |
ACPI_FUNCTION_TRACE(hw_register_write); |
switch (register_id) { |
case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ |
/* |
* Handle the "ignored" bit in PM1 Status. According to the ACPI |
* specification, ignored bits are to be preserved when writing. |
* Normally, this would mean a read/modify/write sequence. However, |
* preserving a bit in the status register is different. Writing a |
* one clears the status, and writing a zero preserves the status. |
* Therefore, we must always write zero to the ignored bit. |
* |
* This behavior is clarified in the ACPI 4.0 specification. |
*/ |
value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; |
status = acpi_hw_write_multiple(value, |
&acpi_gbl_xpm1a_status, |
&acpi_gbl_xpm1b_status); |
break; |
case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ |
status = acpi_hw_write_multiple(value, |
&acpi_gbl_xpm1a_enable, |
&acpi_gbl_xpm1b_enable); |
break; |
case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ |
/* |
* Perform a read first to preserve certain bits (per ACPI spec) |
* Note: This includes SCI_EN, we never want to change this bit |
*/ |
status = acpi_hw_read_multiple(&read_value, |
&acpi_gbl_FADT. |
xpm1a_control_block, |
&acpi_gbl_FADT. |
xpm1b_control_block); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Insert the bits to be preserved */ |
ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, |
read_value); |
/* Now we can write the data */ |
status = acpi_hw_write_multiple(value, |
&acpi_gbl_FADT. |
xpm1a_control_block, |
&acpi_gbl_FADT. |
xpm1b_control_block); |
break; |
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ |
/* |
* For control registers, all reserved bits must be preserved, |
* as per the ACPI spec. |
*/ |
status = |
acpi_hw_read(&read_value, |
&acpi_gbl_FADT.xpm2_control_block); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Insert the bits to be preserved */ |
ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS, |
read_value); |
status = |
acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block); |
break; |
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ |
status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block); |
break; |
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ |
/* SMI_CMD is currently always in IO space */ |
status = |
acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8); |
break; |
default: |
ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id)); |
status = AE_BAD_PARAMETER; |
break; |
} |
exit: |
return_ACPI_STATUS(status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_read_multiple |
* |
* PARAMETERS: value - Where the register value is returned |
* register_a - First ACPI register (required) |
* register_b - Second ACPI register (optional) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_read_multiple(u32 *value, |
struct acpi_generic_address *register_a, |
struct acpi_generic_address *register_b) |
{ |
u32 value_a = 0; |
u32 value_b = 0; |
acpi_status status; |
/* The first register is always required */ |
status = acpi_hw_read(&value_a, register_a); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Second register is optional */ |
if (register_b->address) { |
status = acpi_hw_read(&value_b, register_b); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
/* |
* OR the two return values together. No shifting or masking is necessary, |
* because of how the PM1 registers are defined in the ACPI specification: |
* |
* "Although the bits can be split between the two register blocks (each |
* register block has a unique pointer within the FADT), the bit positions |
* are maintained. The register block with unimplemented bits (that is, |
* those implemented in the other register block) always returns zeros, |
* and writes have no side effects" |
*/ |
*value = (value_a | value_b); |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_write_multiple |
* |
* PARAMETERS: value - The value to write |
* register_a - First ACPI register (required) |
* register_b - Second ACPI register (optional) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_write_multiple(u32 value, |
struct acpi_generic_address *register_a, |
struct acpi_generic_address *register_b) |
{ |
acpi_status status; |
/* The first register is always required */ |
status = acpi_hw_write(value, register_a); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* Second register is optional |
* |
* No bit shifting or clearing is necessary, because of how the PM1 |
* registers are defined in the ACPI specification: |
* |
* "Although the bits can be split between the two register blocks (each |
* register block has a unique pointer within the FADT), the bit positions |
* are maintained. The register block with unimplemented bits (that is, |
* those implemented in the other register block) always returns zeros, |
* and writes have no side effects" |
*/ |
if (register_b->address) { |
status = acpi_hw_write(value, register_b); |
} |
return (status); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/hwsleep.c |
---|
0,0 → 1,345 |
/****************************************************************************** |
* |
* Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the |
* original/legacy sleep/PM registers. |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include <linux/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwsleep") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_legacy_sleep |
* |
* PARAMETERS: sleep_state - Which sleep state to enter |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers |
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
* |
******************************************************************************/ |
acpi_status acpi_hw_legacy_sleep(u8 sleep_state) |
{ |
struct acpi_bit_register_info *sleep_type_reg_info; |
struct acpi_bit_register_info *sleep_enable_reg_info; |
u32 pm1a_control; |
u32 pm1b_control; |
u32 in_value; |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_legacy_sleep); |
sleep_type_reg_info = |
acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE); |
sleep_enable_reg_info = |
acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE); |
/* Clear wake status */ |
status = |
acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Clear all fixed and general purpose status bits */ |
status = acpi_hw_clear_acpi_status(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* 1) Disable/Clear all GPEs |
* 2) Enable all wakeup GPEs |
*/ |
status = acpi_hw_disable_all_gpes(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_gbl_system_awake_and_running = FALSE; |
status = acpi_hw_enable_all_wakeup_gpes(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get current value of PM1A control */ |
status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, |
&pm1a_control); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INIT, |
"Entering sleep state [S%u]\n", sleep_state)); |
/* Clear the SLP_EN and SLP_TYP fields */ |
pm1a_control &= ~(sleep_type_reg_info->access_bit_mask | |
sleep_enable_reg_info->access_bit_mask); |
pm1b_control = pm1a_control; |
/* Insert the SLP_TYP bits */ |
pm1a_control |= |
(acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position); |
pm1b_control |= |
(acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position); |
/* |
* We split the writes of SLP_TYP and SLP_EN to workaround |
* poorly implemented hardware. |
*/ |
/* Write #1: write the SLP_TYP data to the PM1 Control registers */ |
status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Insert the sleep enable (SLP_EN) bit */ |
pm1a_control |= sleep_enable_reg_info->access_bit_mask; |
pm1b_control |= sleep_enable_reg_info->access_bit_mask; |
/* Flush caches, as per ACPI specification */ |
ACPI_FLUSH_CPU_CACHE(); |
status = acpi_os_prepare_sleep(sleep_state, pm1a_control, |
pm1b_control); |
if (ACPI_SKIP(status)) |
return_ACPI_STATUS(AE_OK); |
if (ACPI_FAILURE(status)) |
return_ACPI_STATUS(status); |
/* Write #2: Write both SLP_TYP + SLP_EN */ |
status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (sleep_state > ACPI_STATE_S3) { |
/* |
* We wanted to sleep > S3, but it didn't happen (by virtue of the |
* fact that we are still executing!) |
* |
* Wait ten seconds, then try again. This is to get S4/S5 to work on |
* all machines. |
* |
* We wait so long to allow chipsets that poll this reg very slowly |
* to still read the right value. Ideally, this block would go |
* away entirely. |
*/ |
acpi_os_stall(10 * ACPI_USEC_PER_SEC); |
status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL, |
sleep_enable_reg_info-> |
access_bit_mask); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* Wait for transition back to Working State */ |
do { |
status = |
acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} while (!in_value); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_legacy_wake_prep |
* |
* PARAMETERS: sleep_state - Which sleep state we just exited |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a |
* sleep. |
* Called with interrupts ENABLED. |
* |
******************************************************************************/ |
acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state) |
{ |
acpi_status status; |
struct acpi_bit_register_info *sleep_type_reg_info; |
struct acpi_bit_register_info *sleep_enable_reg_info; |
u32 pm1a_control; |
u32 pm1b_control; |
ACPI_FUNCTION_TRACE(hw_legacy_wake_prep); |
/* |
* Set SLP_TYPE and SLP_EN to state S0. |
* This is unclear from the ACPI Spec, but it is required |
* by some machines. |
*/ |
status = acpi_get_sleep_type_data(ACPI_STATE_S0, |
&acpi_gbl_sleep_type_a, |
&acpi_gbl_sleep_type_b); |
if (ACPI_SUCCESS(status)) { |
sleep_type_reg_info = |
acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE); |
sleep_enable_reg_info = |
acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE); |
/* Get current value of PM1A control */ |
status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, |
&pm1a_control); |
if (ACPI_SUCCESS(status)) { |
/* Clear the SLP_EN and SLP_TYP fields */ |
pm1a_control &= ~(sleep_type_reg_info->access_bit_mask | |
sleep_enable_reg_info-> |
access_bit_mask); |
pm1b_control = pm1a_control; |
/* Insert the SLP_TYP bits */ |
pm1a_control |= (acpi_gbl_sleep_type_a << |
sleep_type_reg_info->bit_position); |
pm1b_control |= (acpi_gbl_sleep_type_b << |
sleep_type_reg_info->bit_position); |
/* Write the control registers and ignore any errors */ |
(void)acpi_hw_write_pm1_control(pm1a_control, |
pm1b_control); |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_legacy_wake |
* |
* PARAMETERS: sleep_state - Which sleep state we just exited |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep |
* Called with interrupts ENABLED. |
* |
******************************************************************************/ |
acpi_status acpi_hw_legacy_wake(u8 sleep_state) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(hw_legacy_wake); |
/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ |
acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; |
acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING); |
/* |
* GPEs must be enabled before _WAK is called as GPEs |
* might get fired there |
* |
* Restore the GPEs: |
* 1) Disable/Clear all GPEs |
* 2) Enable all runtime GPEs |
*/ |
status = acpi_hw_disable_all_gpes(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_hw_enable_all_runtime_gpes(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Now we can execute _WAK, etc. Some machines require that the GPEs |
* are enabled before the wake methods are executed. |
*/ |
acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state); |
/* |
* Some BIOS code assumes that WAK_STS will be cleared on resume |
* and use it to determine whether the system is rebooting or |
* resuming. Clear WAK_STS for compatibility. |
*/ |
(void)acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, |
ACPI_CLEAR_STATUS); |
acpi_gbl_system_awake_and_running = TRUE; |
/* Enable power button */ |
(void) |
acpi_write_bit_register(acpi_gbl_fixed_event_info |
[ACPI_EVENT_POWER_BUTTON]. |
enable_register_id, ACPI_ENABLE_EVENT); |
(void) |
acpi_write_bit_register(acpi_gbl_fixed_event_info |
[ACPI_EVENT_POWER_BUTTON]. |
status_register_id, ACPI_CLEAR_STATUS); |
acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); |
return_ACPI_STATUS(status); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/hwtimer.c |
---|
0,0 → 1,202 |
/****************************************************************************** |
* |
* Name: hwtimer.c - ACPI Power Management Timer Interface |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwtimer") |
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
/****************************************************************************** |
* |
* FUNCTION: acpi_get_timer_resolution |
* |
* PARAMETERS: resolution - Where the resolution is returned |
* |
* RETURN: Status and timer resolution |
* |
* DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits). |
* |
******************************************************************************/ |
acpi_status acpi_get_timer_resolution(u32 * resolution) |
{ |
ACPI_FUNCTION_TRACE(acpi_get_timer_resolution); |
if (!resolution) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { |
*resolution = 24; |
} else { |
*resolution = 32; |
} |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_timer_resolution) |
/****************************************************************************** |
* |
* FUNCTION: acpi_get_timer |
* |
* PARAMETERS: ticks - Where the timer value is returned |
* |
* RETURN: Status and current timer value (ticks) |
* |
* DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). |
* |
******************************************************************************/ |
acpi_status acpi_get_timer(u32 * ticks) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_get_timer); |
if (!ticks) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* ACPI 5.0A: PM Timer is optional */ |
if (!acpi_gbl_FADT.xpm_timer_block.address) { |
return_ACPI_STATUS(AE_SUPPORT); |
} |
status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_timer) |
/****************************************************************************** |
* |
* FUNCTION: acpi_get_timer_duration |
* |
* PARAMETERS: start_ticks - Starting timestamp |
* end_ticks - End timestamp |
* time_elapsed - Where the elapsed time is returned |
* |
* RETURN: Status and time_elapsed |
* |
* DESCRIPTION: Computes the time elapsed (in microseconds) between two |
* PM Timer time stamps, taking into account the possibility of |
* rollovers, the timer resolution, and timer frequency. |
* |
* The PM Timer's clock ticks at roughly 3.6 times per |
* _microsecond_, and its clock continues through Cx state |
* transitions (unlike many CPU timestamp counters) -- making it |
* a versatile and accurate timer. |
* |
* Note that this function accommodates only a single timer |
* rollover. Thus for 24-bit timers, this function should only |
* be used for calculating durations less than ~4.6 seconds |
* (~20 minutes for 32-bit timers) -- calculations below: |
* |
* 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec |
* 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes |
* |
******************************************************************************/ |
acpi_status |
acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) |
{ |
acpi_status status; |
u32 delta_ticks; |
u64 quotient; |
ACPI_FUNCTION_TRACE(acpi_get_timer_duration); |
if (!time_elapsed) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* ACPI 5.0A: PM Timer is optional */ |
if (!acpi_gbl_FADT.xpm_timer_block.address) { |
return_ACPI_STATUS(AE_SUPPORT); |
} |
/* |
* Compute Tick Delta: |
* Handle (max one) timer rollovers on 24-bit versus 32-bit timers. |
*/ |
if (start_ticks < end_ticks) { |
delta_ticks = end_ticks - start_ticks; |
} else if (start_ticks > end_ticks) { |
if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { |
/* 24-bit Timer */ |
delta_ticks = |
(((0x00FFFFFF - start_ticks) + |
end_ticks) & 0x00FFFFFF); |
} else { |
/* 32-bit Timer */ |
delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; |
} |
} else { /* start_ticks == end_ticks */ |
*time_elapsed = 0; |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Compute Duration (Requires a 64-bit multiply and divide): |
* |
* time_elapsed (microseconds) = |
* (delta_ticks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY; |
*/ |
status = acpi_ut_short_divide(((u64)delta_ticks) * ACPI_USEC_PER_SEC, |
ACPI_PM_TIMER_FREQUENCY, "ient, NULL); |
*time_elapsed = (u32) quotient; |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_timer_duration) |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/drivers/acpi/acpica/hwvalid.c |
---|
0,0 → 1,328 |
/****************************************************************************** |
* |
* Module Name: hwvalid - I/O request validation |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwvalid") |
/* Local prototypes */ |
static acpi_status |
acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width); |
/* |
* Protected I/O ports. Some ports are always illegal, and some are |
* conditionally illegal. This table must remain ordered by port address. |
* |
* The table is used to implement the Microsoft port access rules that |
* first appeared in Windows XP. Some ports are always illegal, and some |
* ports are only illegal if the BIOS calls _OSI with a win_XP string or |
* later (meaning that the BIOS itelf is post-XP.) |
* |
* This provides ACPICA with the desired port protections and |
* Microsoft compatibility. |
* |
* Description of port entries: |
* DMA: DMA controller |
* PIC0: Programmable Interrupt Controller (8259A) |
* PIT1: System Timer 1 |
* PIT2: System Timer 2 failsafe |
* RTC: Real-time clock |
* CMOS: Extended CMOS |
* DMA1: DMA 1 page registers |
* DMA1L: DMA 1 Ch 0 low page |
* DMA2: DMA 2 page registers |
* DMA2L: DMA 2 low page refresh |
* ARBC: Arbitration control |
* SETUP: Reserved system board setup |
* POS: POS channel select |
* PIC1: Cascaded PIC |
* IDMA: ISA DMA |
* ELCR: PIC edge/level registers |
* PCI: PCI configuration space |
*/ |
static const struct acpi_port_info acpi_protected_ports[] = { |
{"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP}, |
{"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL}, |
{"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP}, |
{"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP}, |
{"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP}, |
{"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP}, |
{"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP}, |
{"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP}, |
{"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP}, |
{"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP}, |
{"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP}, |
{"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP}, |
{"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP}, |
{"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL}, |
{"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP}, |
{"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL}, |
{"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP} |
}; |
#define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (acpi_protected_ports) |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_validate_io_request |
* |
* PARAMETERS: Address Address of I/O port/register |
* bit_width Number of bits (8,16,32) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Validates an I/O request (address/length). Certain ports are |
* always illegal and some ports are only illegal depending on |
* the requests the BIOS AML code makes to the predefined |
* _OSI method. |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) |
{ |
u32 i; |
u32 byte_width; |
acpi_io_address last_address; |
const struct acpi_port_info *port_info; |
ACPI_FUNCTION_TRACE(hw_validate_io_request); |
/* Supported widths are 8/16/32 */ |
if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) { |
ACPI_ERROR((AE_INFO, |
"Bad BitWidth parameter: %8.8X", bit_width)); |
return (AE_BAD_PARAMETER); |
} |
port_info = acpi_protected_ports; |
byte_width = ACPI_DIV_8(bit_width); |
last_address = address + byte_width - 1; |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"Address %8.8X%8.8X LastAddress %8.8X%8.8X Length %X", |
ACPI_FORMAT_UINT64(address), |
ACPI_FORMAT_UINT64(last_address), byte_width)); |
/* Maximum 16-bit address in I/O space */ |
if (last_address > ACPI_UINT16_MAX) { |
ACPI_ERROR((AE_INFO, |
"Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X", |
ACPI_FORMAT_UINT64(address), byte_width)); |
return_ACPI_STATUS(AE_LIMIT); |
} |
/* Exit if requested address is not within the protected port table */ |
if (address > acpi_protected_ports[ACPI_PORT_INFO_ENTRIES - 1].end) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Check request against the list of protected I/O ports */ |
for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, port_info++) { |
/* |
* Check if the requested address range will write to a reserved |
* port. Four cases to consider: |
* |
* 1) Address range is contained completely in the port address range |
* 2) Address range overlaps port range at the port range start |
* 3) Address range overlaps port range at the port range end |
* 4) Address range completely encompasses the port range |
*/ |
if ((address <= port_info->end) |
&& (last_address >= port_info->start)) { |
/* Port illegality may depend on the _OSI calls made by the BIOS */ |
if (acpi_gbl_osi_data >= port_info->osi_dependency) { |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)", |
ACPI_FORMAT_UINT64(address), |
byte_width, port_info->name, |
port_info->start, |
port_info->end)); |
return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); |
} |
} |
/* Finished if address range ends before the end of this port */ |
if (last_address <= port_info->end) { |
break; |
} |
} |
return_ACPI_STATUS(AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_read_port |
* |
* PARAMETERS: Address Address of I/O port/register to read |
* Value Where value is placed |
* Width Number of bits |
* |
* RETURN: Status and value read from port |
* |
* DESCRIPTION: Read data from an I/O port or register. This is a front-end |
* to acpi_os_read_port that performs validation on both the port |
* address and the length. |
* |
*****************************************************************************/ |
acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) |
{ |
acpi_status status; |
u32 one_byte; |
u32 i; |
/* Truncate address to 16 bits if requested */ |
if (acpi_gbl_truncate_io_addresses) { |
address &= ACPI_UINT16_MAX; |
} |
/* Validate the entire request and perform the I/O */ |
status = acpi_hw_validate_io_request(address, width); |
if (ACPI_SUCCESS(status)) { |
status = acpi_os_read_port(address, value, width); |
return (status); |
} |
if (status != AE_AML_ILLEGAL_ADDRESS) { |
return (status); |
} |
/* |
* There has been a protection violation within the request. Fall |
* back to byte granularity port I/O and ignore the failing bytes. |
* This provides Windows compatibility. |
*/ |
for (i = 0, *value = 0; i < width; i += 8) { |
/* Validate and read one byte */ |
if (acpi_hw_validate_io_request(address, 8) == AE_OK) { |
status = acpi_os_read_port(address, &one_byte, 8); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
*value |= (one_byte << i); |
} |
address++; |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_hw_write_port |
* |
* PARAMETERS: Address Address of I/O port/register to write |
* Value Value to write |
* Width Number of bits |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write data to an I/O port or register. This is a front-end |
* to acpi_os_write_port that performs validation on both the port |
* address and the length. |
* |
*****************************************************************************/ |
acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) |
{ |
acpi_status status; |
u32 i; |
/* Truncate address to 16 bits if requested */ |
if (acpi_gbl_truncate_io_addresses) { |
address &= ACPI_UINT16_MAX; |
} |
/* Validate the entire request and perform the I/O */ |
status = acpi_hw_validate_io_request(address, width); |
if (ACPI_SUCCESS(status)) { |
status = acpi_os_write_port(address, value, width); |
return (status); |
} |
if (status != AE_AML_ILLEGAL_ADDRESS) { |
return (status); |
} |
/* |
* There has been a protection violation within the request. Fall |
* back to byte granularity port I/O and ignore the failing bytes. |
* This provides Windows compatibility. |
*/ |
for (i = 0; i < width; i += 8) { |
/* Validate and write one byte */ |
if (acpi_hw_validate_io_request(address, 8) == AE_OK) { |
status = |
acpi_os_write_port(address, (value >> i) & 0xFF, 8); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
address++; |
} |
return (AE_OK); |
} |
/drivers/acpi/acpica/hwxface.c |
---|
0,0 → 1,587 |
/****************************************************************************** |
* |
* Module Name: hwxface - Public ACPICA hardware interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwxface") |
/****************************************************************************** |
* |
* FUNCTION: acpi_reset |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Set reset register in memory or IO space. Note: Does not |
* support reset register in PCI config space, this must be |
* handled separately. |
* |
******************************************************************************/ |
acpi_status acpi_reset(void) |
{ |
struct acpi_generic_address *reset_reg; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_reset); |
reset_reg = &acpi_gbl_FADT.reset_register; |
/* Check if the reset register is supported */ |
if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || |
!reset_reg->address) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { |
/* |
* For I/O space, write directly to the OSL. This bypasses the port |
* validation mechanism, which may block a valid write to the reset |
* register. |
* |
* NOTE: |
* The ACPI spec requires the reset register width to be 8, so we |
* hardcode it here and ignore the FADT value. This maintains |
* compatibility with other ACPI implementations that have allowed |
* BIOS code with bad register width values to go unnoticed. |
*/ |
status = |
acpi_os_write_port((acpi_io_address) reset_reg->address, |
acpi_gbl_FADT.reset_value, |
ACPI_RESET_REGISTER_WIDTH); |
} else { |
/* Write the reset value to the reset register */ |
status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_reset) |
/****************************************************************************** |
* |
* FUNCTION: acpi_read |
* |
* PARAMETERS: value - Where the value is returned |
* reg - GAS register structure |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read from either memory or IO space. |
* |
* LIMITATIONS: <These limitations also apply to acpi_write> |
* bit_width must be exactly 8, 16, 32, or 64. |
* space_ID must be system_memory or system_IO. |
* bit_offset and access_width are currently ignored, as there has |
* not been a need to implement these. |
* |
******************************************************************************/ |
acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg) |
{ |
u32 value_lo; |
u32 value_hi; |
u32 width; |
u64 address; |
acpi_status status; |
ACPI_FUNCTION_NAME(acpi_read); |
if (!return_value) { |
return (AE_BAD_PARAMETER); |
} |
/* Validate contents of the GAS register. Allow 64-bit transfers */ |
status = acpi_hw_validate_register(reg, 64, &address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* Two address spaces supported: Memory or I/O. PCI_Config is |
* not supported here because the GAS structure is insufficient |
*/ |
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
status = acpi_os_read_memory((acpi_physical_address) |
address, return_value, |
reg->bit_width); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ |
value_lo = 0; |
value_hi = 0; |
width = reg->bit_width; |
if (width == 64) { |
width = 32; /* Break into two 32-bit transfers */ |
} |
status = acpi_hw_read_port((acpi_io_address) |
address, &value_lo, width); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (reg->bit_width == 64) { |
/* Read the top 32 bits */ |
status = acpi_hw_read_port((acpi_io_address) |
(address + 4), &value_hi, |
32); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
/* Set the return value only if status is AE_OK */ |
*return_value = (value_lo | ((u64)value_hi << 32)); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n", |
ACPI_FORMAT_UINT64(*return_value), reg->bit_width, |
ACPI_FORMAT_UINT64(address), |
acpi_ut_get_region_name(reg->space_id))); |
return (AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_read) |
/****************************************************************************** |
* |
* FUNCTION: acpi_write |
* |
* PARAMETERS: value - Value to be written |
* reg - GAS register structure |
* |
* RETURN: Status |
* |
* DESCRIPTION: Write to either memory or IO space. |
* |
******************************************************************************/ |
acpi_status acpi_write(u64 value, struct acpi_generic_address *reg) |
{ |
u32 width; |
u64 address; |
acpi_status status; |
ACPI_FUNCTION_NAME(acpi_write); |
/* Validate contents of the GAS register. Allow 64-bit transfers */ |
status = acpi_hw_validate_register(reg, 64, &address); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* Two address spaces supported: Memory or IO. PCI_Config is |
* not supported here because the GAS structure is insufficient |
*/ |
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
status = acpi_os_write_memory((acpi_physical_address) |
address, value, reg->bit_width); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ |
width = reg->bit_width; |
if (width == 64) { |
width = 32; /* Break into two 32-bit transfers */ |
} |
status = acpi_hw_write_port((acpi_io_address) |
address, ACPI_LODWORD(value), |
width); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (reg->bit_width == 64) { |
status = acpi_hw_write_port((acpi_io_address) |
(address + 4), |
ACPI_HIDWORD(value), 32); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", |
ACPI_FORMAT_UINT64(value), reg->bit_width, |
ACPI_FORMAT_UINT64(address), |
acpi_ut_get_region_name(reg->space_id))); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_write) |
#if (!ACPI_REDUCED_HARDWARE) |
/******************************************************************************* |
* |
* FUNCTION: acpi_read_bit_register |
* |
* PARAMETERS: register_id - ID of ACPI Bit Register to access |
* return_value - Value that was read from the register, |
* normalized to bit position zero. |
* |
* RETURN: Status and the value read from the specified Register. Value |
* returned is normalized to bit0 (is shifted all the way right) |
* |
* DESCRIPTION: ACPI bit_register read function. Does not acquire the HW lock. |
* |
* SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and |
* PM2 Control. |
* |
* Note: The hardware lock is not required when reading the ACPI bit registers |
* since almost all of them are single bit and it does not matter that |
* the parent hardware register can be split across two physical |
* registers. The only multi-bit field is SLP_TYP in the PM1 control |
* register, but this field does not cross an 8-bit boundary (nor does |
* it make much sense to actually read this field.) |
* |
******************************************************************************/ |
acpi_status acpi_read_bit_register(u32 register_id, u32 *return_value) |
{ |
struct acpi_bit_register_info *bit_reg_info; |
u32 register_value; |
u32 value; |
acpi_status status; |
ACPI_FUNCTION_TRACE_U32(acpi_read_bit_register, register_id); |
/* Get the info structure corresponding to the requested ACPI Register */ |
bit_reg_info = acpi_hw_get_bit_register_info(register_id); |
if (!bit_reg_info) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Read the entire parent register */ |
status = acpi_hw_register_read(bit_reg_info->parent_register, |
®ister_value); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Normalize the value that was read, mask off other bits */ |
value = ((register_value & bit_reg_info->access_bit_mask) |
>> bit_reg_info->bit_position); |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"BitReg %X, ParentReg %X, Actual %8.8X, ReturnValue %8.8X\n", |
register_id, bit_reg_info->parent_register, |
register_value, value)); |
*return_value = value; |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_read_bit_register) |
/******************************************************************************* |
* |
* FUNCTION: acpi_write_bit_register |
* |
* PARAMETERS: register_id - ID of ACPI Bit Register to access |
* value - Value to write to the register, in bit |
* position zero. The bit is automatically |
* shifted to the correct position. |
* |
* RETURN: Status |
* |
* DESCRIPTION: ACPI Bit Register write function. Acquires the hardware lock |
* since most operations require a read/modify/write sequence. |
* |
* SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and |
* PM2 Control. |
* |
* Note that at this level, the fact that there may be actually two |
* hardware registers (A and B - and B may not exist) is abstracted. |
* |
******************************************************************************/ |
acpi_status acpi_write_bit_register(u32 register_id, u32 value) |
{ |
struct acpi_bit_register_info *bit_reg_info; |
acpi_cpu_flags lock_flags; |
u32 register_value; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_U32(acpi_write_bit_register, register_id); |
/* Get the info structure corresponding to the requested ACPI Register */ |
bit_reg_info = acpi_hw_get_bit_register_info(register_id); |
if (!bit_reg_info) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); |
/* |
* At this point, we know that the parent register is one of the |
* following: PM1 Status, PM1 Enable, PM1 Control, or PM2 Control |
*/ |
if (bit_reg_info->parent_register != ACPI_REGISTER_PM1_STATUS) { |
/* |
* 1) Case for PM1 Enable, PM1 Control, and PM2 Control |
* |
* Perform a register read to preserve the bits that we are not |
* interested in |
*/ |
status = acpi_hw_register_read(bit_reg_info->parent_register, |
®ister_value); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* |
* Insert the input bit into the value that was just read |
* and write the register |
*/ |
ACPI_REGISTER_INSERT_VALUE(register_value, |
bit_reg_info->bit_position, |
bit_reg_info->access_bit_mask, |
value); |
status = acpi_hw_register_write(bit_reg_info->parent_register, |
register_value); |
} else { |
/* |
* 2) Case for PM1 Status |
* |
* The Status register is different from the rest. Clear an event |
* by writing 1, writing 0 has no effect. So, the only relevant |
* information is the single bit we're interested in, all others |
* should be written as 0 so they will be left unchanged. |
*/ |
register_value = ACPI_REGISTER_PREPARE_BITS(value, |
bit_reg_info-> |
bit_position, |
bit_reg_info-> |
access_bit_mask); |
/* No need to write the register if value is all zeros */ |
if (register_value) { |
status = |
acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, |
register_value); |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_IO, |
"BitReg %X, ParentReg %X, Value %8.8X, Actual %8.8X\n", |
register_id, bit_reg_info->parent_register, value, |
register_value)); |
unlock_and_exit: |
acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_write_bit_register) |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_sleep_type_data |
* |
* PARAMETERS: sleep_state - Numeric sleep state |
* *sleep_type_a - Where SLP_TYPa is returned |
* *sleep_type_b - Where SLP_TYPb is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested |
* sleep state via the appropriate \_Sx object. |
* |
* The sleep state package returned from the corresponding \_Sx_ object |
* must contain at least one integer. |
* |
* March 2005: |
* Added support for a package that contains two integers. This |
* goes against the ACPI specification which defines this object as a |
* package with one encoded DWORD integer. However, existing practice |
* by many BIOS vendors is to return a package with 2 or more integer |
* elements, at least one per sleep type (A/B). |
* |
* January 2013: |
* Therefore, we must be prepared to accept a package with either a |
* single integer or multiple integers. |
* |
* The single integer DWORD format is as follows: |
* BYTE 0 - Value for the PM1A SLP_TYP register |
* BYTE 1 - Value for the PM1B SLP_TYP register |
* BYTE 2-3 - Reserved |
* |
* The dual integer format is as follows: |
* Integer 0 - Value for the PM1A SLP_TYP register |
* Integer 1 - Value for the PM1A SLP_TYP register |
* |
******************************************************************************/ |
acpi_status |
acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) |
{ |
acpi_status status; |
struct acpi_evaluate_info *info; |
union acpi_operand_object **elements; |
ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); |
/* Validate parameters */ |
if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Allocate the evaluation information block */ |
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* |
* Evaluate the \_Sx namespace object containing the register values |
* for this state |
*/ |
info->relative_pathname = |
ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]); |
status = acpi_ns_evaluate(info); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Must have a return object */ |
if (!info->return_object) { |
ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", |
info->relative_pathname)); |
status = AE_AML_NO_RETURN_VALUE; |
goto cleanup; |
} |
/* Return object must be of type Package */ |
if (info->return_object->common.type != ACPI_TYPE_PACKAGE) { |
ACPI_ERROR((AE_INFO, |
"Sleep State return object is not a Package")); |
status = AE_AML_OPERAND_TYPE; |
goto cleanup1; |
} |
/* |
* Any warnings about the package length or the object types have |
* already been issued by the predefined name module -- there is no |
* need to repeat them here. |
*/ |
elements = info->return_object->package.elements; |
switch (info->return_object->package.count) { |
case 0: |
status = AE_AML_PACKAGE_LIMIT; |
break; |
case 1: |
if (elements[0]->common.type != ACPI_TYPE_INTEGER) { |
status = AE_AML_OPERAND_TYPE; |
break; |
} |
/* A valid _Sx_ package with one integer */ |
*sleep_type_a = (u8)elements[0]->integer.value; |
*sleep_type_b = (u8)(elements[0]->integer.value >> 8); |
break; |
case 2: |
default: |
if ((elements[0]->common.type != ACPI_TYPE_INTEGER) || |
(elements[1]->common.type != ACPI_TYPE_INTEGER)) { |
status = AE_AML_OPERAND_TYPE; |
break; |
} |
/* A valid _Sx_ package with two integers */ |
*sleep_type_a = (u8)elements[0]->integer.value; |
*sleep_type_b = (u8)elements[1]->integer.value; |
break; |
} |
cleanup1: |
acpi_ut_remove_reference(info->return_object); |
cleanup: |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"While evaluating Sleep State [%s]", |
info->relative_pathname)); |
} |
ACPI_FREE(info); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data) |
/drivers/acpi/acpica/hwxfsleep.c |
---|
0,0 → 1,504 |
/****************************************************************************** |
* |
* Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_HARDWARE |
ACPI_MODULE_NAME("hwxfsleep") |
/* Local prototypes */ |
#if (!ACPI_REDUCED_HARDWARE) |
static acpi_status |
acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, |
acpi_physical_address physical_address, |
acpi_physical_address physical_address64); |
#endif |
static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); |
/* |
* Dispatch table used to efficiently branch to the various sleep |
* functions. |
*/ |
#define ACPI_SLEEP_FUNCTION_ID 0 |
#define ACPI_WAKE_PREP_FUNCTION_ID 1 |
#define ACPI_WAKE_FUNCTION_ID 2 |
/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ |
static struct acpi_sleep_functions acpi_sleep_dispatch[] = { |
{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep), |
acpi_hw_extended_sleep}, |
{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep), |
acpi_hw_extended_wake_prep}, |
{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), acpi_hw_extended_wake} |
}; |
/* |
* These functions are removed for the ACPI_REDUCED_HARDWARE case: |
* acpi_set_firmware_waking_vectors |
* acpi_set_firmware_waking_vector |
* acpi_set_firmware_waking_vector64 |
* acpi_enter_sleep_state_s4bios |
*/ |
#if (!ACPI_REDUCED_HARDWARE) |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_set_firmware_waking_vectors |
* |
* PARAMETERS: facs - Pointer to FACS table |
* physical_address - 32-bit physical address of ACPI real mode |
* entry point. |
* physical_address64 - 64-bit physical address of ACPI protected |
* mode entry point. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Sets the firmware_waking_vector fields of the FACS |
* |
******************************************************************************/ |
static acpi_status |
acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, |
acpi_physical_address physical_address, |
acpi_physical_address physical_address64) |
{ |
ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vectors); |
/* |
* According to the ACPI specification 2.0c and later, the 64-bit |
* waking vector should be cleared and the 32-bit waking vector should |
* be used, unless we want the wake-up code to be called by the BIOS in |
* Protected Mode. Some systems (for example HP dv5-1004nr) are known |
* to fail to resume if the 64-bit vector is used. |
*/ |
/* Set the 32-bit vector */ |
facs->firmware_waking_vector = (u32)physical_address; |
if (facs->length > 32) { |
if (facs->version >= 1) { |
/* Set the 64-bit vector */ |
facs->xfirmware_waking_vector = physical_address64; |
} else { |
/* Clear the 64-bit vector if it exists */ |
facs->xfirmware_waking_vector = 0; |
} |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_set_firmware_waking_vectors |
* |
* PARAMETERS: physical_address - 32-bit physical address of ACPI real mode |
* entry point. |
* physical_address64 - 64-bit physical address of ACPI protected |
* mode entry point. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Sets the firmware_waking_vector fields of the FACS |
* |
******************************************************************************/ |
acpi_status |
acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, |
acpi_physical_address physical_address64) |
{ |
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); |
if (acpi_gbl_FACS) { |
(void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_FACS, |
physical_address, |
physical_address64); |
} |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vectors) |
/******************************************************************************* |
* |
* FUNCTION: acpi_set_firmware_waking_vector |
* |
* PARAMETERS: physical_address - 32-bit physical address of ACPI real mode |
* entry point. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS |
* |
******************************************************************************/ |
acpi_status acpi_set_firmware_waking_vector(u32 physical_address) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); |
status = acpi_set_firmware_waking_vectors((acpi_physical_address) |
physical_address, 0); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) |
#if ACPI_MACHINE_WIDTH == 64 |
/******************************************************************************* |
* |
* FUNCTION: acpi_set_firmware_waking_vector64 |
* |
* PARAMETERS: physical_address - 64-bit physical address of ACPI protected |
* mode entry point. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if |
* it exists in the table. This function is intended for use with |
* 64-bit host operating systems. |
* |
******************************************************************************/ |
acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); |
status = acpi_set_firmware_waking_vectors(0, |
(acpi_physical_address) |
physical_address); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_enter_sleep_state_s4bios |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform a S4 bios request. |
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
* |
******************************************************************************/ |
acpi_status acpi_enter_sleep_state_s4bios(void) |
{ |
u32 in_value; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); |
/* Clear the wake status bit (PM1) */ |
status = |
acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_hw_clear_acpi_status(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* 1) Disable/Clear all GPEs |
* 2) Enable all wakeup GPEs |
*/ |
status = acpi_hw_disable_all_gpes(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_gbl_system_awake_and_running = FALSE; |
status = acpi_hw_enable_all_wakeup_gpes(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_FLUSH_CPU_CACHE(); |
status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, |
(u32)acpi_gbl_FADT.s4_bios_request, 8); |
do { |
acpi_os_stall(ACPI_USEC_PER_MSEC); |
status = |
acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} while (!in_value); |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_hw_sleep_dispatch |
* |
* PARAMETERS: sleep_state - Which sleep state to enter/exit |
* function_id - Sleep, wake_prep, or Wake |
* |
* RETURN: Status from the invoked sleep handling function. |
* |
* DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling |
* function. |
* |
******************************************************************************/ |
static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) |
{ |
acpi_status status; |
struct acpi_sleep_functions *sleep_functions = |
&acpi_sleep_dispatch[function_id]; |
#if (!ACPI_REDUCED_HARDWARE) |
/* |
* If the Hardware Reduced flag is set (from the FADT), we must |
* use the extended sleep registers (FADT). Note: As per the ACPI |
* specification, these extended registers are to be used for HW-reduced |
* platforms only. They are not general-purpose replacements for the |
* legacy PM register sleep support. |
*/ |
if (acpi_gbl_reduced_hardware) { |
status = sleep_functions->extended_function(sleep_state); |
} else { |
/* Legacy sleep */ |
status = sleep_functions->legacy_function(sleep_state); |
} |
return (status); |
#else |
/* |
* For the case where reduced-hardware-only code is being generated, |
* we know that only the extended sleep registers are available |
*/ |
status = sleep_functions->extended_function(sleep_state); |
return (status); |
#endif /* !ACPI_REDUCED_HARDWARE */ |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_enter_sleep_state_prep |
* |
* PARAMETERS: sleep_state - Which sleep state to enter |
* |
* RETURN: Status |
* |
* DESCRIPTION: Prepare to enter a system sleep state. |
* This function must execute with interrupts enabled. |
* We break sleeping into 2 stages so that OSPM can handle |
* various OS-specific tasks between the two steps. |
* |
******************************************************************************/ |
acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) |
{ |
acpi_status status; |
struct acpi_object_list arg_list; |
union acpi_object arg; |
u32 sst_value; |
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep); |
status = acpi_get_sleep_type_data(sleep_state, |
&acpi_gbl_sleep_type_a, |
&acpi_gbl_sleep_type_b); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Execute the _PTS method (Prepare To Sleep) */ |
arg_list.count = 1; |
arg_list.pointer = &arg; |
arg.type = ACPI_TYPE_INTEGER; |
arg.integer.value = sleep_state; |
status = |
acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL); |
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
return_ACPI_STATUS(status); |
} |
/* Setup the argument to the _SST method (System STatus) */ |
switch (sleep_state) { |
case ACPI_STATE_S0: |
sst_value = ACPI_SST_WORKING; |
break; |
case ACPI_STATE_S1: |
case ACPI_STATE_S2: |
case ACPI_STATE_S3: |
sst_value = ACPI_SST_SLEEPING; |
break; |
case ACPI_STATE_S4: |
sst_value = ACPI_SST_SLEEP_CONTEXT; |
break; |
default: |
sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */ |
break; |
} |
/* |
* Set the system indicators to show the desired sleep state. |
* _SST is an optional method (return no error if not found) |
*/ |
acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value); |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) |
/******************************************************************************* |
* |
* FUNCTION: acpi_enter_sleep_state |
* |
* PARAMETERS: sleep_state - Which sleep state to enter |
* |
* RETURN: Status |
* |
* DESCRIPTION: Enter a system sleep state |
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
* |
******************************************************************************/ |
acpi_status acpi_enter_sleep_state(u8 sleep_state) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); |
if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || |
(acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { |
ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", |
acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b)); |
return_ACPI_STATUS(AE_AML_OPERAND_VALUE); |
} |
status = acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) |
/******************************************************************************* |
* |
* FUNCTION: acpi_leave_sleep_state_prep |
* |
* PARAMETERS: sleep_state - Which sleep state we are exiting |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a |
* sleep. Called with interrupts DISABLED. |
* We break wake/resume into 2 stages so that OSPM can handle |
* various OS-specific tasks between the two steps. |
* |
******************************************************************************/ |
acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); |
status = |
acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_PREP_FUNCTION_ID); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep) |
/******************************************************************************* |
* |
* FUNCTION: acpi_leave_sleep_state |
* |
* PARAMETERS: sleep_state - Which sleep state we are exiting |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep |
* Called with interrupts ENABLED. |
* |
******************************************************************************/ |
acpi_status acpi_leave_sleep_state(u8 sleep_state) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); |
status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state) |
/drivers/acpi/acpica/nsaccess.c |
---|
0,0 → 1,680 |
/******************************************************************************* |
* |
* Module Name: nsaccess - Top-level functions for accessing ACPI namespace |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#include "acdispat.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsaccess") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_root_initialize |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Allocate and initialize the default root named objects |
* |
* MUTEX: Locks namespace for entire execution |
* |
******************************************************************************/ |
acpi_status acpi_ns_root_initialize(void) |
{ |
acpi_status status; |
const struct acpi_predefined_names *init_val = NULL; |
struct acpi_namespace_node *new_node; |
union acpi_operand_object *obj_desc; |
acpi_string val = NULL; |
ACPI_FUNCTION_TRACE(ns_root_initialize); |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* The global root ptr is initially NULL, so a non-NULL value indicates |
* that acpi_ns_root_initialize() has already been called; just return. |
*/ |
if (acpi_gbl_root_node) { |
status = AE_OK; |
goto unlock_and_exit; |
} |
/* |
* Tell the rest of the subsystem that the root is initialized |
* (This is OK because the namespace is locked) |
*/ |
acpi_gbl_root_node = &acpi_gbl_root_node_struct; |
/* Enter the pre-defined names in the name table */ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Entering predefined entries into namespace\n")); |
for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { |
/* _OSI is optional for now, will be permanent later */ |
if (!strcmp(init_val->name, "_OSI") |
&& !acpi_gbl_create_osi_method) { |
continue; |
} |
status = acpi_ns_lookup(NULL, init_val->name, init_val->type, |
ACPI_IMODE_LOAD_PASS2, |
ACPI_NS_NO_UPSEARCH, NULL, &new_node); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not create predefined name %s", |
init_val->name)); |
continue; |
} |
/* |
* Name entered successfully. If entry in pre_defined_names[] specifies |
* an initial value, create the initial value. |
*/ |
if (init_val->val) { |
status = acpi_os_predefined_override(init_val, &val); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not override predefined %s", |
init_val->name)); |
} |
if (!val) { |
val = init_val->val; |
} |
/* |
* Entry requests an initial value, allocate a |
* descriptor for it. |
*/ |
obj_desc = |
acpi_ut_create_internal_object(init_val->type); |
if (!obj_desc) { |
status = AE_NO_MEMORY; |
goto unlock_and_exit; |
} |
/* |
* Convert value string from table entry to |
* internal representation. Only types actually |
* used for initial values are implemented here. |
*/ |
switch (init_val->type) { |
case ACPI_TYPE_METHOD: |
obj_desc->method.param_count = |
(u8) ACPI_TO_INTEGER(val); |
obj_desc->common.flags |= AOPOBJ_DATA_VALID; |
#if defined (ACPI_ASL_COMPILER) |
/* Save the parameter count for the iASL compiler */ |
new_node->value = obj_desc->method.param_count; |
#else |
/* Mark this as a very SPECIAL method */ |
obj_desc->method.info_flags = |
ACPI_METHOD_INTERNAL_ONLY; |
obj_desc->method.dispatch.implementation = |
acpi_ut_osi_implementation; |
#endif |
break; |
case ACPI_TYPE_INTEGER: |
obj_desc->integer.value = ACPI_TO_INTEGER(val); |
break; |
case ACPI_TYPE_STRING: |
/* Build an object around the static string */ |
obj_desc->string.length = (u32)strlen(val); |
obj_desc->string.pointer = val; |
obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; |
break; |
case ACPI_TYPE_MUTEX: |
obj_desc->mutex.node = new_node; |
obj_desc->mutex.sync_level = |
(u8) (ACPI_TO_INTEGER(val) - 1); |
/* Create a mutex */ |
status = |
acpi_os_create_mutex(&obj_desc->mutex. |
os_mutex); |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(obj_desc); |
goto unlock_and_exit; |
} |
/* Special case for ACPI Global Lock */ |
if (strcmp(init_val->name, "_GL_") == 0) { |
acpi_gbl_global_lock_mutex = obj_desc; |
/* Create additional counting semaphore for global lock */ |
status = |
acpi_os_create_semaphore(1, 0, |
&acpi_gbl_global_lock_semaphore); |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference |
(obj_desc); |
goto unlock_and_exit; |
} |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Unsupported initial type value 0x%X", |
init_val->type)); |
acpi_ut_remove_reference(obj_desc); |
obj_desc = NULL; |
continue; |
} |
/* Store pointer to value descriptor in the Node */ |
status = acpi_ns_attach_object(new_node, obj_desc, |
obj_desc->common.type); |
/* Remove local reference to the object */ |
acpi_ut_remove_reference(obj_desc); |
} |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
/* Save a handle to "_GPE", it is always present */ |
if (ACPI_SUCCESS(status)) { |
status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH, |
&acpi_gbl_fadt_gpe_device); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_lookup |
* |
* PARAMETERS: scope_info - Current scope info block |
* pathname - Search pathname, in internal format |
* (as represented in the AML stream) |
* type - Type associated with name |
* interpreter_mode - IMODE_LOAD_PASS2 => add name if not found |
* flags - Flags describing the search restrictions |
* walk_state - Current state of the walk |
* return_node - Where the Node is placed (if found |
* or created successfully) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Find or enter the passed name in the name space. |
* Log an error if name not found in Exec mode. |
* |
* MUTEX: Assumes namespace is locked. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_lookup(union acpi_generic_state *scope_info, |
char *pathname, |
acpi_object_type type, |
acpi_interpreter_mode interpreter_mode, |
u32 flags, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node **return_node) |
{ |
acpi_status status; |
char *path = pathname; |
struct acpi_namespace_node *prefix_node; |
struct acpi_namespace_node *current_node = NULL; |
struct acpi_namespace_node *this_node = NULL; |
u32 num_segments; |
u32 num_carats; |
acpi_name simple_name; |
acpi_object_type type_to_check_for; |
acpi_object_type this_search_type; |
u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; |
u32 local_flags; |
ACPI_FUNCTION_TRACE(ns_lookup); |
if (!return_node) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
local_flags = flags & |
~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_OVERRIDE_IF_FOUND | |
ACPI_NS_SEARCH_PARENT); |
*return_node = ACPI_ENTRY_NOT_FOUND; |
acpi_gbl_ns_lookup_count++; |
if (!acpi_gbl_root_node) { |
return_ACPI_STATUS(AE_NO_NAMESPACE); |
} |
/* Get the prefix scope. A null scope means use the root scope */ |
if ((!scope_info) || (!scope_info->scope.node)) { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Null scope prefix, using root node (%p)\n", |
acpi_gbl_root_node)); |
prefix_node = acpi_gbl_root_node; |
} else { |
prefix_node = scope_info->scope.node; |
if (ACPI_GET_DESCRIPTOR_TYPE(prefix_node) != |
ACPI_DESC_TYPE_NAMED) { |
ACPI_ERROR((AE_INFO, "%p is not a namespace node [%s]", |
prefix_node, |
acpi_ut_get_descriptor_name(prefix_node))); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
if (!(flags & ACPI_NS_PREFIX_IS_SCOPE)) { |
/* |
* This node might not be a actual "scope" node (such as a |
* Device/Method, etc.) It could be a Package or other object |
* node. Backup up the tree to find the containing scope node. |
*/ |
while (!acpi_ns_opens_scope(prefix_node->type) && |
prefix_node->type != ACPI_TYPE_ANY) { |
prefix_node = prefix_node->parent; |
} |
} |
} |
/* Save type. TBD: may be no longer necessary */ |
type_to_check_for = type; |
/* |
* Begin examination of the actual pathname |
*/ |
if (!pathname) { |
/* A Null name_path is allowed and refers to the root */ |
num_segments = 0; |
this_node = acpi_gbl_root_node; |
path = ""; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Null Pathname (Zero segments), Flags=%X\n", |
flags)); |
} else { |
/* |
* Name pointer is valid (and must be in internal name format) |
* |
* Check for scope prefixes: |
* |
* As represented in the AML stream, a namepath consists of an |
* optional scope prefix followed by a name segment part. |
* |
* If present, the scope prefix is either a Root Prefix (in |
* which case the name is fully qualified), or one or more |
* Parent Prefixes (in which case the name's scope is relative |
* to the current scope). |
*/ |
if (*path == (u8) AML_ROOT_PREFIX) { |
/* Pathname is fully qualified, start from the root */ |
this_node = acpi_gbl_root_node; |
search_parent_flag = ACPI_NS_NO_UPSEARCH; |
/* Point to name segment part */ |
path++; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Path is absolute from root [%p]\n", |
this_node)); |
} else { |
/* Pathname is relative to current scope, start there */ |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Searching relative to prefix scope [%4.4s] (%p)\n", |
acpi_ut_get_node_name(prefix_node), |
prefix_node)); |
/* |
* Handle multiple Parent Prefixes (carat) by just getting |
* the parent node for each prefix instance. |
*/ |
this_node = prefix_node; |
num_carats = 0; |
while (*path == (u8) AML_PARENT_PREFIX) { |
/* Name is fully qualified, no search rules apply */ |
search_parent_flag = ACPI_NS_NO_UPSEARCH; |
/* |
* Point past this prefix to the name segment |
* part or the next Parent Prefix |
*/ |
path++; |
/* Backup to the parent node */ |
num_carats++; |
this_node = this_node->parent; |
if (!this_node) { |
/* Current scope has no parent scope */ |
ACPI_ERROR((AE_INFO, |
"%s: Path has too many parent prefixes (^) " |
"- reached beyond root node", |
pathname)); |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
} |
if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Search scope is [%4.4s], path has %u carat(s)\n", |
acpi_ut_get_node_name |
(this_node), num_carats)); |
} |
} |
/* |
* Determine the number of ACPI name segments in this pathname. |
* |
* The segment part consists of either: |
* - A Null name segment (0) |
* - A dual_name_prefix followed by two 4-byte name segments |
* - A multi_name_prefix followed by a byte indicating the |
* number of segments and the segments themselves. |
* - A single 4-byte name segment |
* |
* Examine the name prefix opcode, if any, to determine the number of |
* segments. |
*/ |
switch (*path) { |
case 0: |
/* |
* Null name after a root or parent prefixes. We already |
* have the correct target node and there are no name segments. |
*/ |
num_segments = 0; |
type = this_node->type; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Prefix-only Pathname (Zero name segments), Flags=%X\n", |
flags)); |
break; |
case AML_DUAL_NAME_PREFIX: |
/* More than one name_seg, search rules do not apply */ |
search_parent_flag = ACPI_NS_NO_UPSEARCH; |
/* Two segments, point to first name segment */ |
num_segments = 2; |
path++; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Dual Pathname (2 segments, Flags=%X)\n", |
flags)); |
break; |
case AML_MULTI_NAME_PREFIX_OP: |
/* More than one name_seg, search rules do not apply */ |
search_parent_flag = ACPI_NS_NO_UPSEARCH; |
/* Extract segment count, point to first name segment */ |
path++; |
num_segments = (u32) (u8) * path; |
path++; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Multi Pathname (%u Segments, Flags=%X)\n", |
num_segments, flags)); |
break; |
default: |
/* |
* Not a Null name, no Dual or Multi prefix, hence there is |
* only one name segment and Pathname is already pointing to it. |
*/ |
num_segments = 1; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Simple Pathname (1 segment, Flags=%X)\n", |
flags)); |
break; |
} |
ACPI_DEBUG_EXEC(acpi_ns_print_pathname(num_segments, path)); |
} |
/* |
* Search namespace for each segment of the name. Loop through and |
* verify (or add to the namespace) each name segment. |
* |
* The object type is significant only at the last name |
* segment. (We don't care about the types along the path, only |
* the type of the final target object.) |
*/ |
this_search_type = ACPI_TYPE_ANY; |
current_node = this_node; |
while (num_segments && current_node) { |
num_segments--; |
if (!num_segments) { |
/* This is the last segment, enable typechecking */ |
this_search_type = type; |
/* |
* Only allow automatic parent search (search rules) if the caller |
* requested it AND we have a single, non-fully-qualified name_seg |
*/ |
if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) && |
(flags & ACPI_NS_SEARCH_PARENT)) { |
local_flags |= ACPI_NS_SEARCH_PARENT; |
} |
/* Set error flag according to caller */ |
if (flags & ACPI_NS_ERROR_IF_FOUND) { |
local_flags |= ACPI_NS_ERROR_IF_FOUND; |
} |
/* Set override flag according to caller */ |
if (flags & ACPI_NS_OVERRIDE_IF_FOUND) { |
local_flags |= ACPI_NS_OVERRIDE_IF_FOUND; |
} |
} |
/* Extract one ACPI name from the front of the pathname */ |
ACPI_MOVE_32_TO_32(&simple_name, path); |
/* Try to find the single (4 character) ACPI name */ |
status = |
acpi_ns_search_and_enter(simple_name, walk_state, |
current_node, interpreter_mode, |
this_search_type, local_flags, |
&this_node); |
if (ACPI_FAILURE(status)) { |
if (status == AE_NOT_FOUND) { |
/* Name not found in ACPI namespace */ |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Name [%4.4s] not found in scope [%4.4s] %p\n", |
(char *)&simple_name, |
(char *)¤t_node->name, |
current_node)); |
} |
*return_node = this_node; |
return_ACPI_STATUS(status); |
} |
/* More segments to follow? */ |
if (num_segments > 0) { |
/* |
* If we have an alias to an object that opens a scope (such as a |
* device or processor), we need to dereference the alias here so |
* that we can access any children of the original node (via the |
* remaining segments). |
*/ |
if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) { |
if (!this_node->object) { |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
if (acpi_ns_opens_scope |
(((struct acpi_namespace_node *) |
this_node->object)->type)) { |
this_node = |
(struct acpi_namespace_node *) |
this_node->object; |
} |
} |
} |
/* Special handling for the last segment (num_segments == 0) */ |
else { |
/* |
* Sanity typecheck of the target object: |
* |
* If 1) This is the last segment (num_segments == 0) |
* 2) And we are looking for a specific type |
* (Not checking for TYPE_ANY) |
* 3) Which is not an alias |
* 4) Which is not a local type (TYPE_SCOPE) |
* 5) And the type of target object is known (not TYPE_ANY) |
* 6) And target object does not match what we are looking for |
* |
* Then we have a type mismatch. Just warn and ignore it. |
*/ |
if ((type_to_check_for != ACPI_TYPE_ANY) && |
(type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && |
(type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) |
&& (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) |
&& (this_node->type != ACPI_TYPE_ANY) |
&& (this_node->type != type_to_check_for)) { |
/* Complain about a type mismatch */ |
ACPI_WARNING((AE_INFO, |
"NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", |
ACPI_CAST_PTR(char, &simple_name), |
acpi_ut_get_type_name(this_node-> |
type), |
acpi_ut_get_type_name |
(type_to_check_for))); |
} |
/* |
* If this is the last name segment and we are not looking for a |
* specific type, but the type of found object is known, use that |
* type to (later) see if it opens a scope. |
*/ |
if (type == ACPI_TYPE_ANY) { |
type = this_node->type; |
} |
} |
/* Point to next name segment and make this node current */ |
path += ACPI_NAME_SIZE; |
current_node = this_node; |
} |
/* Always check if we need to open a new scope */ |
if (!(flags & ACPI_NS_DONT_OPEN_SCOPE) && (walk_state)) { |
/* |
* If entry is a type which opens a scope, push the new scope on the |
* scope stack. |
*/ |
if (acpi_ns_opens_scope(type)) { |
status = |
acpi_ds_scope_stack_push(this_node, type, |
walk_state); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} |
*return_node = this_node; |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/nsalloc.c |
---|
0,0 → 1,526 |
/******************************************************************************* |
* |
* Module Name: nsalloc - Namespace allocation and deletion utilities |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsalloc") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_create_node |
* |
* PARAMETERS: name - Name of the new node (4 char ACPI name) |
* |
* RETURN: New namespace node (Null on failure) |
* |
* DESCRIPTION: Create a namespace node |
* |
******************************************************************************/ |
struct acpi_namespace_node *acpi_ns_create_node(u32 name) |
{ |
struct acpi_namespace_node *node; |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
u32 temp; |
#endif |
ACPI_FUNCTION_TRACE(ns_create_node); |
node = acpi_os_acquire_object(acpi_gbl_namespace_cache); |
if (!node) { |
return_PTR(NULL); |
} |
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++); |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
temp = acpi_gbl_ns_node_list->total_allocated - |
acpi_gbl_ns_node_list->total_freed; |
if (temp > acpi_gbl_ns_node_list->max_occupied) { |
acpi_gbl_ns_node_list->max_occupied = temp; |
} |
#endif |
node->name.integer = name; |
ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED); |
return_PTR(node); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_delete_node |
* |
* PARAMETERS: node - Node to be deleted |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete a namespace node. All node deletions must come through |
* here. Detaches any attached objects, including any attached |
* data. If a handler is associated with attached data, it is |
* invoked before the node is deleted. |
* |
******************************************************************************/ |
void acpi_ns_delete_node(struct acpi_namespace_node *node) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *next_desc; |
ACPI_FUNCTION_NAME(ns_delete_node); |
/* Detach an object if there is one */ |
acpi_ns_detach_object(node); |
/* |
* Delete an attached data object list if present (objects that were |
* attached via acpi_attach_data). Note: After any normal object is |
* detached above, the only possible remaining object(s) are data |
* objects, in a linked list. |
*/ |
obj_desc = node->object; |
while (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { |
/* Invoke the attached data deletion handler if present */ |
if (obj_desc->data.handler) { |
obj_desc->data.handler(node, obj_desc->data.pointer); |
} |
next_desc = obj_desc->common.next_object; |
acpi_ut_remove_reference(obj_desc); |
obj_desc = next_desc; |
} |
/* Special case for the statically allocated root node */ |
if (node == acpi_gbl_root_node) { |
return; |
} |
/* Now we can delete the node */ |
(void)acpi_os_release_object(acpi_gbl_namespace_cache, node); |
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n", |
node, acpi_gbl_current_node_count)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_remove_node |
* |
* PARAMETERS: node - Node to be removed/deleted |
* |
* RETURN: None |
* |
* DESCRIPTION: Remove (unlink) and delete a namespace node |
* |
******************************************************************************/ |
void acpi_ns_remove_node(struct acpi_namespace_node *node) |
{ |
struct acpi_namespace_node *parent_node; |
struct acpi_namespace_node *prev_node; |
struct acpi_namespace_node *next_node; |
ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node); |
parent_node = node->parent; |
prev_node = NULL; |
next_node = parent_node->child; |
/* Find the node that is the previous peer in the parent's child list */ |
while (next_node != node) { |
prev_node = next_node; |
next_node = next_node->peer; |
} |
if (prev_node) { |
/* Node is not first child, unlink it */ |
prev_node->peer = node->peer; |
} else { |
/* |
* Node is first child (has no previous peer). |
* Link peer list to parent |
*/ |
parent_node->child = node->peer; |
} |
/* Delete the node and any attached objects */ |
acpi_ns_delete_node(node); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_install_node |
* |
* PARAMETERS: walk_state - Current state of the walk |
* parent_node - The parent of the new Node |
* node - The new Node to install |
* type - ACPI object type of the new Node |
* |
* RETURN: None |
* |
* DESCRIPTION: Initialize a new namespace node and install it amongst |
* its peers. |
* |
* Note: Current namespace lookup is linear search. This appears |
* to be sufficient as namespace searches consume only a small |
* fraction of the execution time of the ACPI subsystem. |
* |
******************************************************************************/ |
void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node, /* Parent */ |
struct acpi_namespace_node *node, /* New Child */ |
acpi_object_type type) |
{ |
acpi_owner_id owner_id = 0; |
struct acpi_namespace_node *child_node; |
ACPI_FUNCTION_TRACE(ns_install_node); |
if (walk_state) { |
/* |
* Get the owner ID from the Walk state. The owner ID is used to |
* track table deletion and deletion of objects created by methods. |
*/ |
owner_id = walk_state->owner_id; |
if ((walk_state->method_desc) && |
(parent_node != walk_state->method_node)) { |
/* |
* A method is creating a new node that is not a child of the |
* method (it is non-local). Mark the executing method as having |
* modified the namespace. This is used for cleanup when the |
* method exits. |
*/ |
walk_state->method_desc->method.info_flags |= |
ACPI_METHOD_MODIFIED_NAMESPACE; |
} |
} |
/* Link the new entry into the parent and existing children */ |
node->peer = NULL; |
node->parent = parent_node; |
child_node = parent_node->child; |
if (!child_node) { |
parent_node->child = node; |
} else { |
/* Add node to the end of the peer list */ |
while (child_node->peer) { |
child_node = child_node->peer; |
} |
child_node->peer = node; |
} |
/* Init the new entry */ |
node->owner_id = owner_id; |
node->type = (u8) type; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", |
acpi_ut_get_node_name(node), |
acpi_ut_get_type_name(node->type), node, owner_id, |
acpi_ut_get_node_name(parent_node), |
acpi_ut_get_type_name(parent_node->type), |
parent_node)); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_delete_children |
* |
* PARAMETERS: parent_node - Delete this objects children |
* |
* RETURN: None. |
* |
* DESCRIPTION: Delete all children of the parent object. In other words, |
* deletes a "scope". |
* |
******************************************************************************/ |
void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) |
{ |
struct acpi_namespace_node *next_node; |
struct acpi_namespace_node *node_to_delete; |
ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node); |
if (!parent_node) { |
return_VOID; |
} |
/* Deallocate all children at this level */ |
next_node = parent_node->child; |
while (next_node) { |
/* Grandchildren should have all been deleted already */ |
if (next_node->child) { |
ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p", |
parent_node, next_node)); |
} |
/* |
* Delete this child node and move on to the next child in the list. |
* No need to unlink the node since we are deleting the entire branch. |
*/ |
node_to_delete = next_node; |
next_node = next_node->peer; |
acpi_ns_delete_node(node_to_delete); |
}; |
/* Clear the parent's child pointer */ |
parent_node->child = NULL; |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_delete_namespace_subtree |
* |
* PARAMETERS: parent_node - Root of the subtree to be deleted |
* |
* RETURN: None. |
* |
* DESCRIPTION: Delete a subtree of the namespace. This includes all objects |
* stored within the subtree. |
* |
******************************************************************************/ |
void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) |
{ |
struct acpi_namespace_node *child_node = NULL; |
u32 level = 1; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); |
if (!parent_node) { |
return_VOID; |
} |
/* Lock namespace for possible update */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_VOID; |
} |
/* |
* Traverse the tree of objects until we bubble back up |
* to where we started. |
*/ |
while (level > 0) { |
/* Get the next node in this scope (NULL if none) */ |
child_node = acpi_ns_get_next_node(parent_node, child_node); |
if (child_node) { |
/* Found a child node - detach any attached object */ |
acpi_ns_detach_object(child_node); |
/* Check if this node has any children */ |
if (child_node->child) { |
/* |
* There is at least one child of this node, |
* visit the node |
*/ |
level++; |
parent_node = child_node; |
child_node = NULL; |
} |
} else { |
/* |
* No more children of this parent node. |
* Move up to the grandparent. |
*/ |
level--; |
/* |
* Now delete all of the children of this parent |
* all at the same time. |
*/ |
acpi_ns_delete_children(parent_node); |
/* New "last child" is this parent node */ |
child_node = parent_node; |
/* Move up the tree to the grandparent */ |
parent_node = parent_node->parent; |
} |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_delete_namespace_by_owner |
* |
* PARAMETERS: owner_id - All nodes with this owner will be deleted |
* |
* RETURN: Status |
* |
* DESCRIPTION: Delete entries within the namespace that are owned by a |
* specific ID. Used to delete entire ACPI tables. All |
* reference counts are updated. |
* |
* MUTEX: Locks namespace during deletion walk. |
* |
******************************************************************************/ |
void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) |
{ |
struct acpi_namespace_node *child_node; |
struct acpi_namespace_node *deletion_node; |
struct acpi_namespace_node *parent_node; |
u32 level; |
acpi_status status; |
ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); |
if (owner_id == 0) { |
return_VOID; |
} |
/* Lock namespace for possible update */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_VOID; |
} |
deletion_node = NULL; |
parent_node = acpi_gbl_root_node; |
child_node = NULL; |
level = 1; |
/* |
* Traverse the tree of nodes until we bubble back up |
* to where we started. |
*/ |
while (level > 0) { |
/* |
* Get the next child of this parent node. When child_node is NULL, |
* the first child of the parent is returned |
*/ |
child_node = acpi_ns_get_next_node(parent_node, child_node); |
if (deletion_node) { |
acpi_ns_delete_children(deletion_node); |
acpi_ns_remove_node(deletion_node); |
deletion_node = NULL; |
} |
if (child_node) { |
if (child_node->owner_id == owner_id) { |
/* Found a matching child node - detach any attached object */ |
acpi_ns_detach_object(child_node); |
} |
/* Check if this node has any children */ |
if (child_node->child) { |
/* |
* There is at least one child of this node, |
* visit the node |
*/ |
level++; |
parent_node = child_node; |
child_node = NULL; |
} else if (child_node->owner_id == owner_id) { |
deletion_node = child_node; |
} |
} else { |
/* |
* No more children of this parent node. |
* Move up to the grandparent. |
*/ |
level--; |
if (level != 0) { |
if (parent_node->owner_id == owner_id) { |
deletion_node = parent_node; |
} |
} |
/* New "last child" is this parent node */ |
child_node = parent_node; |
/* Move up the tree to the grandparent */ |
parent_node = parent_node->parent; |
} |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_VOID; |
} |
/drivers/acpi/acpica/nsarguments.c |
---|
0,0 → 1,294 |
/****************************************************************************** |
* |
* Module Name: nsarguments - Validation of args for ACPI predefined methods |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acpredef.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsarguments") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_argument_types |
* |
* PARAMETERS: info - Method execution information block |
* |
* RETURN: None |
* |
* DESCRIPTION: Check the incoming argument count and all argument types |
* against the argument type list for a predefined name. |
* |
******************************************************************************/ |
void acpi_ns_check_argument_types(struct acpi_evaluate_info *info) |
{ |
u16 arg_type_list; |
u8 arg_count; |
u8 arg_type; |
u8 user_arg_type; |
u32 i; |
/* If not a predefined name, cannot typecheck args */ |
if (!info->predefined) { |
return; |
} |
arg_type_list = info->predefined->info.argument_list; |
arg_count = METHOD_GET_ARG_COUNT(arg_type_list); |
/* Typecheck all arguments */ |
for (i = 0; ((i < arg_count) && (i < info->param_count)); i++) { |
arg_type = METHOD_GET_NEXT_TYPE(arg_type_list); |
user_arg_type = info->parameters[i]->common.type; |
if (user_arg_type != arg_type) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
ACPI_WARN_ALWAYS, |
"Argument #%u type mismatch - " |
"Found [%s], ACPI requires [%s]", |
(i + 1), |
acpi_ut_get_type_name |
(user_arg_type), |
acpi_ut_get_type_name(arg_type))); |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_acpi_compliance |
* |
* PARAMETERS: pathname - Full pathname to the node (for error msgs) |
* node - Namespace node for the method/object |
* predefined - Pointer to entry in predefined name table |
* |
* RETURN: None |
* |
* DESCRIPTION: Check that the declared parameter count (in ASL/AML) for a |
* predefined name is what is expected (matches what is defined in |
* the ACPI specification for this predefined name.) |
* |
******************************************************************************/ |
void |
acpi_ns_check_acpi_compliance(char *pathname, |
struct acpi_namespace_node *node, |
const union acpi_predefined_info *predefined) |
{ |
u32 aml_param_count; |
u32 required_param_count; |
if (!predefined) { |
return; |
} |
/* Get the ACPI-required arg count from the predefined info table */ |
required_param_count = |
METHOD_GET_ARG_COUNT(predefined->info.argument_list); |
/* |
* If this object is not a control method, we can check if the ACPI |
* spec requires that it be a method. |
*/ |
if (node->type != ACPI_TYPE_METHOD) { |
if (required_param_count > 0) { |
/* Object requires args, must be implemented as a method */ |
ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, |
ACPI_WARN_ALWAYS, |
"Object (%s) must be a control method with %u arguments", |
acpi_ut_get_type_name(node-> |
type), |
required_param_count)); |
} else if (!required_param_count |
&& !predefined->info.expected_btypes) { |
/* Object requires no args and no return value, must be a method */ |
ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, |
ACPI_WARN_ALWAYS, |
"Object (%s) must be a control method " |
"with no arguments and no return value", |
acpi_ut_get_type_name(node-> |
type))); |
} |
return; |
} |
/* |
* This is a control method. |
* Check that the ASL/AML-defined parameter count for this method |
* matches the ACPI-required parameter count |
* |
* Some methods are allowed to have a "minimum" number of args (_SCP) |
* because their definition in ACPI has changed over time. |
* |
* Note: These are BIOS errors in the declaration of the object |
*/ |
aml_param_count = node->object->method.param_count; |
if (aml_param_count < required_param_count) { |
ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, |
"Insufficient arguments - " |
"ASL declared %u, ACPI requires %u", |
aml_param_count, |
required_param_count)); |
} else if ((aml_param_count > required_param_count) |
&& !(predefined->info. |
argument_list & ARG_COUNT_IS_MINIMUM)) { |
ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, |
"Excess arguments - " |
"ASL declared %u, ACPI requires %u", |
aml_param_count, |
required_param_count)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_argument_count |
* |
* PARAMETERS: pathname - Full pathname to the node (for error msgs) |
* node - Namespace node for the method/object |
* user_param_count - Number of args passed in by the caller |
* predefined - Pointer to entry in predefined name table |
* |
* RETURN: None |
* |
* DESCRIPTION: Check that incoming argument count matches the declared |
* parameter count (in the ASL/AML) for an object. |
* |
******************************************************************************/ |
void |
acpi_ns_check_argument_count(char *pathname, |
struct acpi_namespace_node *node, |
u32 user_param_count, |
const union acpi_predefined_info *predefined) |
{ |
u32 aml_param_count; |
u32 required_param_count; |
if (!predefined) { |
/* |
* Not a predefined name. Check the incoming user argument count |
* against the count that is specified in the method/object. |
*/ |
if (node->type != ACPI_TYPE_METHOD) { |
if (user_param_count) { |
ACPI_INFO_PREDEFINED((AE_INFO, pathname, |
ACPI_WARN_ALWAYS, |
"%u arguments were passed to a non-method ACPI object (%s)", |
user_param_count, |
acpi_ut_get_type_name |
(node->type))); |
} |
return; |
} |
/* |
* This is a control method. Check the parameter count. |
* We can only check the incoming argument count against the |
* argument count declared for the method in the ASL/AML. |
* |
* Emit a message if too few or too many arguments have been passed |
* by the caller. |
* |
* Note: Too many arguments will not cause the method to |
* fail. However, the method will fail if there are too few |
* arguments and the method attempts to use one of the missing ones. |
*/ |
aml_param_count = node->object->method.param_count; |
if (user_param_count < aml_param_count) { |
ACPI_WARN_PREDEFINED((AE_INFO, pathname, |
ACPI_WARN_ALWAYS, |
"Insufficient arguments - " |
"Caller passed %u, method requires %u", |
user_param_count, |
aml_param_count)); |
} else if (user_param_count > aml_param_count) { |
ACPI_INFO_PREDEFINED((AE_INFO, pathname, |
ACPI_WARN_ALWAYS, |
"Excess arguments - " |
"Caller passed %u, method requires %u", |
user_param_count, |
aml_param_count)); |
} |
return; |
} |
/* |
* This is a predefined name. Validate the user-supplied parameter |
* count against the ACPI specification. We don't validate against |
* the method itself because what is important here is that the |
* caller is in conformance with the spec. (The arg count for the |
* method was checked against the ACPI spec earlier.) |
* |
* Some methods are allowed to have a "minimum" number of args (_SCP) |
* because their definition in ACPI has changed over time. |
*/ |
required_param_count = |
METHOD_GET_ARG_COUNT(predefined->info.argument_list); |
if (user_param_count < required_param_count) { |
ACPI_WARN_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, |
"Insufficient arguments - " |
"Caller passed %u, ACPI requires %u", |
user_param_count, required_param_count)); |
} else if ((user_param_count > required_param_count) && |
!(predefined->info.argument_list & ARG_COUNT_IS_MINIMUM)) { |
ACPI_INFO_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, |
"Excess arguments - " |
"Caller passed %u, ACPI requires %u", |
user_param_count, required_param_count)); |
} |
} |
/drivers/acpi/acpica/nsconvert.c |
---|
0,0 → 1,446 |
/****************************************************************************** |
* |
* Module Name: nsconvert - Object conversions for objects returned by |
* predefined methods |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#include "acpredef.h" |
#include "amlresrc.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsconvert") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_convert_to_integer |
* |
* PARAMETERS: original_object - Object to be converted |
* return_object - Where the new converted object is returned |
* |
* RETURN: Status. AE_OK if conversion was successful. |
* |
* DESCRIPTION: Attempt to convert a String/Buffer object to an Integer. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_convert_to_integer(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object) |
{ |
union acpi_operand_object *new_object; |
acpi_status status; |
u64 value = 0; |
u32 i; |
switch (original_object->common.type) { |
case ACPI_TYPE_STRING: |
/* String-to-Integer conversion */ |
status = acpi_ut_strtoul64(original_object->string.pointer, |
ACPI_ANY_BASE, &value); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
case ACPI_TYPE_BUFFER: |
/* Buffer-to-Integer conversion. Max buffer size is 64 bits. */ |
if (original_object->buffer.length > 8) { |
return (AE_AML_OPERAND_TYPE); |
} |
/* Extract each buffer byte to create the integer */ |
for (i = 0; i < original_object->buffer.length; i++) { |
value |= |
((u64)original_object->buffer. |
pointer[i] << (i * 8)); |
} |
break; |
default: |
return (AE_AML_OPERAND_TYPE); |
} |
new_object = acpi_ut_create_integer_object(value); |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
*return_object = new_object; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_convert_to_string |
* |
* PARAMETERS: original_object - Object to be converted |
* return_object - Where the new converted object is returned |
* |
* RETURN: Status. AE_OK if conversion was successful. |
* |
* DESCRIPTION: Attempt to convert a Integer/Buffer object to a String. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_convert_to_string(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object) |
{ |
union acpi_operand_object *new_object; |
acpi_size length; |
acpi_status status; |
switch (original_object->common.type) { |
case ACPI_TYPE_INTEGER: |
/* |
* Integer-to-String conversion. Commonly, convert |
* an integer of value 0 to a NULL string. The last element of |
* _BIF and _BIX packages occasionally need this fix. |
*/ |
if (original_object->integer.value == 0) { |
/* Allocate a new NULL string object */ |
new_object = acpi_ut_create_string_object(0); |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
} else { |
status = |
acpi_ex_convert_to_string(original_object, |
&new_object, |
ACPI_IMPLICIT_CONVERT_HEX); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
break; |
case ACPI_TYPE_BUFFER: |
/* |
* Buffer-to-String conversion. Use a to_string |
* conversion, no transform performed on the buffer data. The best |
* example of this is the _BIF method, where the string data from |
* the battery is often (incorrectly) returned as buffer object(s). |
*/ |
length = 0; |
while ((length < original_object->buffer.length) && |
(original_object->buffer.pointer[length])) { |
length++; |
} |
/* Allocate a new string object */ |
new_object = acpi_ut_create_string_object(length); |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
/* |
* Copy the raw buffer data with no transform. String is already NULL |
* terminated at Length+1. |
*/ |
memcpy(new_object->string.pointer, |
original_object->buffer.pointer, length); |
break; |
default: |
return (AE_AML_OPERAND_TYPE); |
} |
*return_object = new_object; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_convert_to_buffer |
* |
* PARAMETERS: original_object - Object to be converted |
* return_object - Where the new converted object is returned |
* |
* RETURN: Status. AE_OK if conversion was successful. |
* |
* DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object) |
{ |
union acpi_operand_object *new_object; |
acpi_status status; |
union acpi_operand_object **elements; |
u32 *dword_buffer; |
u32 count; |
u32 i; |
switch (original_object->common.type) { |
case ACPI_TYPE_INTEGER: |
/* |
* Integer-to-Buffer conversion. |
* Convert the Integer to a packed-byte buffer. _MAT and other |
* objects need this sometimes, if a read has been performed on a |
* Field object that is less than or equal to the global integer |
* size (32 or 64 bits). |
*/ |
status = |
acpi_ex_convert_to_buffer(original_object, &new_object); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
case ACPI_TYPE_STRING: |
/* String-to-Buffer conversion. Simple data copy */ |
new_object = |
acpi_ut_create_buffer_object(original_object->string. |
length); |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
memcpy(new_object->buffer.pointer, |
original_object->string.pointer, |
original_object->string.length); |
break; |
case ACPI_TYPE_PACKAGE: |
/* |
* This case is often seen for predefined names that must return a |
* Buffer object with multiple DWORD integers within. For example, |
* _FDE and _GTM. The Package can be converted to a Buffer. |
*/ |
/* All elements of the Package must be integers */ |
elements = original_object->package.elements; |
count = original_object->package.count; |
for (i = 0; i < count; i++) { |
if ((!*elements) || |
((*elements)->common.type != ACPI_TYPE_INTEGER)) { |
return (AE_AML_OPERAND_TYPE); |
} |
elements++; |
} |
/* Create the new buffer object to replace the Package */ |
new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count)); |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
/* Copy the package elements (integers) to the buffer as DWORDs */ |
elements = original_object->package.elements; |
dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer); |
for (i = 0; i < count; i++) { |
*dword_buffer = (u32)(*elements)->integer.value; |
dword_buffer++; |
elements++; |
} |
break; |
default: |
return (AE_AML_OPERAND_TYPE); |
} |
*return_object = new_object; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_convert_to_unicode |
* |
* PARAMETERS: original_object - ASCII String Object to be converted |
* return_object - Where the new converted object is returned |
* |
* RETURN: Status. AE_OK if conversion was successful. |
* |
* DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_convert_to_unicode(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object) |
{ |
union acpi_operand_object *new_object; |
char *ascii_string; |
u16 *unicode_buffer; |
u32 unicode_length; |
u32 i; |
if (!original_object) { |
return (AE_OK); |
} |
/* If a Buffer was returned, it must be at least two bytes long */ |
if (original_object->common.type == ACPI_TYPE_BUFFER) { |
if (original_object->buffer.length < 2) { |
return (AE_AML_OPERAND_VALUE); |
} |
*return_object = NULL; |
return (AE_OK); |
} |
/* |
* The original object is an ASCII string. Convert this string to |
* a unicode buffer. |
*/ |
ascii_string = original_object->string.pointer; |
unicode_length = (original_object->string.length * 2) + 2; |
/* Create a new buffer object for the Unicode data */ |
new_object = acpi_ut_create_buffer_object(unicode_length); |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
unicode_buffer = ACPI_CAST_PTR(u16, new_object->buffer.pointer); |
/* Convert ASCII to Unicode */ |
for (i = 0; i < original_object->string.length; i++) { |
unicode_buffer[i] = (u16)ascii_string[i]; |
} |
*return_object = new_object; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_convert_to_resource |
* |
* PARAMETERS: original_object - Object to be converted |
* return_object - Where the new converted object is returned |
* |
* RETURN: Status. AE_OK if conversion was successful |
* |
* DESCRIPTION: Attempt to convert a Integer object to a resource_template |
* Buffer. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_convert_to_resource(union acpi_operand_object *original_object, |
union acpi_operand_object **return_object) |
{ |
union acpi_operand_object *new_object; |
u8 *buffer; |
/* |
* We can fix the following cases for an expected resource template: |
* 1. No return value (interpreter slack mode is disabled) |
* 2. A "Return (Zero)" statement |
* 3. A "Return empty buffer" statement |
* |
* We will return a buffer containing a single end_tag |
* resource descriptor. |
*/ |
if (original_object) { |
switch (original_object->common.type) { |
case ACPI_TYPE_INTEGER: |
/* We can only repair an Integer==0 */ |
if (original_object->integer.value) { |
return (AE_AML_OPERAND_TYPE); |
} |
break; |
case ACPI_TYPE_BUFFER: |
if (original_object->buffer.length) { |
/* Additional checks can be added in the future */ |
*return_object = NULL; |
return (AE_OK); |
} |
break; |
case ACPI_TYPE_STRING: |
default: |
return (AE_AML_OPERAND_TYPE); |
} |
} |
/* Create the new buffer object for the resource descriptor */ |
new_object = acpi_ut_create_buffer_object(2); |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
buffer = ACPI_CAST_PTR(u8, new_object->buffer.pointer); |
/* Initialize the Buffer with a single end_tag descriptor */ |
buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE); |
buffer[1] = 0x00; |
*return_object = new_object; |
return (AE_OK); |
} |
/drivers/acpi/acpica/nsdump.c |
---|
0,0 → 1,880 |
/****************************************************************************** |
* |
* Module Name: nsdump - table dumping routines for debug |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include <acpi/acoutput.h> |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsdump") |
/* Local prototypes */ |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
void acpi_ns_dump_root_devices(void); |
static acpi_status |
acpi_ns_dump_one_device(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
#endif |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
static acpi_status |
acpi_ns_dump_one_object_path(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
static acpi_status |
acpi_ns_get_max_depth(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_print_pathname |
* |
* PARAMETERS: num_segments - Number of ACPI name segments |
* pathname - The compressed (internal) path |
* |
* RETURN: None |
* |
* DESCRIPTION: Print an object's full namespace pathname |
* |
******************************************************************************/ |
void acpi_ns_print_pathname(u32 num_segments, char *pathname) |
{ |
u32 i; |
ACPI_FUNCTION_NAME(ns_print_pathname); |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_NAMES, ACPI_NAMESPACE)) { |
return; |
} |
/* Print the entire name */ |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "[")); |
while (num_segments) { |
for (i = 0; i < 4; i++) { |
isprint((int)pathname[i]) ? |
acpi_os_printf("%c", pathname[i]) : |
acpi_os_printf("?"); |
} |
pathname += ACPI_NAME_SIZE; |
num_segments--; |
if (num_segments) { |
acpi_os_printf("."); |
} |
} |
acpi_os_printf("]\n"); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_pathname |
* |
* PARAMETERS: handle - Object |
* msg - Prefix message |
* level - Desired debug level |
* component - Caller's component ID |
* |
* RETURN: None |
* |
* DESCRIPTION: Print an object's full namespace pathname |
* Manages allocation/freeing of a pathname buffer |
* |
******************************************************************************/ |
void |
acpi_ns_dump_pathname(acpi_handle handle, char *msg, u32 level, u32 component) |
{ |
ACPI_FUNCTION_TRACE(ns_dump_pathname); |
/* Do this only if the requested debug level and component are enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(level, component)) { |
return_VOID; |
} |
/* Convert handle to a full pathname and print it (with supplied message) */ |
acpi_ns_print_node_pathname(handle, msg); |
acpi_os_printf("\n"); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_one_object |
* |
* PARAMETERS: obj_handle - Node to be dumped |
* level - Nesting level of the handle |
* context - Passed into walk_namespace |
* return_value - Not used |
* |
* RETURN: Status |
* |
* DESCRIPTION: Dump a single Node |
* This procedure is a user_function called by acpi_ns_walk_namespace. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_dump_one_object(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
struct acpi_walk_info *info = (struct acpi_walk_info *)context; |
struct acpi_namespace_node *this_node; |
union acpi_operand_object *obj_desc = NULL; |
acpi_object_type obj_type; |
acpi_object_type type; |
u32 bytes_to_dump; |
u32 dbg_level; |
u32 i; |
ACPI_FUNCTION_NAME(ns_dump_one_object); |
/* Is output enabled? */ |
if (!(acpi_dbg_level & info->debug_level)) { |
return (AE_OK); |
} |
if (!obj_handle) { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null object handle\n")); |
return (AE_OK); |
} |
this_node = acpi_ns_validate_handle(obj_handle); |
if (!this_node) { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", |
obj_handle)); |
return (AE_OK); |
} |
type = this_node->type; |
/* Check if the owner matches */ |
if ((info->owner_id != ACPI_OWNER_ID_MAX) && |
(info->owner_id != this_node->owner_id)) { |
return (AE_OK); |
} |
if (!(info->display_type & ACPI_DISPLAY_SHORT)) { |
/* Indent the object according to the level */ |
acpi_os_printf("%2d%*s", (u32) level - 1, (int)level * 2, " "); |
/* Check the node type and name */ |
if (type > ACPI_TYPE_LOCAL_MAX) { |
ACPI_WARNING((AE_INFO, |
"Invalid ACPI Object Type 0x%08X", type)); |
} |
acpi_os_printf("%4.4s", acpi_ut_get_node_name(this_node)); |
} |
/* Now we can print out the pertinent information */ |
acpi_os_printf(" %-12s %p %2.2X ", |
acpi_ut_get_type_name(type), this_node, |
this_node->owner_id); |
dbg_level = acpi_dbg_level; |
acpi_dbg_level = 0; |
obj_desc = acpi_ns_get_attached_object(this_node); |
acpi_dbg_level = dbg_level; |
/* Temp nodes are those nodes created by a control method */ |
if (this_node->flags & ANOBJ_TEMPORARY) { |
acpi_os_printf("(T) "); |
} |
switch (info->display_type & ACPI_DISPLAY_MASK) { |
case ACPI_DISPLAY_SUMMARY: |
if (!obj_desc) { |
/* No attached object. Some types should always have an object */ |
switch (type) { |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_PACKAGE: |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_METHOD: |
acpi_os_printf("<No attached object>"); |
break; |
default: |
break; |
} |
acpi_os_printf("\n"); |
return (AE_OK); |
} |
switch (type) { |
case ACPI_TYPE_PROCESSOR: |
acpi_os_printf("ID %02X Len %02X Addr %8.8X%8.8X\n", |
obj_desc->processor.proc_id, |
obj_desc->processor.length, |
ACPI_FORMAT_UINT64(obj_desc->processor. |
address)); |
break; |
case ACPI_TYPE_DEVICE: |
acpi_os_printf("Notify Object: %p\n", obj_desc); |
break; |
case ACPI_TYPE_METHOD: |
acpi_os_printf("Args %X Len %.4X Aml %p\n", |
(u32) obj_desc->method.param_count, |
obj_desc->method.aml_length, |
obj_desc->method.aml_start); |
break; |
case ACPI_TYPE_INTEGER: |
acpi_os_printf("= %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(obj_desc->integer. |
value)); |
break; |
case ACPI_TYPE_PACKAGE: |
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
acpi_os_printf("Elements %.2X\n", |
obj_desc->package.count); |
} else { |
acpi_os_printf("[Length not yet evaluated]\n"); |
} |
break; |
case ACPI_TYPE_BUFFER: |
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
acpi_os_printf("Len %.2X", |
obj_desc->buffer.length); |
/* Dump some of the buffer */ |
if (obj_desc->buffer.length > 0) { |
acpi_os_printf(" ="); |
for (i = 0; |
(i < obj_desc->buffer.length |
&& i < 12); i++) { |
acpi_os_printf(" %.2hX", |
obj_desc->buffer. |
pointer[i]); |
} |
} |
acpi_os_printf("\n"); |
} else { |
acpi_os_printf("[Length not yet evaluated]\n"); |
} |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf("Len %.2X ", obj_desc->string.length); |
acpi_ut_print_string(obj_desc->string.pointer, 32); |
acpi_os_printf("\n"); |
break; |
case ACPI_TYPE_REGION: |
acpi_os_printf("[%s]", |
acpi_ut_get_region_name(obj_desc->region. |
space_id)); |
if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { |
acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n", |
ACPI_FORMAT_UINT64(obj_desc-> |
region. |
address), |
obj_desc->region.length); |
} else { |
acpi_os_printf |
(" [Address/Length not yet evaluated]\n"); |
} |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
acpi_os_printf("[%s]\n", |
acpi_ut_get_reference_name(obj_desc)); |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
if (obj_desc->buffer_field.buffer_obj && |
obj_desc->buffer_field.buffer_obj->buffer.node) { |
acpi_os_printf("Buf [%4.4s]", |
acpi_ut_get_node_name(obj_desc-> |
buffer_field. |
buffer_obj-> |
buffer. |
node)); |
} |
break; |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
acpi_os_printf("Rgn [%4.4s]", |
acpi_ut_get_node_name(obj_desc-> |
common_field. |
region_obj->region. |
node)); |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
acpi_os_printf("Rgn [%4.4s] Bnk [%4.4s]", |
acpi_ut_get_node_name(obj_desc-> |
common_field. |
region_obj->region. |
node), |
acpi_ut_get_node_name(obj_desc-> |
bank_field. |
bank_obj-> |
common_field. |
node)); |
break; |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
acpi_os_printf("Idx [%4.4s] Dat [%4.4s]", |
acpi_ut_get_node_name(obj_desc-> |
index_field. |
index_obj-> |
common_field.node), |
acpi_ut_get_node_name(obj_desc-> |
index_field. |
data_obj-> |
common_field. |
node)); |
break; |
case ACPI_TYPE_LOCAL_ALIAS: |
case ACPI_TYPE_LOCAL_METHOD_ALIAS: |
acpi_os_printf("Target %4.4s (%p)\n", |
acpi_ut_get_node_name(obj_desc), |
obj_desc); |
break; |
default: |
acpi_os_printf("Object %p\n", obj_desc); |
break; |
} |
/* Common field handling */ |
switch (type) { |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
acpi_os_printf(" Off %.3X Len %.2X Acc %.2hd\n", |
(obj_desc->common_field. |
base_byte_offset * 8) |
+ |
obj_desc->common_field. |
start_field_bit_offset, |
obj_desc->common_field.bit_length, |
obj_desc->common_field. |
access_byte_width); |
break; |
default: |
break; |
} |
break; |
case ACPI_DISPLAY_OBJECTS: |
acpi_os_printf("O:%p", obj_desc); |
if (!obj_desc) { |
/* No attached object, we are done */ |
acpi_os_printf("\n"); |
return (AE_OK); |
} |
acpi_os_printf("(R%u)", obj_desc->common.reference_count); |
switch (type) { |
case ACPI_TYPE_METHOD: |
/* Name is a Method and its AML offset/length are set */ |
acpi_os_printf(" M:%p-%X\n", obj_desc->method.aml_start, |
obj_desc->method.aml_length); |
break; |
case ACPI_TYPE_INTEGER: |
acpi_os_printf(" I:%8.8X8.8%X\n", |
ACPI_FORMAT_UINT64(obj_desc->integer. |
value)); |
break; |
case ACPI_TYPE_STRING: |
acpi_os_printf(" S:%p-%X\n", obj_desc->string.pointer, |
obj_desc->string.length); |
break; |
case ACPI_TYPE_BUFFER: |
acpi_os_printf(" B:%p-%X\n", obj_desc->buffer.pointer, |
obj_desc->buffer.length); |
break; |
default: |
acpi_os_printf("\n"); |
break; |
} |
break; |
default: |
acpi_os_printf("\n"); |
break; |
} |
/* If debug turned off, done */ |
if (!(acpi_dbg_level & ACPI_LV_VALUES)) { |
return (AE_OK); |
} |
/* If there is an attached object, display it */ |
dbg_level = acpi_dbg_level; |
acpi_dbg_level = 0; |
obj_desc = acpi_ns_get_attached_object(this_node); |
acpi_dbg_level = dbg_level; |
/* Dump attached objects */ |
while (obj_desc) { |
obj_type = ACPI_TYPE_INVALID; |
acpi_os_printf("Attached Object %p: ", obj_desc); |
/* Decode the type of attached object and dump the contents */ |
switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
case ACPI_DESC_TYPE_NAMED: |
acpi_os_printf("(Ptr to Node)\n"); |
bytes_to_dump = sizeof(struct acpi_namespace_node); |
ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); |
break; |
case ACPI_DESC_TYPE_OPERAND: |
obj_type = obj_desc->common.type; |
if (obj_type > ACPI_TYPE_LOCAL_MAX) { |
acpi_os_printf |
("(Pointer to ACPI Object type %.2X [UNKNOWN])\n", |
obj_type); |
bytes_to_dump = 32; |
} else { |
acpi_os_printf |
("(Pointer to ACPI Object type %.2X [%s])\n", |
obj_type, acpi_ut_get_type_name(obj_type)); |
bytes_to_dump = |
sizeof(union acpi_operand_object); |
} |
ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); |
break; |
default: |
break; |
} |
/* If value is NOT an internal object, we are done */ |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != |
ACPI_DESC_TYPE_OPERAND) { |
goto cleanup; |
} |
/* Valid object, get the pointer to next level, if any */ |
switch (obj_type) { |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_STRING: |
/* |
* NOTE: takes advantage of common fields between string/buffer |
*/ |
bytes_to_dump = obj_desc->string.length; |
obj_desc = (void *)obj_desc->string.pointer; |
acpi_os_printf("(Buffer/String pointer %p length %X)\n", |
obj_desc, bytes_to_dump); |
ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); |
goto cleanup; |
case ACPI_TYPE_BUFFER_FIELD: |
obj_desc = |
(union acpi_operand_object *)obj_desc->buffer_field. |
buffer_obj; |
break; |
case ACPI_TYPE_PACKAGE: |
obj_desc = (void *)obj_desc->package.elements; |
break; |
case ACPI_TYPE_METHOD: |
obj_desc = (void *)obj_desc->method.aml_start; |
break; |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
obj_desc = (void *)obj_desc->field.region_obj; |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
obj_desc = (void *)obj_desc->bank_field.region_obj; |
break; |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
obj_desc = (void *)obj_desc->index_field.index_obj; |
break; |
default: |
goto cleanup; |
} |
obj_type = ACPI_TYPE_INVALID; /* Terminate loop after next pass */ |
} |
cleanup: |
acpi_os_printf("\n"); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_objects |
* |
* PARAMETERS: type - Object type to be dumped |
* display_type - 0 or ACPI_DISPLAY_SUMMARY |
* max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX |
* for an effectively unlimited depth. |
* owner_id - Dump only objects owned by this ID. Use |
* ACPI_UINT32_MAX to match all owners. |
* start_handle - Where in namespace to start/end search |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump typed objects within the loaded namespace. Uses |
* acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object. |
* |
******************************************************************************/ |
void |
acpi_ns_dump_objects(acpi_object_type type, |
u8 display_type, |
u32 max_depth, |
acpi_owner_id owner_id, acpi_handle start_handle) |
{ |
struct acpi_walk_info info; |
acpi_status status; |
ACPI_FUNCTION_ENTRY(); |
/* |
* Just lock the entire namespace for the duration of the dump. |
* We don't want any changes to the namespace during this time, |
* especially the temporary nodes since we are going to display |
* them also. |
*/ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not acquire namespace mutex\n"); |
return; |
} |
info.debug_level = ACPI_LV_TABLES; |
info.owner_id = owner_id; |
info.display_type = display_type; |
(void)acpi_ns_walk_namespace(type, start_handle, max_depth, |
ACPI_NS_WALK_NO_UNLOCK | |
ACPI_NS_WALK_TEMP_NODES, |
acpi_ns_dump_one_object, NULL, |
(void *)&info, NULL); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_one_object_path, acpi_ns_get_max_depth |
* |
* PARAMETERS: obj_handle - Node to be dumped |
* level - Nesting level of the handle |
* context - Passed into walk_namespace |
* return_value - Not used |
* |
* RETURN: Status |
* |
* DESCRIPTION: Dump the full pathname to a namespace object. acp_ns_get_max_depth |
* computes the maximum nesting depth in the namespace tree, in |
* order to simplify formatting in acpi_ns_dump_one_object_path. |
* These procedures are user_functions called by acpi_ns_walk_namespace. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_dump_one_object_path(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
u32 max_level = *((u32 *)context); |
char *pathname; |
struct acpi_namespace_node *node; |
int path_indent; |
if (!obj_handle) { |
return (AE_OK); |
} |
node = acpi_ns_validate_handle(obj_handle); |
if (!node) { |
/* Ignore bad node during namespace walk */ |
return (AE_OK); |
} |
pathname = acpi_ns_get_external_pathname(node); |
path_indent = 1; |
if (level <= max_level) { |
path_indent = max_level - level + 1; |
} |
acpi_os_printf("%2d%*s%-12s%*s", |
level, level, " ", acpi_ut_get_type_name(node->type), |
path_indent, " "); |
acpi_os_printf("%s\n", &pathname[1]); |
ACPI_FREE(pathname); |
return (AE_OK); |
} |
static acpi_status |
acpi_ns_get_max_depth(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
u32 *max_level = (u32 *)context; |
if (level > *max_level) { |
*max_level = level; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_object_paths |
* |
* PARAMETERS: type - Object type to be dumped |
* display_type - 0 or ACPI_DISPLAY_SUMMARY |
* max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX |
* for an effectively unlimited depth. |
* owner_id - Dump only objects owned by this ID. Use |
* ACPI_UINT32_MAX to match all owners. |
* start_handle - Where in namespace to start/end search |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump full object pathnames within the loaded namespace. Uses |
* acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object_path. |
* |
******************************************************************************/ |
void |
acpi_ns_dump_object_paths(acpi_object_type type, |
u8 display_type, |
u32 max_depth, |
acpi_owner_id owner_id, acpi_handle start_handle) |
{ |
acpi_status status; |
u32 max_level = 0; |
ACPI_FUNCTION_ENTRY(); |
/* |
* Just lock the entire namespace for the duration of the dump. |
* We don't want any changes to the namespace during this time, |
* especially the temporary nodes since we are going to display |
* them also. |
*/ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not acquire namespace mutex\n"); |
return; |
} |
/* Get the max depth of the namespace tree, for formatting later */ |
(void)acpi_ns_walk_namespace(type, start_handle, max_depth, |
ACPI_NS_WALK_NO_UNLOCK | |
ACPI_NS_WALK_TEMP_NODES, |
acpi_ns_get_max_depth, NULL, |
(void *)&max_level, NULL); |
/* Now dump the entire namespace */ |
(void)acpi_ns_walk_namespace(type, start_handle, max_depth, |
ACPI_NS_WALK_NO_UNLOCK | |
ACPI_NS_WALK_TEMP_NODES, |
acpi_ns_dump_one_object_path, NULL, |
(void *)&max_level, NULL); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_entry |
* |
* PARAMETERS: handle - Node to be dumped |
* debug_level - Output level |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump a single Node |
* |
******************************************************************************/ |
void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level) |
{ |
struct acpi_walk_info info; |
ACPI_FUNCTION_ENTRY(); |
info.debug_level = debug_level; |
info.owner_id = ACPI_OWNER_ID_MAX; |
info.display_type = ACPI_DISPLAY_SUMMARY; |
(void)acpi_ns_dump_one_object(handle, 1, &info, NULL); |
} |
#ifdef ACPI_ASL_COMPILER |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_tables |
* |
* PARAMETERS: search_base - Root of subtree to be dumped, or |
* NS_ALL to dump the entire namespace |
* max_depth - Maximum depth of dump. Use INT_MAX |
* for an effectively unlimited depth. |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump the name space, or a portion of it. |
* |
******************************************************************************/ |
void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth) |
{ |
acpi_handle search_handle = search_base; |
ACPI_FUNCTION_TRACE(ns_dump_tables); |
if (!acpi_gbl_root_node) { |
/* |
* If the name space has not been initialized, |
* there is nothing to dump. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_TABLES, |
"namespace not initialized!\n")); |
return_VOID; |
} |
if (ACPI_NS_ALL == search_base) { |
/* Entire namespace */ |
search_handle = acpi_gbl_root_node; |
ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "\\\n")); |
} |
acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_OBJECTS, max_depth, |
ACPI_OWNER_ID_MAX, search_handle); |
return_VOID; |
} |
#endif |
#endif |
/drivers/acpi/acpica/nsdumpdv.c |
---|
0,0 → 1,141 |
/****************************************************************************** |
* |
* Module Name: nsdump - table dumping routines for debug |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
/* TBD: This entire module is apparently obsolete and should be removed */ |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsdumpdv") |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
#include "acnamesp.h" |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_one_device |
* |
* PARAMETERS: handle - Node to be dumped |
* level - Nesting level of the handle |
* context - Passed into walk_namespace |
* return_value - Not used |
* |
* RETURN: Status |
* |
* DESCRIPTION: Dump a single Node that represents a device |
* This procedure is a user_function called by acpi_ns_walk_namespace. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_dump_one_device(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
struct acpi_buffer buffer; |
struct acpi_device_info *info; |
acpi_status status; |
u32 i; |
ACPI_FUNCTION_NAME(ns_dump_one_device); |
status = |
acpi_ns_dump_one_object(obj_handle, level, context, return_value); |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_get_object_info(obj_handle, &buffer); |
if (ACPI_SUCCESS(status)) { |
info = buffer.pointer; |
for (i = 0; i < level; i++) { |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES, " ")); |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES, |
" HID: %s, ADR: %8.8X%8.8X, Status: %X\n", |
info->hardware_id.value, |
ACPI_FORMAT_UINT64(info->address), |
info->current_status)); |
ACPI_FREE(info); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_dump_root_devices |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump all objects of type "device" |
* |
******************************************************************************/ |
void acpi_ns_dump_root_devices(void) |
{ |
acpi_handle sys_bus_handle; |
acpi_status status; |
ACPI_FUNCTION_NAME(ns_dump_root_devices); |
/* Only dump the table if tracing is enabled */ |
if (!(ACPI_LV_TABLES & acpi_dbg_level)) { |
return; |
} |
status = acpi_get_handle(NULL, METHOD_NAME__SB_, &sys_bus_handle); |
if (ACPI_FAILURE(status)) { |
return; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_TABLES, |
"Display of all devices in the namespace:\n")); |
status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, sys_bus_handle, |
ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, |
acpi_ns_dump_one_device, NULL, NULL, |
NULL); |
} |
#endif |
#endif |
/drivers/acpi/acpica/nseval.c |
---|
0,0 → 1,495 |
/******************************************************************************* |
* |
* Module Name: nseval - Object evaluation, includes control method execution |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nseval") |
/* Local prototypes */ |
static void |
acpi_ns_exec_module_code(union acpi_operand_object *method_obj, |
struct acpi_evaluate_info *info); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_evaluate |
* |
* PARAMETERS: info - Evaluation info block, contains these fields |
* and more: |
* prefix_node - Prefix or Method/Object Node to execute |
* relative_path - Name of method to execute, If NULL, the |
* Node is the object to execute |
* parameters - List of parameters to pass to the method, |
* terminated by NULL. Params itself may be |
* NULL if no parameters are being passed. |
* parameter_type - Type of Parameter list |
* return_object - Where to put method's return value (if |
* any). If NULL, no value is returned. |
* flags - ACPI_IGNORE_RETURN_VALUE to delete return |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute a control method or return the current value of an |
* ACPI namespace object. |
* |
* MUTEX: Locks interpreter |
* |
******************************************************************************/ |
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_evaluate); |
if (!info) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (!info->node) { |
/* |
* Get the actual namespace node for the target object if we |
* need to. Handles these cases: |
* |
* 1) Null node, valid pathname from root (absolute path) |
* 2) Node and valid pathname (path relative to Node) |
* 3) Node, Null pathname |
*/ |
status = |
acpi_ns_get_node(info->prefix_node, info->relative_pathname, |
ACPI_NS_NO_UPSEARCH, &info->node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* |
* For a method alias, we must grab the actual method node so that |
* proper scoping context will be established before execution. |
*/ |
if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { |
info->node = |
ACPI_CAST_PTR(struct acpi_namespace_node, |
info->node->object); |
} |
/* Complete the info block initialization */ |
info->return_object = NULL; |
info->node_flags = info->node->flags; |
info->obj_desc = acpi_ns_get_attached_object(info->node); |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", |
info->relative_pathname, info->node, |
acpi_ns_get_attached_object(info->node))); |
/* Get info if we have a predefined name (_HID, etc.) */ |
info->predefined = |
acpi_ut_match_predefined_method(info->node->name.ascii); |
/* Get the full pathname to the object, for use in warning messages */ |
info->full_pathname = acpi_ns_get_external_pathname(info->node); |
if (!info->full_pathname) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Count the number of arguments being passed in */ |
info->param_count = 0; |
if (info->parameters) { |
while (info->parameters[info->param_count]) { |
info->param_count++; |
} |
/* Warn on impossible argument count */ |
if (info->param_count > ACPI_METHOD_NUM_ARGS) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
ACPI_WARN_ALWAYS, |
"Excess arguments (%u) - using only %u", |
info->param_count, |
ACPI_METHOD_NUM_ARGS)); |
info->param_count = ACPI_METHOD_NUM_ARGS; |
} |
} |
/* |
* For predefined names: Check that the declared argument count |
* matches the ACPI spec -- otherwise this is a BIOS error. |
*/ |
acpi_ns_check_acpi_compliance(info->full_pathname, info->node, |
info->predefined); |
/* |
* For all names: Check that the incoming argument count for |
* this method/object matches the actual ASL/AML definition. |
*/ |
acpi_ns_check_argument_count(info->full_pathname, info->node, |
info->param_count, info->predefined); |
/* For predefined names: Typecheck all incoming arguments */ |
acpi_ns_check_argument_types(info); |
/* |
* Three major evaluation cases: |
* |
* 1) Object types that cannot be evaluated by definition |
* 2) The object is a control method -- execute it |
* 3) The object is not a method -- just return it's current value |
*/ |
switch (acpi_ns_get_type(info->node)) { |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_EVENT: |
case ACPI_TYPE_MUTEX: |
case ACPI_TYPE_REGION: |
case ACPI_TYPE_THERMAL: |
case ACPI_TYPE_LOCAL_SCOPE: |
/* |
* 1) Disallow evaluation of certain object types. For these, |
* object evaluation is undefined and not supported. |
*/ |
ACPI_ERROR((AE_INFO, |
"%s: Evaluation of object type [%s] is not supported", |
info->full_pathname, |
acpi_ut_get_type_name(info->node->type))); |
status = AE_TYPE; |
goto cleanup; |
case ACPI_TYPE_METHOD: |
/* |
* 2) Object is a control method - execute it |
*/ |
/* Verify that there is a method object associated with this node */ |
if (!info->obj_desc) { |
ACPI_ERROR((AE_INFO, |
"%s: Method has no attached sub-object", |
info->full_pathname)); |
status = AE_NULL_OBJECT; |
goto cleanup; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"**** Execute method [%s] at AML address %p length %X\n", |
info->full_pathname, |
info->obj_desc->method.aml_start + 1, |
info->obj_desc->method.aml_length - 1)); |
/* |
* Any namespace deletion must acquire both the namespace and |
* interpreter locks to ensure that no thread is using the portion of |
* the namespace that is being deleted. |
* |
* Execute the method via the interpreter. The interpreter is locked |
* here before calling into the AML parser |
*/ |
acpi_ex_enter_interpreter(); |
status = acpi_ps_execute_method(info); |
acpi_ex_exit_interpreter(); |
break; |
default: |
/* |
* 3) All other non-method objects -- get the current object value |
*/ |
/* |
* Some objects require additional resolution steps (e.g., the Node |
* may be a field that must be read, etc.) -- we can't just grab |
* the object out of the node. |
* |
* Use resolve_node_to_value() to get the associated value. |
* |
* NOTE: we can get away with passing in NULL for a walk state because |
* the Node is guaranteed to not be a reference to either a method |
* local or a method argument (because this interface is never called |
* from a running method.) |
* |
* Even though we do not directly invoke the interpreter for object |
* resolution, we must lock it because we could access an op_region. |
* The op_region access code assumes that the interpreter is locked. |
*/ |
acpi_ex_enter_interpreter(); |
/* TBD: resolve_node_to_value has a strange interface, fix */ |
info->return_object = |
ACPI_CAST_PTR(union acpi_operand_object, info->node); |
status = |
acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR |
(struct acpi_namespace_node, |
&info->return_object), NULL); |
acpi_ex_exit_interpreter(); |
if (ACPI_FAILURE(status)) { |
info->return_object = NULL; |
goto cleanup; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Returned object %p [%s]\n", |
info->return_object, |
acpi_ut_get_object_type_name(info-> |
return_object))); |
status = AE_CTRL_RETURN_VALUE; /* Always has a "return value" */ |
break; |
} |
/* |
* For predefined names, check the return value against the ACPI |
* specification. Some incorrect return value types are repaired. |
*/ |
(void)acpi_ns_check_return_value(info->node, info, info->param_count, |
status, &info->return_object); |
/* Check if there is a return value that must be dealt with */ |
if (status == AE_CTRL_RETURN_VALUE) { |
/* If caller does not want the return value, delete it */ |
if (info->flags & ACPI_IGNORE_RETURN_VALUE) { |
acpi_ut_remove_reference(info->return_object); |
info->return_object = NULL; |
} |
/* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ |
status = AE_OK; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"*** Completed evaluation of object %s ***\n", |
info->relative_pathname)); |
cleanup: |
/* |
* Namespace was unlocked by the handling acpi_ns* function, so we |
* just free the pathname and return |
*/ |
ACPI_FREE(info->full_pathname); |
info->full_pathname = NULL; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_exec_module_code_list |
* |
* PARAMETERS: None |
* |
* RETURN: None. Exceptions during method execution are ignored, since |
* we cannot abort a table load. |
* |
* DESCRIPTION: Execute all elements of the global module-level code list. |
* Each element is executed as a single control method. |
* |
******************************************************************************/ |
void acpi_ns_exec_module_code_list(void) |
{ |
union acpi_operand_object *prev; |
union acpi_operand_object *next; |
struct acpi_evaluate_info *info; |
u32 method_count = 0; |
ACPI_FUNCTION_TRACE(ns_exec_module_code_list); |
/* Exit now if the list is empty */ |
next = acpi_gbl_module_code_list; |
if (!next) { |
return_VOID; |
} |
/* Allocate the evaluation information block */ |
info = ACPI_ALLOCATE(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
return_VOID; |
} |
/* Walk the list, executing each "method" */ |
while (next) { |
prev = next; |
next = next->method.mutex; |
/* Clear the link field and execute the method */ |
prev->method.mutex = NULL; |
acpi_ns_exec_module_code(prev, info); |
method_count++; |
/* Delete the (temporary) method object */ |
acpi_ut_remove_reference(prev); |
} |
ACPI_INFO((AE_INFO, |
"Executed %u blocks of module-level executable AML code", |
method_count)); |
ACPI_FREE(info); |
acpi_gbl_module_code_list = NULL; |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_exec_module_code |
* |
* PARAMETERS: method_obj - Object container for the module-level code |
* info - Info block for method evaluation |
* |
* RETURN: None. Exceptions during method execution are ignored, since |
* we cannot abort a table load. |
* |
* DESCRIPTION: Execute a control method containing a block of module-level |
* executable AML code. The control method is temporarily |
* installed to the root node, then evaluated. |
* |
******************************************************************************/ |
static void |
acpi_ns_exec_module_code(union acpi_operand_object *method_obj, |
struct acpi_evaluate_info *info) |
{ |
union acpi_operand_object *parent_obj; |
struct acpi_namespace_node *parent_node; |
acpi_object_type type; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_exec_module_code); |
/* |
* Get the parent node. We cheat by using the next_object field |
* of the method object descriptor. |
*/ |
parent_node = ACPI_CAST_PTR(struct acpi_namespace_node, |
method_obj->method.next_object); |
type = acpi_ns_get_type(parent_node); |
/* |
* Get the region handler and save it in the method object. We may need |
* this if an operation region declaration causes a _REG method to be run. |
* |
* We can't do this in acpi_ps_link_module_code because |
* acpi_gbl_root_node->Object is NULL at PASS1. |
*/ |
if ((type == ACPI_TYPE_DEVICE) && parent_node->object) { |
method_obj->method.dispatch.handler = |
parent_node->object->device.handler; |
} |
/* Must clear next_object (acpi_ns_attach_object needs the field) */ |
method_obj->method.next_object = NULL; |
/* Initialize the evaluation information block */ |
memset(info, 0, sizeof(struct acpi_evaluate_info)); |
info->prefix_node = parent_node; |
/* |
* Get the currently attached parent object. Add a reference, because the |
* ref count will be decreased when the method object is installed to |
* the parent node. |
*/ |
parent_obj = acpi_ns_get_attached_object(parent_node); |
if (parent_obj) { |
acpi_ut_add_reference(parent_obj); |
} |
/* Install the method (module-level code) in the parent node */ |
status = acpi_ns_attach_object(parent_node, method_obj, |
ACPI_TYPE_METHOD); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* Execute the parent node as a control method */ |
status = acpi_ns_evaluate(info); |
ACPI_DEBUG_PRINT((ACPI_DB_INIT_NAMES, |
"Executed module-level code at %p\n", |
method_obj->method.aml_start)); |
/* Delete a possible implicit return value (in slack mode) */ |
if (info->return_object) { |
acpi_ut_remove_reference(info->return_object); |
} |
/* Detach the temporary method object */ |
acpi_ns_detach_object(parent_node); |
/* Restore the original parent object */ |
if (parent_obj) { |
status = acpi_ns_attach_object(parent_node, parent_obj, type); |
} else { |
parent_node->type = (u8)type; |
} |
exit: |
if (parent_obj) { |
acpi_ut_remove_reference(parent_obj); |
} |
return_VOID; |
} |
/drivers/acpi/acpica/nsinit.c |
---|
0,0 → 1,607 |
/****************************************************************************** |
* |
* Module Name: nsinit - namespace initialization |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsinit") |
/* Local prototypes */ |
static acpi_status |
acpi_ns_init_one_object(acpi_handle obj_handle, |
u32 level, void *context, void **return_value); |
static acpi_status |
acpi_ns_init_one_device(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value); |
static acpi_status |
acpi_ns_find_ini_methods(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_initialize_objects |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walk the entire namespace and perform any necessary |
* initialization on the objects found therein |
* |
******************************************************************************/ |
acpi_status acpi_ns_initialize_objects(void) |
{ |
acpi_status status; |
struct acpi_init_walk_info info; |
ACPI_FUNCTION_TRACE(ns_initialize_objects); |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"**** Starting initialization of namespace objects ****\n")); |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
"Completing Region/Field/Buffer/Package initialization:\n")); |
/* Set all init info to zero */ |
memset(&info, 0, sizeof(struct acpi_init_walk_info)); |
/* Walk entire namespace from the supplied root */ |
status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, acpi_ns_init_one_object, |
NULL, &info, NULL); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
" Initialized %u/%u Regions %u/%u Fields %u/%u " |
"Buffers %u/%u Packages (%u nodes)\n", |
info.op_region_init, info.op_region_count, |
info.field_init, info.field_count, |
info.buffer_init, info.buffer_count, |
info.package_init, info.package_count, |
info.object_count)); |
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
"%u Control Methods found\n%u Op Regions found\n", |
info.method_count, info.op_region_count)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_initialize_devices |
* |
* PARAMETERS: None |
* |
* RETURN: acpi_status |
* |
* DESCRIPTION: Walk the entire namespace and initialize all ACPI devices. |
* This means running _INI on all present devices. |
* |
* Note: We install PCI config space handler on region access, |
* not here. |
* |
******************************************************************************/ |
acpi_status acpi_ns_initialize_devices(void) |
{ |
acpi_status status; |
struct acpi_device_walk_info info; |
ACPI_FUNCTION_TRACE(ns_initialize_devices); |
/* Init counters */ |
info.device_count = 0; |
info.num_STA = 0; |
info.num_INI = 0; |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
"Initializing Device/Processor/Thermal objects " |
"and executing _INI/_STA methods:\n")); |
/* Tree analysis: find all subtrees that contain _INI methods */ |
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, FALSE, |
acpi_ns_find_ini_methods, NULL, &info, |
NULL); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
/* Allocate the evaluation information block */ |
info.evaluate_info = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info.evaluate_info) { |
status = AE_NO_MEMORY; |
goto error_exit; |
} |
/* |
* Execute the "global" _INI method that may appear at the root. This |
* support is provided for Windows compatibility (Vista+) and is not |
* part of the ACPI specification. |
*/ |
info.evaluate_info->prefix_node = acpi_gbl_root_node; |
info.evaluate_info->relative_pathname = METHOD_NAME__INI; |
info.evaluate_info->parameters = NULL; |
info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE; |
status = acpi_ns_evaluate(info.evaluate_info); |
if (ACPI_SUCCESS(status)) { |
info.num_INI++; |
} |
/* Walk namespace to execute all _INIs on present devices */ |
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, FALSE, |
acpi_ns_init_one_device, NULL, &info, |
NULL); |
/* |
* Any _OSI requests should be completed by now. If the BIOS has |
* requested any Windows OSI strings, we will always truncate |
* I/O addresses to 16 bits -- for Windows compatibility. |
*/ |
if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) { |
acpi_gbl_truncate_io_addresses = TRUE; |
} |
ACPI_FREE(info.evaluate_info); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
" Executed %u _INI methods requiring %u _STA executions " |
"(examined %u objects)\n", |
info.num_INI, info.num_STA, info.device_count)); |
return_ACPI_STATUS(status); |
error_exit: |
ACPI_EXCEPTION((AE_INFO, status, "During device initialization")); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_init_one_object |
* |
* PARAMETERS: obj_handle - Node |
* level - Current nesting level |
* context - Points to a init info struct |
* return_value - Not used |
* |
* RETURN: Status |
* |
* DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object |
* within the namespace. |
* |
* Currently, the only objects that require initialization are: |
* 1) Methods |
* 2) Op Regions |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_init_one_object(acpi_handle obj_handle, |
u32 level, void *context, void **return_value) |
{ |
acpi_object_type type; |
acpi_status status = AE_OK; |
struct acpi_init_walk_info *info = |
(struct acpi_init_walk_info *)context; |
struct acpi_namespace_node *node = |
(struct acpi_namespace_node *)obj_handle; |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_NAME(ns_init_one_object); |
info->object_count++; |
/* And even then, we are only interested in a few object types */ |
type = acpi_ns_get_type(obj_handle); |
obj_desc = acpi_ns_get_attached_object(node); |
if (!obj_desc) { |
return (AE_OK); |
} |
/* Increment counters for object types we are looking for */ |
switch (type) { |
case ACPI_TYPE_REGION: |
info->op_region_count++; |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
info->field_count++; |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
info->field_count++; |
break; |
case ACPI_TYPE_BUFFER: |
info->buffer_count++; |
break; |
case ACPI_TYPE_PACKAGE: |
info->package_count++; |
break; |
default: |
/* No init required, just exit now */ |
return (AE_OK); |
} |
/* If the object is already initialized, nothing else to do */ |
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
return (AE_OK); |
} |
/* Must lock the interpreter before executing AML code */ |
acpi_ex_enter_interpreter(); |
/* |
* Each of these types can contain executable AML code within the |
* declaration. |
*/ |
switch (type) { |
case ACPI_TYPE_REGION: |
info->op_region_init++; |
status = acpi_ds_get_region_arguments(obj_desc); |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
info->field_init++; |
status = acpi_ds_get_buffer_field_arguments(obj_desc); |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
info->field_init++; |
status = acpi_ds_get_bank_field_arguments(obj_desc); |
break; |
case ACPI_TYPE_BUFFER: |
info->buffer_init++; |
status = acpi_ds_get_buffer_arguments(obj_desc); |
break; |
case ACPI_TYPE_PACKAGE: |
info->package_init++; |
status = acpi_ds_get_package_arguments(obj_desc); |
break; |
default: |
/* No other types can get here */ |
break; |
} |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not execute arguments for [%4.4s] (%s)", |
acpi_ut_get_node_name(node), |
acpi_ut_get_type_name(type))); |
} |
/* |
* We ignore errors from above, and always return OK, since we don't want |
* to abort the walk on any single error. |
*/ |
acpi_ex_exit_interpreter(); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_find_ini_methods |
* |
* PARAMETERS: acpi_walk_callback |
* |
* RETURN: acpi_status |
* |
* DESCRIPTION: Called during namespace walk. Finds objects named _INI under |
* device/processor/thermal objects, and marks the entire subtree |
* with a SUBTREE_HAS_INI flag. This flag is used during the |
* subsequent device initialization walk to avoid entire subtrees |
* that do not contain an _INI. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_find_ini_methods(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value) |
{ |
struct acpi_device_walk_info *info = |
ACPI_CAST_PTR(struct acpi_device_walk_info, context); |
struct acpi_namespace_node *node; |
struct acpi_namespace_node *parent_node; |
/* Keep count of device/processor/thermal objects */ |
node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
if ((node->type == ACPI_TYPE_DEVICE) || |
(node->type == ACPI_TYPE_PROCESSOR) || |
(node->type == ACPI_TYPE_THERMAL)) { |
info->device_count++; |
return (AE_OK); |
} |
/* We are only looking for methods named _INI */ |
if (!ACPI_COMPARE_NAME(node->name.ascii, METHOD_NAME__INI)) { |
return (AE_OK); |
} |
/* |
* The only _INI methods that we care about are those that are |
* present under Device, Processor, and Thermal objects. |
*/ |
parent_node = node->parent; |
switch (parent_node->type) { |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_THERMAL: |
/* Mark parent and bubble up the INI present flag to the root */ |
while (parent_node) { |
parent_node->flags |= ANOBJ_SUBTREE_HAS_INI; |
parent_node = parent_node->parent; |
} |
break; |
default: |
break; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_init_one_device |
* |
* PARAMETERS: acpi_walk_callback |
* |
* RETURN: acpi_status |
* |
* DESCRIPTION: This is called once per device soon after ACPI is enabled |
* to initialize each device. It determines if the device is |
* present, and if so, calls _INI. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_init_one_device(acpi_handle obj_handle, |
u32 nesting_level, void *context, void **return_value) |
{ |
struct acpi_device_walk_info *walk_info = |
ACPI_CAST_PTR(struct acpi_device_walk_info, context); |
struct acpi_evaluate_info *info = walk_info->evaluate_info; |
u32 flags; |
acpi_status status; |
struct acpi_namespace_node *device_node; |
ACPI_FUNCTION_TRACE(ns_init_one_device); |
/* We are interested in Devices, Processors and thermal_zones only */ |
device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
if ((device_node->type != ACPI_TYPE_DEVICE) && |
(device_node->type != ACPI_TYPE_PROCESSOR) && |
(device_node->type != ACPI_TYPE_THERMAL)) { |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Because of an earlier namespace analysis, all subtrees that contain an |
* _INI method are tagged. |
* |
* If this device subtree does not contain any _INI methods, we |
* can exit now and stop traversing this entire subtree. |
*/ |
if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) { |
return_ACPI_STATUS(AE_CTRL_DEPTH); |
} |
/* |
* Run _STA to determine if this device is present and functioning. We |
* must know this information for two important reasons (from ACPI spec): |
* |
* 1) We can only run _INI if the device is present. |
* 2) We must abort the device tree walk on this subtree if the device is |
* not present and is not functional (we will not examine the children) |
* |
* The _STA method is not required to be present under the device, we |
* assume the device is present if _STA does not exist. |
*/ |
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
(ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA)); |
status = acpi_ut_execute_STA(device_node, &flags); |
if (ACPI_FAILURE(status)) { |
/* Ignore error and move on to next device */ |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Flags == -1 means that _STA was not found. In this case, we assume that |
* the device is both present and functional. |
* |
* From the ACPI spec, description of _STA: |
* |
* "If a device object (including the processor object) does not have an |
* _STA object, then OSPM assumes that all of the above bits are set (in |
* other words, the device is present, ..., and functioning)" |
*/ |
if (flags != ACPI_UINT32_MAX) { |
walk_info->num_STA++; |
} |
/* |
* Examine the PRESENT and FUNCTIONING status bits |
* |
* Note: ACPI spec does not seem to specify behavior for the present but |
* not functioning case, so we assume functioning if present. |
*/ |
if (!(flags & ACPI_STA_DEVICE_PRESENT)) { |
/* Device is not present, we must examine the Functioning bit */ |
if (flags & ACPI_STA_DEVICE_FUNCTIONING) { |
/* |
* Device is not present but is "functioning". In this case, |
* we will not run _INI, but we continue to examine the children |
* of this device. |
* |
* From the ACPI spec, description of _STA: (note - no mention |
* of whether to run _INI or not on the device in question) |
* |
* "_STA may return bit 0 clear (not present) with bit 3 set |
* (device is functional). This case is used to indicate a valid |
* device for which no device driver should be loaded (for example, |
* a bridge device.) Children of this device may be present and |
* valid. OSPM should continue enumeration below a device whose |
* _STA returns this bit combination" |
*/ |
return_ACPI_STATUS(AE_OK); |
} else { |
/* |
* Device is not present and is not functioning. We must abort the |
* walk of this subtree immediately -- don't look at the children |
* of such a device. |
* |
* From the ACPI spec, description of _INI: |
* |
* "If the _STA method indicates that the device is not present, |
* OSPM will not run the _INI and will not examine the children |
* of the device for _INI methods" |
*/ |
return_ACPI_STATUS(AE_CTRL_DEPTH); |
} |
} |
/* |
* The device is present or is assumed present if no _STA exists. |
* Run the _INI if it exists (not required to exist) |
* |
* Note: We know there is an _INI within this subtree, but it may not be |
* under this particular device, it may be lower in the branch. |
*/ |
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
(ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI)); |
memset(info, 0, sizeof(struct acpi_evaluate_info)); |
info->prefix_node = device_node; |
info->relative_pathname = METHOD_NAME__INI; |
info->parameters = NULL; |
info->flags = ACPI_IGNORE_RETURN_VALUE; |
status = acpi_ns_evaluate(info); |
if (ACPI_SUCCESS(status)) { |
walk_info->num_INI++; |
} |
#ifdef ACPI_DEBUG_OUTPUT |
else if (status != AE_NOT_FOUND) { |
/* Ignore error and move on to next device */ |
char *scope_name = acpi_ns_get_external_pathname(info->node); |
ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", |
scope_name)); |
ACPI_FREE(scope_name); |
} |
#endif |
/* Ignore errors from above */ |
status = AE_OK; |
/* |
* The _INI method has been run if present; call the Global Initialization |
* Handler for this device. |
*/ |
if (acpi_gbl_init_handler) { |
status = |
acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI); |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/nsload.c |
---|
0,0 → 1,328 |
/****************************************************************************** |
* |
* Module Name: nsload - namespace loading/expanding/contracting procedures |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acdispat.h" |
#include "actables.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsload") |
/* Local prototypes */ |
#ifdef ACPI_FUTURE_IMPLEMENTATION |
acpi_status acpi_ns_unload_namespace(acpi_handle handle); |
static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle); |
#endif |
#ifndef ACPI_NO_METHOD_EXECUTION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_load_table |
* |
* PARAMETERS: table_index - Index for table to be loaded |
* node - Owning NS node |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load one ACPI table into the namespace |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_load_table); |
/* |
* Parse the table and load the namespace with all named |
* objects found within. Control methods are NOT parsed |
* at this time. In fact, the control methods cannot be |
* parsed until the entire namespace is loaded, because |
* if a control method makes a forward reference (call) |
* to another control method, we can't continue parsing |
* because we don't know how many arguments to parse next! |
*/ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* If table already loaded into namespace, just return */ |
if (acpi_tb_is_table_loaded(table_index)) { |
status = AE_ALREADY_EXISTS; |
goto unlock; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"**** Loading table into namespace ****\n")); |
status = acpi_tb_allocate_owner_id(table_index); |
if (ACPI_FAILURE(status)) { |
goto unlock; |
} |
status = acpi_ns_parse_table(table_index, node); |
if (ACPI_SUCCESS(status)) { |
acpi_tb_set_table_loaded_flag(table_index, TRUE); |
} else { |
/* |
* On error, delete any namespace objects created by this table. |
* We cannot initialize these objects, so delete them. There are |
* a couple of expecially bad cases: |
* AE_ALREADY_EXISTS - namespace collision. |
* AE_NOT_FOUND - the target of a Scope operator does not |
* exist. This target of Scope must already exist in the |
* namespace, as per the ACPI specification. |
*/ |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
acpi_ns_delete_namespace_by_owner(acpi_gbl_root_table_list. |
tables[table_index].owner_id); |
acpi_tb_release_owner_id(table_index); |
return_ACPI_STATUS(status); |
} |
unlock: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Now we can parse the control methods. We always parse |
* them here for a sanity check, and if configured for |
* just-in-time parsing, we delete the control method |
* parse trees. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"**** Begin Table Object Initialization\n")); |
status = acpi_ds_initialize_objects(table_index, node); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"**** Completed Table Object Initialization\n")); |
return_ACPI_STATUS(status); |
} |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
/******************************************************************************* |
* |
* FUNCTION: acpi_load_namespace |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load the name space from what ever is pointed to by DSDT. |
* (DSDT points to either the BIOS or a buffer.) |
* |
******************************************************************************/ |
acpi_status acpi_ns_load_namespace(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_load_name_space); |
/* There must be at least a DSDT installed */ |
if (acpi_gbl_DSDT == NULL) { |
ACPI_ERROR((AE_INFO, "DSDT is not in memory")); |
return_ACPI_STATUS(AE_NO_ACPI_TABLES); |
} |
/* |
* Load the namespace. The DSDT is required, |
* but the SSDT and PSDT tables are optional. |
*/ |
status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Ignore exceptions from these */ |
(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT); |
(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT); |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
"ACPI Namespace successfully loaded at root %p\n", |
acpi_gbl_root_node)); |
return_ACPI_STATUS(status); |
} |
#endif |
#ifdef ACPI_FUTURE_IMPLEMENTATION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_delete_subtree |
* |
* PARAMETERS: start_handle - Handle in namespace where search begins |
* |
* RETURNS Status |
* |
* DESCRIPTION: Walks the namespace starting at the given handle and deletes |
* all objects, entries, and scopes in the entire subtree. |
* |
* Namespace/Interpreter should be locked or the subsystem should |
* be in shutdown before this routine is called. |
* |
******************************************************************************/ |
static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) |
{ |
acpi_status status; |
acpi_handle child_handle; |
acpi_handle parent_handle; |
acpi_handle next_child_handle; |
acpi_handle dummy; |
u32 level; |
ACPI_FUNCTION_TRACE(ns_delete_subtree); |
parent_handle = start_handle; |
child_handle = NULL; |
level = 1; |
/* |
* Traverse the tree of objects until we bubble back up |
* to where we started. |
*/ |
while (level > 0) { |
/* Attempt to get the next object in this scope */ |
status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, |
child_handle, &next_child_handle); |
child_handle = next_child_handle; |
/* Did we get a new object? */ |
if (ACPI_SUCCESS(status)) { |
/* Check if this object has any children */ |
if (ACPI_SUCCESS |
(acpi_get_next_object |
(ACPI_TYPE_ANY, child_handle, NULL, &dummy))) { |
/* |
* There is at least one child of this object, |
* visit the object |
*/ |
level++; |
parent_handle = child_handle; |
child_handle = NULL; |
} |
} else { |
/* |
* No more children in this object, go back up to |
* the object's parent |
*/ |
level--; |
/* Delete all children now */ |
acpi_ns_delete_children(child_handle); |
child_handle = parent_handle; |
status = acpi_get_parent(parent_handle, &parent_handle); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
} |
/* Now delete the starting object, and we are done */ |
acpi_ns_remove_node(child_handle); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_unload_name_space |
* |
* PARAMETERS: handle - Root of namespace subtree to be deleted |
* |
* RETURN: Status |
* |
* DESCRIPTION: Shrinks the namespace, typically in response to an undocking |
* event. Deletes an entire subtree starting from (and |
* including) the given handle. |
* |
******************************************************************************/ |
acpi_status acpi_ns_unload_namespace(acpi_handle handle) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_unload_name_space); |
/* Parameter validation */ |
if (!acpi_gbl_root_node) { |
return_ACPI_STATUS(AE_NO_NAMESPACE); |
} |
if (!handle) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* This function does the real work */ |
status = acpi_ns_delete_subtree(handle); |
return_ACPI_STATUS(status); |
} |
#endif |
#endif |
/drivers/acpi/acpica/nsnames.c |
---|
0,0 → 1,303 |
/******************************************************************************* |
* |
* Module Name: nsnames - Name manipulation and search |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsnames") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_external_pathname |
* |
* PARAMETERS: node - Namespace node whose pathname is needed |
* |
* RETURN: Pointer to storage containing the fully qualified name of |
* the node, In external format (name segments separated by path |
* separators.) |
* |
* DESCRIPTION: Used to obtain the full pathname to a namespace node, usually |
* for error and debug statements. |
* |
******************************************************************************/ |
char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) |
{ |
char *name_buffer; |
ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node); |
name_buffer = acpi_ns_get_normalized_pathname(node, FALSE); |
return_PTR(name_buffer); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_pathname_length |
* |
* PARAMETERS: node - Namespace node |
* |
* RETURN: Length of path, including prefix |
* |
* DESCRIPTION: Get the length of the pathname string for this node |
* |
******************************************************************************/ |
acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) |
{ |
acpi_size size; |
ACPI_FUNCTION_ENTRY(); |
size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE); |
return (size); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_handle_to_pathname |
* |
* PARAMETERS: target_handle - Handle of named object whose name is |
* to be found |
* buffer - Where the pathname is returned |
* no_trailing - Remove trailing '_' for each name |
* segment |
* |
* RETURN: Status, Buffer is filled with pathname if status is AE_OK |
* |
* DESCRIPTION: Build and return a full namespace pathname |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_handle_to_pathname(acpi_handle target_handle, |
struct acpi_buffer * buffer, u8 no_trailing) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
acpi_size required_size; |
ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); |
node = acpi_ns_validate_handle(target_handle); |
if (!node) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Determine size required for the caller buffer */ |
required_size = |
acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); |
if (!required_size) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Validate/Allocate/Clear caller buffer */ |
status = acpi_ut_initialize_buffer(buffer, required_size); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Build the path in the caller buffer */ |
(void)acpi_ns_build_normalized_path(node, buffer->pointer, |
required_size, no_trailing); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n", |
(char *)buffer->pointer, (u32) required_size)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_build_normalized_path |
* |
* PARAMETERS: node - Namespace node |
* full_path - Where the path name is returned |
* path_size - Size of returned path name buffer |
* no_trailing - Remove trailing '_' from each name segment |
* |
* RETURN: Return 1 if the AML path is empty, otherwise returning (length |
* of pathname + 1) which means the 'FullPath' contains a trailing |
* null. |
* |
* DESCRIPTION: Build and return a full namespace pathname. |
* Note that if the size of 'FullPath' isn't large enough to |
* contain the namespace node's path name, the actual required |
* buffer length is returned, and it should be greater than |
* 'PathSize'. So callers are able to check the returning value |
* to determine the buffer size of 'FullPath'. |
* |
******************************************************************************/ |
u32 |
acpi_ns_build_normalized_path(struct acpi_namespace_node *node, |
char *full_path, u32 path_size, u8 no_trailing) |
{ |
u32 length = 0, i; |
char name[ACPI_NAME_SIZE]; |
u8 do_no_trailing; |
char c, *left, *right; |
struct acpi_namespace_node *next_node; |
ACPI_FUNCTION_TRACE_PTR(ns_build_normalized_path, node); |
#define ACPI_PATH_PUT8(path, size, byte, length) \ |
do { \ |
if ((length) < (size)) \ |
{ \ |
(path)[(length)] = (byte); \ |
} \ |
(length)++; \ |
} while (0) |
/* |
* Make sure the path_size is correct, so that we don't need to |
* validate both full_path and path_size. |
*/ |
if (!full_path) { |
path_size = 0; |
} |
if (!node) { |
goto build_trailing_null; |
} |
next_node = node; |
while (next_node && next_node != acpi_gbl_root_node) { |
if (next_node != node) { |
ACPI_PATH_PUT8(full_path, path_size, |
AML_DUAL_NAME_PREFIX, length); |
} |
ACPI_MOVE_32_TO_32(name, &next_node->name); |
do_no_trailing = no_trailing; |
for (i = 0; i < 4; i++) { |
c = name[4 - i - 1]; |
if (do_no_trailing && c != '_') { |
do_no_trailing = FALSE; |
} |
if (!do_no_trailing) { |
ACPI_PATH_PUT8(full_path, path_size, c, length); |
} |
} |
next_node = next_node->parent; |
} |
ACPI_PATH_PUT8(full_path, path_size, AML_ROOT_PREFIX, length); |
/* Reverse the path string */ |
if (length <= path_size) { |
left = full_path; |
right = full_path + length - 1; |
while (left < right) { |
c = *left; |
*left++ = *right; |
*right-- = c; |
} |
} |
/* Append the trailing null */ |
build_trailing_null: |
ACPI_PATH_PUT8(full_path, path_size, '\0', length); |
#undef ACPI_PATH_PUT8 |
return_UINT32(length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_normalized_pathname |
* |
* PARAMETERS: node - Namespace node whose pathname is needed |
* no_trailing - Remove trailing '_' from each name segment |
* |
* RETURN: Pointer to storage containing the fully qualified name of |
* the node, In external format (name segments separated by path |
* separators.) |
* |
* DESCRIPTION: Used to obtain the full pathname to a namespace node, usually |
* for error and debug statements. All trailing '_' will be |
* removed from the full pathname if 'NoTrailing' is specified.. |
* |
******************************************************************************/ |
char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, |
u8 no_trailing) |
{ |
char *name_buffer; |
acpi_size size; |
ACPI_FUNCTION_TRACE_PTR(ns_get_normalized_pathname, node); |
/* Calculate required buffer size based on depth below root */ |
size = acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); |
if (!size) { |
return_PTR(NULL); |
} |
/* Allocate a buffer to be returned to caller */ |
name_buffer = ACPI_ALLOCATE_ZEROED(size); |
if (!name_buffer) { |
ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); |
return_PTR(NULL); |
} |
/* Build the path in the allocated buffer */ |
(void)acpi_ns_build_normalized_path(node, name_buffer, size, |
no_trailing); |
return_PTR(name_buffer); |
} |
/drivers/acpi/acpica/nsobject.c |
---|
0,0 → 1,464 |
/******************************************************************************* |
* |
* Module Name: nsobject - Utilities for objects attached to namespace |
* table entries |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsobject") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_attach_object |
* |
* PARAMETERS: node - Parent Node |
* object - Object to be attached |
* type - Type of object, or ACPI_TYPE_ANY if not |
* known |
* |
* RETURN: Status |
* |
* DESCRIPTION: Record the given object as the value associated with the |
* name whose acpi_handle is passed. If Object is NULL |
* and Type is ACPI_TYPE_ANY, set the name as having no value. |
* Note: Future may require that the Node->Flags field be passed |
* as a parameter. |
* |
* MUTEX: Assumes namespace is locked |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_attach_object(struct acpi_namespace_node *node, |
union acpi_operand_object *object, acpi_object_type type) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *last_obj_desc; |
acpi_object_type object_type = ACPI_TYPE_ANY; |
ACPI_FUNCTION_TRACE(ns_attach_object); |
/* |
* Parameter validation |
*/ |
if (!node) { |
/* Invalid handle */ |
ACPI_ERROR((AE_INFO, "Null NamedObj handle")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (!object && (ACPI_TYPE_ANY != type)) { |
/* Null object */ |
ACPI_ERROR((AE_INFO, |
"Null object, but type not ACPI_TYPE_ANY")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { |
/* Not a name handle */ |
ACPI_ERROR((AE_INFO, "Invalid handle %p [%s]", |
node, acpi_ut_get_descriptor_name(node))); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Check if this object is already attached */ |
if (node->object == object) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Obj %p already installed in NameObj %p\n", |
object, node)); |
return_ACPI_STATUS(AE_OK); |
} |
/* If null object, we will just install it */ |
if (!object) { |
obj_desc = NULL; |
object_type = ACPI_TYPE_ANY; |
} |
/* |
* If the source object is a namespace Node with an attached object, |
* we will use that (attached) object |
*/ |
else if ((ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) && |
((struct acpi_namespace_node *)object)->object) { |
/* |
* Value passed is a name handle and that name has a |
* non-null value. Use that name's value and type. |
*/ |
obj_desc = ((struct acpi_namespace_node *)object)->object; |
object_type = ((struct acpi_namespace_node *)object)->type; |
} |
/* |
* Otherwise, we will use the parameter object, but we must type |
* it first |
*/ |
else { |
obj_desc = (union acpi_operand_object *)object; |
/* Use the given type */ |
object_type = type; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Installing %p into Node %p [%4.4s]\n", |
obj_desc, node, acpi_ut_get_node_name(node))); |
/* Detach an existing attached object if present */ |
if (node->object) { |
acpi_ns_detach_object(node); |
} |
if (obj_desc) { |
/* |
* Must increment the new value's reference count |
* (if it is an internal object) |
*/ |
acpi_ut_add_reference(obj_desc); |
/* |
* Handle objects with multiple descriptors - walk |
* to the end of the descriptor list |
*/ |
last_obj_desc = obj_desc; |
while (last_obj_desc->common.next_object) { |
last_obj_desc = last_obj_desc->common.next_object; |
} |
/* Install the object at the front of the object list */ |
last_obj_desc->common.next_object = node->object; |
} |
node->type = (u8) object_type; |
node->object = obj_desc; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_detach_object |
* |
* PARAMETERS: node - A Namespace node whose object will be detached |
* |
* RETURN: None. |
* |
* DESCRIPTION: Detach/delete an object associated with a namespace node. |
* if the object is an allocated object, it is freed. |
* Otherwise, the field is simply cleared. |
* |
******************************************************************************/ |
void acpi_ns_detach_object(struct acpi_namespace_node *node) |
{ |
union acpi_operand_object *obj_desc; |
ACPI_FUNCTION_TRACE(ns_detach_object); |
obj_desc = node->object; |
if (!obj_desc || (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { |
return_VOID; |
} |
if (node->flags & ANOBJ_ALLOCATED_BUFFER) { |
/* Free the dynamic aml buffer */ |
if (obj_desc->common.type == ACPI_TYPE_METHOD) { |
ACPI_FREE(obj_desc->method.aml_start); |
} |
} |
/* Clear the Node entry in all cases */ |
node->object = NULL; |
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) { |
/* Unlink object from front of possible object list */ |
node->object = obj_desc->common.next_object; |
/* Handle possible 2-descriptor object */ |
if (node->object && |
(node->object->common.type != ACPI_TYPE_LOCAL_DATA)) { |
node->object = node->object->common.next_object; |
} |
/* |
* Detach the object from any data objects (which are still held by |
* the namespace node) |
*/ |
if (obj_desc->common.next_object && |
((obj_desc->common.next_object)->common.type == |
ACPI_TYPE_LOCAL_DATA)) { |
obj_desc->common.next_object = NULL; |
} |
} |
/* Reset the node type to untyped */ |
node->type = ACPI_TYPE_ANY; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", |
node, acpi_ut_get_node_name(node), obj_desc)); |
/* Remove one reference on the object (and all subobjects) */ |
acpi_ut_remove_reference(obj_desc); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_attached_object |
* |
* PARAMETERS: node - Namespace node |
* |
* RETURN: Current value of the object field from the Node whose |
* handle is passed |
* |
* DESCRIPTION: Obtain the object attached to a namespace node. |
* |
******************************************************************************/ |
union acpi_operand_object *acpi_ns_get_attached_object(struct |
acpi_namespace_node |
*node) |
{ |
ACPI_FUNCTION_TRACE_PTR(ns_get_attached_object, node); |
if (!node) { |
ACPI_WARNING((AE_INFO, "Null Node ptr")); |
return_PTR(NULL); |
} |
if (!node->object || |
((ACPI_GET_DESCRIPTOR_TYPE(node->object) != ACPI_DESC_TYPE_OPERAND) |
&& (ACPI_GET_DESCRIPTOR_TYPE(node->object) != |
ACPI_DESC_TYPE_NAMED)) |
|| ((node->object)->common.type == ACPI_TYPE_LOCAL_DATA)) { |
return_PTR(NULL); |
} |
return_PTR(node->object); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_secondary_object |
* |
* PARAMETERS: node - Namespace node |
* |
* RETURN: Current value of the object field from the Node whose |
* handle is passed. |
* |
* DESCRIPTION: Obtain a secondary object associated with a namespace node. |
* |
******************************************************************************/ |
union acpi_operand_object *acpi_ns_get_secondary_object(union |
acpi_operand_object |
*obj_desc) |
{ |
ACPI_FUNCTION_TRACE_PTR(ns_get_secondary_object, obj_desc); |
if ((!obj_desc) || |
(obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) || |
(!obj_desc->common.next_object) || |
((obj_desc->common.next_object)->common.type == |
ACPI_TYPE_LOCAL_DATA)) { |
return_PTR(NULL); |
} |
return_PTR(obj_desc->common.next_object); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_attach_data |
* |
* PARAMETERS: node - Namespace node |
* handler - Handler to be associated with the data |
* data - Data to be attached |
* |
* RETURN: Status |
* |
* DESCRIPTION: Low-level attach data. Create and attach a Data object. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_attach_data(struct acpi_namespace_node *node, |
acpi_object_handler handler, void *data) |
{ |
union acpi_operand_object *prev_obj_desc; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *data_desc; |
/* We only allow one attachment per handler */ |
prev_obj_desc = NULL; |
obj_desc = node->object; |
while (obj_desc) { |
if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && |
(obj_desc->data.handler == handler)) { |
return (AE_ALREADY_EXISTS); |
} |
prev_obj_desc = obj_desc; |
obj_desc = obj_desc->common.next_object; |
} |
/* Create an internal object for the data */ |
data_desc = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_DATA); |
if (!data_desc) { |
return (AE_NO_MEMORY); |
} |
data_desc->data.handler = handler; |
data_desc->data.pointer = data; |
/* Install the data object */ |
if (prev_obj_desc) { |
prev_obj_desc->common.next_object = data_desc; |
} else { |
node->object = data_desc; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_detach_data |
* |
* PARAMETERS: node - Namespace node |
* handler - Handler associated with the data |
* |
* RETURN: Status |
* |
* DESCRIPTION: Low-level detach data. Delete the data node, but the caller |
* is responsible for the actual data. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_detach_data(struct acpi_namespace_node * node, |
acpi_object_handler handler) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *prev_obj_desc; |
prev_obj_desc = NULL; |
obj_desc = node->object; |
while (obj_desc) { |
if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && |
(obj_desc->data.handler == handler)) { |
if (prev_obj_desc) { |
prev_obj_desc->common.next_object = |
obj_desc->common.next_object; |
} else { |
node->object = obj_desc->common.next_object; |
} |
acpi_ut_remove_reference(obj_desc); |
return (AE_OK); |
} |
prev_obj_desc = obj_desc; |
obj_desc = obj_desc->common.next_object; |
} |
return (AE_NOT_FOUND); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_attached_data |
* |
* PARAMETERS: node - Namespace node |
* handler - Handler associated with the data |
* data - Where the data is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Low level interface to obtain data previously associated with |
* a namespace node. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_get_attached_data(struct acpi_namespace_node * node, |
acpi_object_handler handler, void **data) |
{ |
union acpi_operand_object *obj_desc; |
obj_desc = node->object; |
while (obj_desc) { |
if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && |
(obj_desc->data.handler == handler)) { |
*data = obj_desc->data.pointer; |
return (AE_OK); |
} |
obj_desc = obj_desc->common.next_object; |
} |
return (AE_NOT_FOUND); |
} |
/drivers/acpi/acpica/nsparse.c |
---|
0,0 → 1,207 |
/****************************************************************************** |
* |
* Module Name: nsparse - namespace interface to AML parser |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acparser.h" |
#include "acdispat.h" |
#include "actables.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsparse") |
/******************************************************************************* |
* |
* FUNCTION: ns_one_complete_parse |
* |
* PARAMETERS: pass_number - 1 or 2 |
* table_desc - The table to be parsed. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform one complete parse of an ACPI/AML table. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_one_complete_parse(u32 pass_number, |
u32 table_index, |
struct acpi_namespace_node *start_node) |
{ |
union acpi_parse_object *parse_root; |
acpi_status status; |
u32 aml_length; |
u8 *aml_start; |
struct acpi_walk_state *walk_state; |
struct acpi_table_header *table; |
acpi_owner_id owner_id; |
ACPI_FUNCTION_TRACE(ns_one_complete_parse); |
status = acpi_get_table_by_index(table_index, &table); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Table must consist of at least a complete header */ |
if (table->length < sizeof(struct acpi_table_header)) { |
return_ACPI_STATUS(AE_BAD_HEADER); |
} |
aml_start = (u8 *)table + sizeof(struct acpi_table_header); |
aml_length = table->length - sizeof(struct acpi_table_header); |
status = acpi_tb_get_owner_id(table_index, &owner_id); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Create and init a Root Node */ |
parse_root = acpi_ps_create_scope_op(aml_start); |
if (!parse_root) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Create and initialize a new walk state */ |
walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL); |
if (!walk_state) { |
acpi_ps_free_op(parse_root); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, |
aml_start, aml_length, NULL, |
(u8)pass_number); |
if (ACPI_FAILURE(status)) { |
acpi_ds_delete_walk_state(walk_state); |
goto cleanup; |
} |
/* Found OSDT table, enable the namespace override feature */ |
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT) && |
pass_number == ACPI_IMODE_LOAD_PASS1) { |
walk_state->namespace_override = TRUE; |
} |
/* start_node is the default location to load the table */ |
if (start_node && start_node != acpi_gbl_root_node) { |
status = |
acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD, |
walk_state); |
if (ACPI_FAILURE(status)) { |
acpi_ds_delete_walk_state(walk_state); |
goto cleanup; |
} |
} |
/* Parse the AML */ |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %u parse\n", |
pass_number)); |
status = acpi_ps_parse_aml(walk_state); |
cleanup: |
acpi_ps_delete_parse_tree(parse_root); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_parse_table |
* |
* PARAMETERS: table_desc - An ACPI table descriptor for table to parse |
* start_node - Where to enter the table into the namespace |
* |
* RETURN: Status |
* |
* DESCRIPTION: Parse AML within an ACPI table and return a tree of ops |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_parse_table); |
/* |
* AML Parse, pass 1 |
* |
* In this pass, we load most of the namespace. Control methods |
* are not parsed until later. A parse tree is not created. Instead, |
* each Parser Op subtree is deleted when it is finished. This saves |
* a great deal of memory, and allows a small cache of parse objects |
* to service the entire parse. The second pass of the parse then |
* performs another complete parse of the AML. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n")); |
status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, |
table_index, start_node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* AML Parse, pass 2 |
* |
* In this pass, we resolve forward references and other things |
* that could not be completed during the first pass. |
* Another complete parse of the AML is performed, but the |
* overhead of this is compensated for by the fact that the |
* parse objects are all cached. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n")); |
status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, |
table_index, start_node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/nspredef.c |
---|
0,0 → 1,400 |
/****************************************************************************** |
* |
* Module Name: nspredef - Validation of ACPI predefined methods and objects |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define ACPI_CREATE_PREDEFINED_TABLE |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acpredef.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nspredef") |
/******************************************************************************* |
* |
* This module validates predefined ACPI objects that appear in the namespace, |
* at the time they are evaluated (via acpi_evaluate_object). The purpose of this |
* validation is to detect problems with BIOS-exposed predefined ACPI objects |
* before the results are returned to the ACPI-related drivers. |
* |
* There are several areas that are validated: |
* |
* 1) The number of input arguments as defined by the method/object in the |
* ASL is validated against the ACPI specification. |
* 2) The type of the return object (if any) is validated against the ACPI |
* specification. |
* 3) For returned package objects, the count of package elements is |
* validated, as well as the type of each package element. Nested |
* packages are supported. |
* |
* For any problems found, a warning message is issued. |
* |
******************************************************************************/ |
/* Local prototypes */ |
static acpi_status |
acpi_ns_check_reference(struct acpi_evaluate_info *info, |
union acpi_operand_object *return_object); |
static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_return_value |
* |
* PARAMETERS: node - Namespace node for the method/object |
* info - Method execution information block |
* user_param_count - Number of parameters actually passed |
* return_status - Status from the object evaluation |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check the value returned from a predefined name. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_check_return_value(struct acpi_namespace_node *node, |
struct acpi_evaluate_info *info, |
u32 user_param_count, |
acpi_status return_status, |
union acpi_operand_object **return_object_ptr) |
{ |
acpi_status status; |
const union acpi_predefined_info *predefined; |
/* If not a predefined name, we cannot validate the return object */ |
predefined = info->predefined; |
if (!predefined) { |
return (AE_OK); |
} |
/* |
* If the method failed or did not actually return an object, we cannot |
* validate the return object |
*/ |
if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) { |
return (AE_OK); |
} |
/* |
* Return value validation and possible repair. |
* |
* 1) Don't perform return value validation/repair if this feature |
* has been disabled via a global option. |
* |
* 2) We have a return value, but if one wasn't expected, just exit, |
* this is not a problem. For example, if the "Implicit Return" |
* feature is enabled, methods will always return a value. |
* |
* 3) If the return value can be of any type, then we cannot perform |
* any validation, just exit. |
*/ |
if (acpi_gbl_disable_auto_repair || |
(!predefined->info.expected_btypes) || |
(predefined->info.expected_btypes == ACPI_RTYPE_ALL)) { |
return (AE_OK); |
} |
/* |
* Check that the type of the main return object is what is expected |
* for this predefined name |
*/ |
status = acpi_ns_check_object_type(info, return_object_ptr, |
predefined->info.expected_btypes, |
ACPI_NOT_PACKAGE_ELEMENT); |
if (ACPI_FAILURE(status)) { |
goto exit; |
} |
/* |
* |
* 4) If there is no return value and it is optional, just return |
* AE_OK (_WAK). |
*/ |
if (!(*return_object_ptr)) { |
goto exit; |
} |
/* |
* For returned Package objects, check the type of all sub-objects. |
* Note: Package may have been newly created by call above. |
*/ |
if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) { |
info->parent_package = *return_object_ptr; |
status = acpi_ns_check_package(info, return_object_ptr); |
if (ACPI_FAILURE(status)) { |
/* We might be able to fix some errors */ |
if ((status != AE_AML_OPERAND_TYPE) && |
(status != AE_AML_OPERAND_VALUE)) { |
goto exit; |
} |
} |
} |
/* |
* The return object was OK, or it was successfully repaired above. |
* Now make some additional checks such as verifying that package |
* objects are sorted correctly (if required) or buffer objects have |
* the correct data width (bytes vs. dwords). These repairs are |
* performed on a per-name basis, i.e., the code is specific to |
* particular predefined names. |
*/ |
status = acpi_ns_complex_repairs(info, node, status, return_object_ptr); |
exit: |
/* |
* If the object validation failed or if we successfully repaired one |
* or more objects, mark the parent node to suppress further warning |
* messages during the next evaluation of the same method/object. |
*/ |
if (ACPI_FAILURE(status) || (info->return_flags & ACPI_OBJECT_REPAIRED)) { |
node->flags |= ANOBJ_EVALUATED; |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_object_type |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* expected_btypes - Bitmap of expected return type(s) |
* package_index - Index of object within parent package (if |
* applicable - ACPI_NOT_PACKAGE_ELEMENT |
* otherwise) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check the type of the return object against the expected object |
* type(s). Use of Btype allows multiple expected object types. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_check_object_type(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr, |
u32 expected_btypes, u32 package_index) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
acpi_status status = AE_OK; |
char type_buffer[96]; /* Room for 10 types */ |
/* A Namespace node should not get here, but make sure */ |
if (return_object && |
ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Invalid return type - Found a Namespace node [%4.4s] type %s", |
return_object->node.name.ascii, |
acpi_ut_get_type_name(return_object->node. |
type))); |
return (AE_AML_OPERAND_TYPE); |
} |
/* |
* Convert the object type (ACPI_TYPE_xxx) to a bitmapped object type. |
* The bitmapped type allows multiple possible return types. |
* |
* Note, the cases below must handle all of the possible types returned |
* from all of the predefined names (including elements of returned |
* packages) |
*/ |
info->return_btype = acpi_ns_get_bitmapped_type(return_object); |
if (info->return_btype == ACPI_RTYPE_ANY) { |
/* Not one of the supported objects, must be incorrect */ |
goto type_error_exit; |
} |
/* For reference objects, check that the reference type is correct */ |
if ((info->return_btype & expected_btypes) == ACPI_RTYPE_REFERENCE) { |
status = acpi_ns_check_reference(info, return_object); |
return (status); |
} |
/* Attempt simple repair of the returned object if necessary */ |
status = acpi_ns_simple_repair(info, expected_btypes, |
package_index, return_object_ptr); |
if (ACPI_SUCCESS(status)) { |
return (AE_OK); /* Successful repair */ |
} |
type_error_exit: |
/* Create a string with all expected types for this predefined object */ |
acpi_ut_get_expected_return_types(type_buffer, expected_btypes); |
if (!return_object) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Expected return object of type %s", |
type_buffer)); |
} else if (package_index == ACPI_NOT_PACKAGE_ELEMENT) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Return type mismatch - found %s, expected %s", |
acpi_ut_get_object_type_name |
(return_object), type_buffer)); |
} else { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Return Package type mismatch at index %u - " |
"found %s, expected %s", package_index, |
acpi_ut_get_object_type_name |
(return_object), type_buffer)); |
} |
return (AE_AML_OPERAND_TYPE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_reference |
* |
* PARAMETERS: info - Method execution information block |
* return_object - Object returned from the evaluation of a |
* method or object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check a returned reference object for the correct reference |
* type. The only reference type that can be returned from a |
* predefined method is a named reference. All others are invalid. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_check_reference(struct acpi_evaluate_info *info, |
union acpi_operand_object *return_object) |
{ |
/* |
* Check the reference object for the correct reference type (opcode). |
* The only type of reference that can be converted to an union acpi_object is |
* a reference to a named object (reference class: NAME) |
*/ |
if (return_object->reference.class == ACPI_REFCLASS_NAME) { |
return (AE_OK); |
} |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags, |
"Return type mismatch - unexpected reference object type [%s] %2.2X", |
acpi_ut_get_reference_name(return_object), |
return_object->reference.class)); |
return (AE_AML_OPERAND_TYPE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_bitmapped_type |
* |
* PARAMETERS: return_object - Object returned from method/obj evaluation |
* |
* RETURN: Object return type. ACPI_RTYPE_ANY indicates that the object |
* type is not supported. ACPI_RTYPE_NONE indicates that no |
* object was returned (return_object is NULL). |
* |
* DESCRIPTION: Convert object type into a bitmapped object return type. |
* |
******************************************************************************/ |
static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object) |
{ |
u32 return_btype; |
if (!return_object) { |
return (ACPI_RTYPE_NONE); |
} |
/* Map acpi_object_type to internal bitmapped type */ |
switch (return_object->common.type) { |
case ACPI_TYPE_INTEGER: |
return_btype = ACPI_RTYPE_INTEGER; |
break; |
case ACPI_TYPE_BUFFER: |
return_btype = ACPI_RTYPE_BUFFER; |
break; |
case ACPI_TYPE_STRING: |
return_btype = ACPI_RTYPE_STRING; |
break; |
case ACPI_TYPE_PACKAGE: |
return_btype = ACPI_RTYPE_PACKAGE; |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
return_btype = ACPI_RTYPE_REFERENCE; |
break; |
default: |
/* Not one of the supported objects, must be incorrect */ |
return_btype = ACPI_RTYPE_ANY; |
break; |
} |
return (return_btype); |
} |
/drivers/acpi/acpica/nsprepkg.c |
---|
0,0 → 1,676 |
/****************************************************************************** |
* |
* Module Name: nsprepkg - Validation of package objects for predefined names |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acpredef.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsprepkg") |
/* Local prototypes */ |
static acpi_status |
acpi_ns_check_package_list(struct acpi_evaluate_info *info, |
const union acpi_predefined_info *package, |
union acpi_operand_object **elements, u32 count); |
static acpi_status |
acpi_ns_check_package_elements(struct acpi_evaluate_info *info, |
union acpi_operand_object **elements, |
u8 type1, |
u32 count1, |
u8 type2, u32 count2, u32 start_index); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_package |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check a returned package object for the correct count and |
* correct type of all sub-objects. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_check_package(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
const union acpi_predefined_info *package; |
union acpi_operand_object **elements; |
acpi_status status = AE_OK; |
u32 expected_count; |
u32 count; |
u32 i; |
ACPI_FUNCTION_NAME(ns_check_package); |
/* The package info for this name is in the next table entry */ |
package = info->predefined + 1; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"%s Validating return Package of Type %X, Count %X\n", |
info->full_pathname, package->ret_info.type, |
return_object->package.count)); |
/* |
* For variable-length Packages, we can safely remove all embedded |
* and trailing NULL package elements |
*/ |
acpi_ns_remove_null_elements(info, package->ret_info.type, |
return_object); |
/* Extract package count and elements array */ |
elements = return_object->package.elements; |
count = return_object->package.count; |
/* |
* Most packages must have at least one element. The only exception |
* is the variable-length package (ACPI_PTYPE1_VAR). |
*/ |
if (!count) { |
if (package->ret_info.type == ACPI_PTYPE1_VAR) { |
return (AE_OK); |
} |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Return Package has no elements (empty)")); |
return (AE_AML_OPERAND_VALUE); |
} |
/* |
* Decode the type of the expected package contents |
* |
* PTYPE1 packages contain no subpackages |
* PTYPE2 packages contain subpackages |
*/ |
switch (package->ret_info.type) { |
case ACPI_PTYPE1_FIXED: |
/* |
* The package count is fixed and there are no subpackages |
* |
* If package is too small, exit. |
* If package is larger than expected, issue warning but continue |
*/ |
expected_count = |
package->ret_info.count1 + package->ret_info.count2; |
if (count < expected_count) { |
goto package_too_small; |
} else if (count > expected_count) { |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Return Package is larger than needed - " |
"found %u, expected %u\n", |
info->full_pathname, count, |
expected_count)); |
} |
/* Validate all elements of the returned package */ |
status = acpi_ns_check_package_elements(info, elements, |
package->ret_info. |
object_type1, |
package->ret_info. |
count1, |
package->ret_info. |
object_type2, |
package->ret_info. |
count2, 0); |
break; |
case ACPI_PTYPE1_VAR: |
/* |
* The package count is variable, there are no subpackages, and all |
* elements must be of the same type |
*/ |
for (i = 0; i < count; i++) { |
status = acpi_ns_check_object_type(info, elements, |
package->ret_info. |
object_type1, i); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
elements++; |
} |
break; |
case ACPI_PTYPE1_OPTION: |
/* |
* The package count is variable, there are no subpackages. There are |
* a fixed number of required elements, and a variable number of |
* optional elements. |
* |
* Check if package is at least as large as the minimum required |
*/ |
expected_count = package->ret_info3.count; |
if (count < expected_count) { |
goto package_too_small; |
} |
/* Variable number of sub-objects */ |
for (i = 0; i < count; i++) { |
if (i < package->ret_info3.count) { |
/* These are the required package elements (0, 1, or 2) */ |
status = |
acpi_ns_check_object_type(info, elements, |
package-> |
ret_info3. |
object_type[i], |
i); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} else { |
/* These are the optional package elements */ |
status = |
acpi_ns_check_object_type(info, elements, |
package-> |
ret_info3. |
tail_object_type, |
i); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
elements++; |
} |
break; |
case ACPI_PTYPE2_REV_FIXED: |
/* First element is the (Integer) revision */ |
status = acpi_ns_check_object_type(info, elements, |
ACPI_RTYPE_INTEGER, 0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
elements++; |
count--; |
/* Examine the subpackages */ |
status = |
acpi_ns_check_package_list(info, package, elements, count); |
break; |
case ACPI_PTYPE2_PKG_COUNT: |
/* First element is the (Integer) count of subpackages to follow */ |
status = acpi_ns_check_object_type(info, elements, |
ACPI_RTYPE_INTEGER, 0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* Count cannot be larger than the parent package length, but allow it |
* to be smaller. The >= accounts for the Integer above. |
*/ |
expected_count = (u32)(*elements)->integer.value; |
if (expected_count >= count) { |
goto package_too_small; |
} |
count = expected_count; |
elements++; |
/* Examine the subpackages */ |
status = |
acpi_ns_check_package_list(info, package, elements, count); |
break; |
case ACPI_PTYPE2: |
case ACPI_PTYPE2_FIXED: |
case ACPI_PTYPE2_MIN: |
case ACPI_PTYPE2_COUNT: |
case ACPI_PTYPE2_FIX_VAR: |
/* |
* These types all return a single Package that consists of a |
* variable number of subpackages. |
* |
* First, ensure that the first element is a subpackage. If not, |
* the BIOS may have incorrectly returned the object as a single |
* package instead of a Package of Packages (a common error if |
* there is only one entry). We may be able to repair this by |
* wrapping the returned Package with a new outer Package. |
*/ |
if (*elements |
&& ((*elements)->common.type != ACPI_TYPE_PACKAGE)) { |
/* Create the new outer package and populate it */ |
status = |
acpi_ns_wrap_with_package(info, return_object, |
return_object_ptr); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Update locals to point to the new package (of 1 element) */ |
return_object = *return_object_ptr; |
elements = return_object->package.elements; |
count = 1; |
} |
/* Examine the subpackages */ |
status = |
acpi_ns_check_package_list(info, package, elements, count); |
break; |
case ACPI_PTYPE2_VAR_VAR: |
/* |
* Returns a variable list of packages, each with a variable list |
* of objects. |
*/ |
break; |
case ACPI_PTYPE2_UUID_PAIR: |
/* The package must contain pairs of (UUID + type) */ |
if (count & 1) { |
expected_count = count + 1; |
goto package_too_small; |
} |
while (count > 0) { |
status = acpi_ns_check_object_type(info, elements, |
package->ret_info. |
object_type1, 0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Validate length of the UUID buffer */ |
if ((*elements)->buffer.length != 16) { |
ACPI_WARN_PREDEFINED((AE_INFO, |
info->full_pathname, |
info->node_flags, |
"Invalid length for UUID Buffer")); |
return (AE_AML_OPERAND_VALUE); |
} |
status = acpi_ns_check_object_type(info, elements + 1, |
package->ret_info. |
object_type2, 0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
elements += 2; |
count -= 2; |
} |
break; |
default: |
/* Should not get here if predefined info table is correct */ |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Invalid internal return type in table entry: %X", |
package->ret_info.type)); |
return (AE_AML_INTERNAL); |
} |
return (status); |
package_too_small: |
/* Error exit for the case with an incorrect package count */ |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags, |
"Return Package is too small - found %u elements, expected %u", |
count, expected_count)); |
return (AE_AML_OPERAND_VALUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_package_list |
* |
* PARAMETERS: info - Method execution information block |
* package - Pointer to package-specific info for method |
* elements - Element list of parent package. All elements |
* of this list should be of type Package. |
* count - Count of subpackages |
* |
* RETURN: Status |
* |
* DESCRIPTION: Examine a list of subpackages |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_check_package_list(struct acpi_evaluate_info *info, |
const union acpi_predefined_info *package, |
union acpi_operand_object **elements, u32 count) |
{ |
union acpi_operand_object *sub_package; |
union acpi_operand_object **sub_elements; |
acpi_status status; |
u32 expected_count; |
u32 i; |
u32 j; |
/* |
* Validate each subpackage in the parent Package |
* |
* NOTE: assumes list of subpackages contains no NULL elements. |
* Any NULL elements should have been removed by earlier call |
* to acpi_ns_remove_null_elements. |
*/ |
for (i = 0; i < count; i++) { |
sub_package = *elements; |
sub_elements = sub_package->package.elements; |
info->parent_package = sub_package; |
/* Each sub-object must be of type Package */ |
status = acpi_ns_check_object_type(info, &sub_package, |
ACPI_RTYPE_PACKAGE, i); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Examine the different types of expected subpackages */ |
info->parent_package = sub_package; |
switch (package->ret_info.type) { |
case ACPI_PTYPE2: |
case ACPI_PTYPE2_PKG_COUNT: |
case ACPI_PTYPE2_REV_FIXED: |
/* Each subpackage has a fixed number of elements */ |
expected_count = |
package->ret_info.count1 + package->ret_info.count2; |
if (sub_package->package.count < expected_count) { |
goto package_too_small; |
} |
status = |
acpi_ns_check_package_elements(info, sub_elements, |
package->ret_info. |
object_type1, |
package->ret_info. |
count1, |
package->ret_info. |
object_type2, |
package->ret_info. |
count2, 0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
case ACPI_PTYPE2_FIX_VAR: |
/* |
* Each subpackage has a fixed number of elements and an |
* optional element |
*/ |
expected_count = |
package->ret_info.count1 + package->ret_info.count2; |
if (sub_package->package.count < expected_count) { |
goto package_too_small; |
} |
status = |
acpi_ns_check_package_elements(info, sub_elements, |
package->ret_info. |
object_type1, |
package->ret_info. |
count1, |
package->ret_info. |
object_type2, |
sub_package->package. |
count - |
package->ret_info. |
count1, 0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
case ACPI_PTYPE2_VAR_VAR: |
/* |
* Each subpackage has a fixed or variable number of elements |
*/ |
break; |
case ACPI_PTYPE2_FIXED: |
/* Each subpackage has a fixed length */ |
expected_count = package->ret_info2.count; |
if (sub_package->package.count < expected_count) { |
goto package_too_small; |
} |
/* Check the type of each subpackage element */ |
for (j = 0; j < expected_count; j++) { |
status = |
acpi_ns_check_object_type(info, |
&sub_elements[j], |
package-> |
ret_info2. |
object_type[j], |
j); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
break; |
case ACPI_PTYPE2_MIN: |
/* Each subpackage has a variable but minimum length */ |
expected_count = package->ret_info.count1; |
if (sub_package->package.count < expected_count) { |
goto package_too_small; |
} |
/* Check the type of each subpackage element */ |
status = |
acpi_ns_check_package_elements(info, sub_elements, |
package->ret_info. |
object_type1, |
sub_package->package. |
count, 0, 0, 0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
case ACPI_PTYPE2_COUNT: |
/* |
* First element is the (Integer) count of elements, including |
* the count field (the ACPI name is num_elements) |
*/ |
status = acpi_ns_check_object_type(info, sub_elements, |
ACPI_RTYPE_INTEGER, |
0); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* Make sure package is large enough for the Count and is |
* is as large as the minimum size |
*/ |
expected_count = (u32)(*sub_elements)->integer.value; |
if (sub_package->package.count < expected_count) { |
goto package_too_small; |
} |
if (sub_package->package.count < |
package->ret_info.count1) { |
expected_count = package->ret_info.count1; |
goto package_too_small; |
} |
if (expected_count == 0) { |
/* |
* Either the num_entries element was originally zero or it was |
* a NULL element and repaired to an Integer of value zero. |
* In either case, repair it by setting num_entries to be the |
* actual size of the subpackage. |
*/ |
expected_count = sub_package->package.count; |
(*sub_elements)->integer.value = expected_count; |
} |
/* Check the type of each subpackage element */ |
status = |
acpi_ns_check_package_elements(info, |
(sub_elements + 1), |
package->ret_info. |
object_type1, |
(expected_count - 1), |
0, 0, 1); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
default: /* Should not get here, type was validated by caller */ |
return (AE_AML_INTERNAL); |
} |
elements++; |
} |
return (AE_OK); |
package_too_small: |
/* The subpackage count was smaller than required */ |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags, |
"Return SubPackage[%u] is too small - found %u elements, expected %u", |
i, sub_package->package.count, expected_count)); |
return (AE_AML_OPERAND_VALUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_check_package_elements |
* |
* PARAMETERS: info - Method execution information block |
* elements - Pointer to the package elements array |
* type1 - Object type for first group |
* count1 - Count for first group |
* type2 - Object type for second group |
* count2 - Count for second group |
* start_index - Start of the first group of elements |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check that all elements of a package are of the correct object |
* type. Supports up to two groups of different object types. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_check_package_elements(struct acpi_evaluate_info *info, |
union acpi_operand_object **elements, |
u8 type1, |
u32 count1, |
u8 type2, u32 count2, u32 start_index) |
{ |
union acpi_operand_object **this_element = elements; |
acpi_status status; |
u32 i; |
/* |
* Up to two groups of package elements are supported by the data |
* structure. All elements in each group must be of the same type. |
* The second group can have a count of zero. |
*/ |
for (i = 0; i < count1; i++) { |
status = acpi_ns_check_object_type(info, this_element, |
type1, i + start_index); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
this_element++; |
} |
for (i = 0; i < count2; i++) { |
status = acpi_ns_check_object_type(info, this_element, |
type2, |
(i + count1 + start_index)); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
this_element++; |
} |
return (AE_OK); |
} |
/drivers/acpi/acpica/nsrepair.c |
---|
0,0 → 1,595 |
/****************************************************************************** |
* |
* Module Name: nsrepair - Repair for objects returned by predefined methods |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#include "acpredef.h" |
#include "amlresrc.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsrepair") |
/******************************************************************************* |
* |
* This module attempts to repair or convert objects returned by the |
* predefined methods to an object type that is expected, as per the ACPI |
* specification. The need for this code is dictated by the many machines that |
* return incorrect types for the standard predefined methods. Performing these |
* conversions here, in one place, eliminates the need for individual ACPI |
* device drivers to do the same. Note: Most of these conversions are different |
* than the internal object conversion routines used for implicit object |
* conversion. |
* |
* The following conversions can be performed as necessary: |
* |
* Integer -> String |
* Integer -> Buffer |
* String -> Integer |
* String -> Buffer |
* Buffer -> Integer |
* Buffer -> String |
* Buffer -> Package of Integers |
* Package -> Package of one Package |
* |
* Additional conversions that are available: |
* Convert a null return or zero return value to an end_tag descriptor |
* Convert an ASCII string to a Unicode buffer |
* |
* An incorrect standalone object is wrapped with required outer package |
* |
* Additional possible repairs: |
* Required package elements that are NULL replaced by Integer/String/Buffer |
* |
******************************************************************************/ |
/* Local prototypes */ |
static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct |
acpi_namespace_node |
*node, |
u32 |
return_btype, |
u32 |
package_index); |
/* |
* Special but simple repairs for some names. |
* |
* 2nd argument: Unexpected types that can be repaired |
*/ |
static const struct acpi_simple_repair_info acpi_object_repair_info[] = { |
/* Resource descriptor conversions */ |
{"_CRS", |
ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | |
ACPI_RTYPE_NONE, |
ACPI_NOT_PACKAGE_ELEMENT, |
acpi_ns_convert_to_resource}, |
{"_DMA", |
ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | |
ACPI_RTYPE_NONE, |
ACPI_NOT_PACKAGE_ELEMENT, |
acpi_ns_convert_to_resource}, |
{"_PRS", |
ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | |
ACPI_RTYPE_NONE, |
ACPI_NOT_PACKAGE_ELEMENT, |
acpi_ns_convert_to_resource}, |
/* Unicode conversions */ |
{"_MLS", ACPI_RTYPE_STRING, 1, |
acpi_ns_convert_to_unicode}, |
{"_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER, |
ACPI_NOT_PACKAGE_ELEMENT, |
acpi_ns_convert_to_unicode}, |
{{0, 0, 0, 0}, 0, 0, NULL} /* Table terminator */ |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_simple_repair |
* |
* PARAMETERS: info - Method execution information block |
* expected_btypes - Object types expected |
* package_index - Index of object within parent package (if |
* applicable - ACPI_NOT_PACKAGE_ELEMENT |
* otherwise) |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if repair was successful. |
* |
* DESCRIPTION: Attempt to repair/convert a return object of a type that was |
* not expected. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_simple_repair(struct acpi_evaluate_info *info, |
u32 expected_btypes, |
u32 package_index, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
union acpi_operand_object *new_object = NULL; |
acpi_status status; |
const struct acpi_simple_repair_info *predefined; |
ACPI_FUNCTION_NAME(ns_simple_repair); |
/* |
* Special repairs for certain names that are in the repair table. |
* Check if this name is in the list of repairable names. |
*/ |
predefined = acpi_ns_match_simple_repair(info->node, |
info->return_btype, |
package_index); |
if (predefined) { |
if (!return_object) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
ACPI_WARN_ALWAYS, |
"Missing expected return value")); |
} |
status = |
predefined->object_converter(return_object, &new_object); |
if (ACPI_FAILURE(status)) { |
/* A fatal error occurred during a conversion */ |
ACPI_EXCEPTION((AE_INFO, status, |
"During return object analysis")); |
return (status); |
} |
if (new_object) { |
goto object_repaired; |
} |
} |
/* |
* Do not perform simple object repair unless the return type is not |
* expected. |
*/ |
if (info->return_btype & expected_btypes) { |
return (AE_OK); |
} |
/* |
* At this point, we know that the type of the returned object was not |
* one of the expected types for this predefined name. Attempt to |
* repair the object by converting it to one of the expected object |
* types for this predefined name. |
*/ |
/* |
* If there is no return value, check if we require a return value for |
* this predefined name. Either one return value is expected, or none, |
* for both methods and other objects. |
* |
* Try to fix if there was no return object. Warning if failed to fix. |
*/ |
if (!return_object) { |
if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) { |
if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { |
ACPI_WARN_PREDEFINED((AE_INFO, |
info->full_pathname, |
ACPI_WARN_ALWAYS, |
"Found unexpected NULL package element")); |
status = |
acpi_ns_repair_null_element(info, |
expected_btypes, |
package_index, |
return_object_ptr); |
if (ACPI_SUCCESS(status)) { |
return (AE_OK); /* Repair was successful */ |
} |
} else { |
ACPI_WARN_PREDEFINED((AE_INFO, |
info->full_pathname, |
ACPI_WARN_ALWAYS, |
"Missing expected return value")); |
} |
return (AE_AML_NO_RETURN_VALUE); |
} |
} |
if (expected_btypes & ACPI_RTYPE_INTEGER) { |
status = acpi_ns_convert_to_integer(return_object, &new_object); |
if (ACPI_SUCCESS(status)) { |
goto object_repaired; |
} |
} |
if (expected_btypes & ACPI_RTYPE_STRING) { |
status = acpi_ns_convert_to_string(return_object, &new_object); |
if (ACPI_SUCCESS(status)) { |
goto object_repaired; |
} |
} |
if (expected_btypes & ACPI_RTYPE_BUFFER) { |
status = acpi_ns_convert_to_buffer(return_object, &new_object); |
if (ACPI_SUCCESS(status)) { |
goto object_repaired; |
} |
} |
if (expected_btypes & ACPI_RTYPE_PACKAGE) { |
/* |
* A package is expected. We will wrap the existing object with a |
* new package object. It is often the case that if a variable-length |
* package is required, but there is only a single object needed, the |
* BIOS will return that object instead of wrapping it with a Package |
* object. Note: after the wrapping, the package will be validated |
* for correct contents (expected object type or types). |
*/ |
status = |
acpi_ns_wrap_with_package(info, return_object, &new_object); |
if (ACPI_SUCCESS(status)) { |
/* |
* The original object just had its reference count |
* incremented for being inserted into the new package. |
*/ |
*return_object_ptr = new_object; /* New Package object */ |
info->return_flags |= ACPI_OBJECT_REPAIRED; |
return (AE_OK); |
} |
} |
/* We cannot repair this object */ |
return (AE_AML_OPERAND_TYPE); |
object_repaired: |
/* Object was successfully repaired */ |
if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { |
/* |
* The original object is a package element. We need to |
* decrement the reference count of the original object, |
* for removing it from the package. |
* |
* However, if the original object was just wrapped with a |
* package object as part of the repair, we don't need to |
* change the reference count. |
*/ |
if (!(info->return_flags & ACPI_OBJECT_WRAPPED)) { |
new_object->common.reference_count = |
return_object->common.reference_count; |
if (return_object->common.reference_count > 1) { |
return_object->common.reference_count--; |
} |
} |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Converted %s to expected %s at Package index %u\n", |
info->full_pathname, |
acpi_ut_get_object_type_name(return_object), |
acpi_ut_get_object_type_name(new_object), |
package_index)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Converted %s to expected %s\n", |
info->full_pathname, |
acpi_ut_get_object_type_name(return_object), |
acpi_ut_get_object_type_name(new_object))); |
} |
/* Delete old object, install the new return object */ |
acpi_ut_remove_reference(return_object); |
*return_object_ptr = new_object; |
info->return_flags |= ACPI_OBJECT_REPAIRED; |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_match_simple_repair |
* |
* PARAMETERS: node - Namespace node for the method/object |
* return_btype - Object type that was returned |
* package_index - Index of object within parent package (if |
* applicable - ACPI_NOT_PACKAGE_ELEMENT |
* otherwise) |
* |
* RETURN: Pointer to entry in repair table. NULL indicates not found. |
* |
* DESCRIPTION: Check an object name against the repairable object list. |
* |
*****************************************************************************/ |
static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct |
acpi_namespace_node |
*node, |
u32 |
return_btype, |
u32 |
package_index) |
{ |
const struct acpi_simple_repair_info *this_name; |
/* Search info table for a repairable predefined method/object name */ |
this_name = acpi_object_repair_info; |
while (this_name->object_converter) { |
if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) { |
/* Check if we can actually repair this name/type combination */ |
if ((return_btype & this_name->unexpected_btypes) && |
(package_index == this_name->package_index)) { |
return (this_name); |
} |
return (NULL); |
} |
this_name++; |
} |
return (NULL); /* Name was not found in the repair table */ |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_repair_null_element |
* |
* PARAMETERS: info - Method execution information block |
* expected_btypes - Object types expected |
* package_index - Index of object within parent package (if |
* applicable - ACPI_NOT_PACKAGE_ELEMENT |
* otherwise) |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if repair was successful. |
* |
* DESCRIPTION: Attempt to repair a NULL element of a returned Package object. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_repair_null_element(struct acpi_evaluate_info * info, |
u32 expected_btypes, |
u32 package_index, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
union acpi_operand_object *new_object; |
ACPI_FUNCTION_NAME(ns_repair_null_element); |
/* No repair needed if return object is non-NULL */ |
if (return_object) { |
return (AE_OK); |
} |
/* |
* Attempt to repair a NULL element of a Package object. This applies to |
* predefined names that return a fixed-length package and each element |
* is required. It does not apply to variable-length packages where NULL |
* elements are allowed, especially at the end of the package. |
*/ |
if (expected_btypes & ACPI_RTYPE_INTEGER) { |
/* Need an integer - create a zero-value integer */ |
new_object = acpi_ut_create_integer_object((u64)0); |
} else if (expected_btypes & ACPI_RTYPE_STRING) { |
/* Need a string - create a NULL string */ |
new_object = acpi_ut_create_string_object(0); |
} else if (expected_btypes & ACPI_RTYPE_BUFFER) { |
/* Need a buffer - create a zero-length buffer */ |
new_object = acpi_ut_create_buffer_object(0); |
} else { |
/* Error for all other expected types */ |
return (AE_AML_OPERAND_TYPE); |
} |
if (!new_object) { |
return (AE_NO_MEMORY); |
} |
/* Set the reference count according to the parent Package object */ |
new_object->common.reference_count = |
info->parent_package->common.reference_count; |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Converted NULL package element to expected %s at index %u\n", |
info->full_pathname, |
acpi_ut_get_object_type_name(new_object), |
package_index)); |
*return_object_ptr = new_object; |
info->return_flags |= ACPI_OBJECT_REPAIRED; |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_remove_null_elements |
* |
* PARAMETERS: info - Method execution information block |
* package_type - An acpi_return_package_types value |
* obj_desc - A Package object |
* |
* RETURN: None. |
* |
* DESCRIPTION: Remove all NULL package elements from packages that contain |
* a variable number of subpackages. For these types of |
* packages, NULL elements can be safely removed. |
* |
*****************************************************************************/ |
void |
acpi_ns_remove_null_elements(struct acpi_evaluate_info *info, |
u8 package_type, |
union acpi_operand_object *obj_desc) |
{ |
union acpi_operand_object **source; |
union acpi_operand_object **dest; |
u32 count; |
u32 new_count; |
u32 i; |
ACPI_FUNCTION_NAME(ns_remove_null_elements); |
/* |
* We can safely remove all NULL elements from these package types: |
* PTYPE1_VAR packages contain a variable number of simple data types. |
* PTYPE2 packages contain a variable number of subpackages. |
*/ |
switch (package_type) { |
case ACPI_PTYPE1_VAR: |
case ACPI_PTYPE2: |
case ACPI_PTYPE2_COUNT: |
case ACPI_PTYPE2_PKG_COUNT: |
case ACPI_PTYPE2_FIXED: |
case ACPI_PTYPE2_MIN: |
case ACPI_PTYPE2_REV_FIXED: |
case ACPI_PTYPE2_FIX_VAR: |
break; |
default: |
case ACPI_PTYPE2_VAR_VAR: |
case ACPI_PTYPE1_FIXED: |
case ACPI_PTYPE1_OPTION: |
return; |
} |
count = obj_desc->package.count; |
new_count = count; |
source = obj_desc->package.elements; |
dest = source; |
/* Examine all elements of the package object, remove nulls */ |
for (i = 0; i < count; i++) { |
if (!*source) { |
new_count--; |
} else { |
*dest = *source; |
dest++; |
} |
source++; |
} |
/* Update parent package if any null elements were removed */ |
if (new_count < count) { |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Found and removed %u NULL elements\n", |
info->full_pathname, (count - new_count))); |
/* NULL terminate list and update the package count */ |
*dest = NULL; |
obj_desc->package.count = new_count; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_wrap_with_package |
* |
* PARAMETERS: info - Method execution information block |
* original_object - Pointer to the object to repair. |
* obj_desc_ptr - The new package object is returned here |
* |
* RETURN: Status, new object in *obj_desc_ptr |
* |
* DESCRIPTION: Repair a common problem with objects that are defined to |
* return a variable-length Package of sub-objects. If there is |
* only one sub-object, some BIOS code mistakenly simply declares |
* the single object instead of a Package with one sub-object. |
* This function attempts to repair this error by wrapping a |
* Package object around the original object, creating the |
* correct and expected Package with one sub-object. |
* |
* Names that can be repaired in this manner include: |
* _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS, |
* _BCL, _DOD, _FIX, _Sx |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_wrap_with_package(struct acpi_evaluate_info *info, |
union acpi_operand_object *original_object, |
union acpi_operand_object **obj_desc_ptr) |
{ |
union acpi_operand_object *pkg_obj_desc; |
ACPI_FUNCTION_NAME(ns_wrap_with_package); |
/* |
* Create the new outer package and populate it. The new package will |
* have a single element, the lone sub-object. |
*/ |
pkg_obj_desc = acpi_ut_create_package_object(1); |
if (!pkg_obj_desc) { |
return (AE_NO_MEMORY); |
} |
pkg_obj_desc->package.elements[0] = original_object; |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Wrapped %s with expected Package object\n", |
info->full_pathname, |
acpi_ut_get_object_type_name(original_object))); |
/* Return the new object in the object pointer */ |
*obj_desc_ptr = pkg_obj_desc; |
info->return_flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED; |
return (AE_OK); |
} |
/drivers/acpi/acpica/nsrepair2.c |
---|
0,0 → 1,979 |
/****************************************************************************** |
* |
* Module Name: nsrepair2 - Repair for objects returned by specific |
* predefined methods |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsrepair2") |
/* |
* Information structure and handler for ACPI predefined names that can |
* be repaired on a per-name basis. |
*/ |
typedef |
acpi_status(*acpi_repair_function) (struct acpi_evaluate_info * info, |
union acpi_operand_object |
**return_object_ptr); |
typedef struct acpi_repair_info { |
char name[ACPI_NAME_SIZE]; |
acpi_repair_function repair_function; |
} acpi_repair_info; |
/* Local prototypes */ |
static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct |
acpi_namespace_node |
*node); |
static acpi_status |
acpi_ns_repair_ALR(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_repair_CID(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_repair_CST(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_repair_FDE(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_repair_HID(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_repair_PRT(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_repair_PSS(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_repair_TSS(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr); |
static acpi_status |
acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, |
union acpi_operand_object *return_object, |
u32 start_index, |
u32 expected_count, |
u32 sort_index, |
u8 sort_direction, char *sort_key_name); |
/* Values for sort_direction above */ |
#define ACPI_SORT_ASCENDING 0 |
#define ACPI_SORT_DESCENDING 1 |
static void |
acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index); |
static void |
acpi_ns_sort_list(union acpi_operand_object **elements, |
u32 count, u32 index, u8 sort_direction); |
/* |
* This table contains the names of the predefined methods for which we can |
* perform more complex repairs. |
* |
* As necessary: |
* |
* _ALR: Sort the list ascending by ambient_illuminance |
* _CID: Strings: uppercase all, remove any leading asterisk |
* _CST: Sort the list ascending by C state type |
* _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs |
* _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs |
* _HID: Strings: uppercase all, remove any leading asterisk |
* _PRT: Fix reversed source_name and source_index |
* _PSS: Sort the list descending by Power |
* _TSS: Sort the list descending by Power |
* |
* Names that must be packages, but cannot be sorted: |
* |
* _BCL: Values are tied to the Package index where they appear, and cannot |
* be moved or sorted. These index values are used for _BQC and _BCM. |
* However, we can fix the case where a buffer is returned, by converting |
* it to a Package of integers. |
*/ |
static const struct acpi_repair_info acpi_ns_repairable_names[] = { |
{"_ALR", acpi_ns_repair_ALR}, |
{"_CID", acpi_ns_repair_CID}, |
{"_CST", acpi_ns_repair_CST}, |
{"_FDE", acpi_ns_repair_FDE}, |
{"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ |
{"_HID", acpi_ns_repair_HID}, |
{"_PRT", acpi_ns_repair_PRT}, |
{"_PSS", acpi_ns_repair_PSS}, |
{"_TSS", acpi_ns_repair_TSS}, |
{{0, 0, 0, 0}, NULL} /* Table terminator */ |
}; |
#define ACPI_FDE_FIELD_COUNT 5 |
#define ACPI_FDE_BYTE_BUFFER_SIZE 5 |
#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (u32)) |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_complex_repairs |
* |
* PARAMETERS: info - Method execution information block |
* node - Namespace node for the method/object |
* validate_status - Original status of earlier validation |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if repair was successful. If name is not |
* matched, validate_status is returned. |
* |
* DESCRIPTION: Attempt to repair/convert a return object of a type that was |
* not expected. |
* |
*****************************************************************************/ |
acpi_status |
acpi_ns_complex_repairs(struct acpi_evaluate_info *info, |
struct acpi_namespace_node *node, |
acpi_status validate_status, |
union acpi_operand_object **return_object_ptr) |
{ |
const struct acpi_repair_info *predefined; |
acpi_status status; |
/* Check if this name is in the list of repairable names */ |
predefined = acpi_ns_match_complex_repair(node); |
if (!predefined) { |
return (validate_status); |
} |
status = predefined->repair_function(info, return_object_ptr); |
return (status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_match_complex_repair |
* |
* PARAMETERS: node - Namespace node for the method/object |
* |
* RETURN: Pointer to entry in repair table. NULL indicates not found. |
* |
* DESCRIPTION: Check an object name against the repairable object list. |
* |
*****************************************************************************/ |
static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct |
acpi_namespace_node |
*node) |
{ |
const struct acpi_repair_info *this_name; |
/* Search info table for a repairable predefined method/object name */ |
this_name = acpi_ns_repairable_names; |
while (this_name->repair_function) { |
if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) { |
return (this_name); |
} |
this_name++; |
} |
return (NULL); /* Not found */ |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_ALR |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list |
* ascending by the ambient illuminance values. |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_ALR(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
acpi_status status; |
status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1, |
ACPI_SORT_ASCENDING, |
"AmbientIlluminance"); |
return (status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_FDE |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return |
* value is a Buffer of 5 DWORDs. This function repairs a common |
* problem where the return value is a Buffer of BYTEs, not |
* DWORDs. |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_FDE(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
union acpi_operand_object *buffer_object; |
u8 *byte_buffer; |
u32 *dword_buffer; |
u32 i; |
ACPI_FUNCTION_NAME(ns_repair_FDE); |
switch (return_object->common.type) { |
case ACPI_TYPE_BUFFER: |
/* This is the expected type. Length should be (at least) 5 DWORDs */ |
if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) { |
return (AE_OK); |
} |
/* We can only repair if we have exactly 5 BYTEs */ |
if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Incorrect return buffer length %u, expected %u", |
return_object->buffer.length, |
ACPI_FDE_DWORD_BUFFER_SIZE)); |
return (AE_AML_OPERAND_TYPE); |
} |
/* Create the new (larger) buffer object */ |
buffer_object = |
acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE); |
if (!buffer_object) { |
return (AE_NO_MEMORY); |
} |
/* Expand each byte to a DWORD */ |
byte_buffer = return_object->buffer.pointer; |
dword_buffer = |
ACPI_CAST_PTR(u32, buffer_object->buffer.pointer); |
for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) { |
*dword_buffer = (u32) *byte_buffer; |
dword_buffer++; |
byte_buffer++; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s Expanded Byte Buffer to expected DWord Buffer\n", |
info->full_pathname)); |
break; |
default: |
return (AE_AML_OPERAND_TYPE); |
} |
/* Delete the original return object, return the new buffer object */ |
acpi_ut_remove_reference(return_object); |
*return_object_ptr = buffer_object; |
info->return_flags |= ACPI_OBJECT_REPAIRED; |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_CID |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _CID object. If a string, ensure that all |
* letters are uppercase and that there is no leading asterisk. |
* If a Package, ensure same for all string elements. |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_CID(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
acpi_status status; |
union acpi_operand_object *return_object = *return_object_ptr; |
union acpi_operand_object **element_ptr; |
union acpi_operand_object *original_element; |
u16 original_ref_count; |
u32 i; |
/* Check for _CID as a simple string */ |
if (return_object->common.type == ACPI_TYPE_STRING) { |
status = acpi_ns_repair_HID(info, return_object_ptr); |
return (status); |
} |
/* Exit if not a Package */ |
if (return_object->common.type != ACPI_TYPE_PACKAGE) { |
return (AE_OK); |
} |
/* Examine each element of the _CID package */ |
element_ptr = return_object->package.elements; |
for (i = 0; i < return_object->package.count; i++) { |
original_element = *element_ptr; |
original_ref_count = original_element->common.reference_count; |
status = acpi_ns_repair_HID(info, element_ptr); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Take care with reference counts */ |
if (original_element != *element_ptr) { |
/* Element was replaced */ |
(*element_ptr)->common.reference_count = |
original_ref_count; |
acpi_ut_remove_reference(original_element); |
} |
element_ptr++; |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_CST |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _CST object: |
* 1. Sort the list ascending by C state type |
* 2. Ensure type cannot be zero |
* 3. A subpackage count of zero means _CST is meaningless |
* 4. Count must match the number of C state subpackages |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_CST(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
union acpi_operand_object **outer_elements; |
u32 outer_element_count; |
union acpi_operand_object *obj_desc; |
acpi_status status; |
u8 removing; |
u32 i; |
ACPI_FUNCTION_NAME(ns_repair_CST); |
/* |
* Check if the C-state type values are proportional. |
*/ |
outer_element_count = return_object->package.count - 1; |
i = 0; |
while (i < outer_element_count) { |
outer_elements = &return_object->package.elements[i + 1]; |
removing = FALSE; |
if ((*outer_elements)->package.count == 0) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"SubPackage[%u] - removing entry due to zero count", |
i)); |
removing = TRUE; |
goto remove_element; |
} |
obj_desc = (*outer_elements)->package.elements[1]; /* Index1 = Type */ |
if ((u32)obj_desc->integer.value == 0) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"SubPackage[%u] - removing entry due to invalid Type(0)", |
i)); |
removing = TRUE; |
} |
remove_element: |
if (removing) { |
acpi_ns_remove_element(return_object, i + 1); |
outer_element_count--; |
} else { |
i++; |
} |
} |
/* Update top-level package count, Type "Integer" checked elsewhere */ |
obj_desc = return_object->package.elements[0]; |
obj_desc->integer.value = outer_element_count; |
/* |
* Entries (subpackages) in the _CST Package must be sorted by the |
* C-state type, in ascending order. |
*/ |
status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1, |
ACPI_SORT_ASCENDING, "C-State Type"); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_HID |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _HID object. If a string, ensure that all |
* letters are uppercase and that there is no leading asterisk. |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_HID(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
union acpi_operand_object *new_string; |
char *source; |
char *dest; |
ACPI_FUNCTION_NAME(ns_repair_HID); |
/* We only care about string _HID objects (not integers) */ |
if (return_object->common.type != ACPI_TYPE_STRING) { |
return (AE_OK); |
} |
if (return_object->string.length == 0) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"Invalid zero-length _HID or _CID string")); |
/* Return AE_OK anyway, let driver handle it */ |
info->return_flags |= ACPI_OBJECT_REPAIRED; |
return (AE_OK); |
} |
/* It is simplest to always create a new string object */ |
new_string = acpi_ut_create_string_object(return_object->string.length); |
if (!new_string) { |
return (AE_NO_MEMORY); |
} |
/* |
* Remove a leading asterisk if present. For some unknown reason, there |
* are many machines in the field that contains IDs like this. |
* |
* Examples: "*PNP0C03", "*ACPI0003" |
*/ |
source = return_object->string.pointer; |
if (*source == '*') { |
source++; |
new_string->string.length--; |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Removed invalid leading asterisk\n", |
info->full_pathname)); |
} |
/* |
* Copy and uppercase the string. From the ACPI 5.0 specification: |
* |
* A valid PNP ID must be of the form "AAA####" where A is an uppercase |
* letter and # is a hex digit. A valid ACPI ID must be of the form |
* "NNNN####" where N is an uppercase letter or decimal digit, and |
* # is a hex digit. |
*/ |
for (dest = new_string->string.pointer; *source; dest++, source++) { |
*dest = (char)toupper((int)*source); |
} |
acpi_ut_remove_reference(return_object); |
*return_object_ptr = new_string; |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_PRT |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed |
* source_name and source_index field, a common BIOS bug. |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_PRT(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *package_object = *return_object_ptr; |
union acpi_operand_object **top_object_list; |
union acpi_operand_object **sub_object_list; |
union acpi_operand_object *obj_desc; |
union acpi_operand_object *sub_package; |
u32 element_count; |
u32 index; |
/* Each element in the _PRT package is a subpackage */ |
top_object_list = package_object->package.elements; |
element_count = package_object->package.count; |
/* Examine each subpackage */ |
for (index = 0; index < element_count; index++, top_object_list++) { |
sub_package = *top_object_list; |
sub_object_list = sub_package->package.elements; |
/* Check for minimum required element count */ |
if (sub_package->package.count < 4) { |
continue; |
} |
/* |
* If the BIOS has erroneously reversed the _PRT source_name (index 2) |
* and the source_index (index 3), fix it. _PRT is important enough to |
* workaround this BIOS error. This also provides compatibility with |
* other ACPI implementations. |
*/ |
obj_desc = sub_object_list[3]; |
if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) { |
sub_object_list[3] = sub_object_list[2]; |
sub_object_list[2] = obj_desc; |
info->return_flags |= ACPI_OBJECT_REPAIRED; |
ACPI_WARN_PREDEFINED((AE_INFO, |
info->full_pathname, |
info->node_flags, |
"PRT[%X]: Fixed reversed SourceName and SourceIndex", |
index)); |
} |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_PSS |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list |
* by the CPU frequencies. Check that the power dissipation values |
* are all proportional to CPU frequency (i.e., sorting by |
* frequency should be the same as sorting by power.) |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_PSS(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
union acpi_operand_object **outer_elements; |
u32 outer_element_count; |
union acpi_operand_object **elements; |
union acpi_operand_object *obj_desc; |
u32 previous_value; |
acpi_status status; |
u32 i; |
/* |
* Entries (subpackages) in the _PSS Package must be sorted by power |
* dissipation, in descending order. If it appears that the list is |
* incorrectly sorted, sort it. We sort by cpu_frequency, since this |
* should be proportional to the power. |
*/ |
status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0, |
ACPI_SORT_DESCENDING, |
"CpuFrequency"); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* |
* We now know the list is correctly sorted by CPU frequency. Check if |
* the power dissipation values are proportional. |
*/ |
previous_value = ACPI_UINT32_MAX; |
outer_elements = return_object->package.elements; |
outer_element_count = return_object->package.count; |
for (i = 0; i < outer_element_count; i++) { |
elements = (*outer_elements)->package.elements; |
obj_desc = elements[1]; /* Index1 = power_dissipation */ |
if ((u32) obj_desc->integer.value > previous_value) { |
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
info->node_flags, |
"SubPackage[%u,%u] - suspicious power dissipation values", |
i - 1, i)); |
} |
previous_value = (u32) obj_desc->integer.value; |
outer_elements++; |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_repair_TSS |
* |
* PARAMETERS: info - Method execution information block |
* return_object_ptr - Pointer to the object returned from the |
* evaluation of a method or object |
* |
* RETURN: Status. AE_OK if object is OK or was repaired successfully |
* |
* DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list |
* descending by the power dissipation values. |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_repair_TSS(struct acpi_evaluate_info *info, |
union acpi_operand_object **return_object_ptr) |
{ |
union acpi_operand_object *return_object = *return_object_ptr; |
acpi_status status; |
struct acpi_namespace_node *node; |
/* |
* We can only sort the _TSS return package if there is no _PSS in the |
* same scope. This is because if _PSS is present, the ACPI specification |
* dictates that the _TSS Power Dissipation field is to be ignored, and |
* therefore some BIOSs leave garbage values in the _TSS Power field(s). |
* In this case, it is best to just return the _TSS package as-is. |
* (May, 2011) |
*/ |
status = acpi_ns_get_node(info->node, "^_PSS", |
ACPI_NS_NO_UPSEARCH, &node); |
if (ACPI_SUCCESS(status)) { |
return (AE_OK); |
} |
status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1, |
ACPI_SORT_DESCENDING, |
"PowerDissipation"); |
return (status); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_check_sorted_list |
* |
* PARAMETERS: info - Method execution information block |
* return_object - Pointer to the top-level returned object |
* start_index - Index of the first subpackage |
* expected_count - Minimum length of each subpackage |
* sort_index - Subpackage entry to sort on |
* sort_direction - Ascending or descending |
* sort_key_name - Name of the sort_index field |
* |
* RETURN: Status. AE_OK if the list is valid and is sorted correctly or |
* has been repaired by sorting the list. |
* |
* DESCRIPTION: Check if the package list is valid and sorted correctly by the |
* sort_index. If not, then sort the list. |
* |
*****************************************************************************/ |
static acpi_status |
acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, |
union acpi_operand_object *return_object, |
u32 start_index, |
u32 expected_count, |
u32 sort_index, |
u8 sort_direction, char *sort_key_name) |
{ |
u32 outer_element_count; |
union acpi_operand_object **outer_elements; |
union acpi_operand_object **elements; |
union acpi_operand_object *obj_desc; |
u32 i; |
u32 previous_value; |
ACPI_FUNCTION_NAME(ns_check_sorted_list); |
/* The top-level object must be a package */ |
if (return_object->common.type != ACPI_TYPE_PACKAGE) { |
return (AE_AML_OPERAND_TYPE); |
} |
/* |
* NOTE: assumes list of subpackages contains no NULL elements. |
* Any NULL elements should have been removed by earlier call |
* to acpi_ns_remove_null_elements. |
*/ |
outer_element_count = return_object->package.count; |
if (!outer_element_count || start_index >= outer_element_count) { |
return (AE_AML_PACKAGE_LIMIT); |
} |
outer_elements = &return_object->package.elements[start_index]; |
outer_element_count -= start_index; |
previous_value = 0; |
if (sort_direction == ACPI_SORT_DESCENDING) { |
previous_value = ACPI_UINT32_MAX; |
} |
/* Examine each subpackage */ |
for (i = 0; i < outer_element_count; i++) { |
/* Each element of the top-level package must also be a package */ |
if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) { |
return (AE_AML_OPERAND_TYPE); |
} |
/* Each subpackage must have the minimum length */ |
if ((*outer_elements)->package.count < expected_count) { |
return (AE_AML_PACKAGE_LIMIT); |
} |
elements = (*outer_elements)->package.elements; |
obj_desc = elements[sort_index]; |
if (obj_desc->common.type != ACPI_TYPE_INTEGER) { |
return (AE_AML_OPERAND_TYPE); |
} |
/* |
* The list must be sorted in the specified order. If we detect a |
* discrepancy, sort the entire list. |
*/ |
if (((sort_direction == ACPI_SORT_ASCENDING) && |
(obj_desc->integer.value < previous_value)) || |
((sort_direction == ACPI_SORT_DESCENDING) && |
(obj_desc->integer.value > previous_value))) { |
acpi_ns_sort_list(&return_object->package. |
elements[start_index], |
outer_element_count, sort_index, |
sort_direction); |
info->return_flags |= ACPI_OBJECT_REPAIRED; |
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
"%s: Repaired unsorted list - now sorted by %s\n", |
info->full_pathname, sort_key_name)); |
return (AE_OK); |
} |
previous_value = (u32) obj_desc->integer.value; |
outer_elements++; |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_sort_list |
* |
* PARAMETERS: elements - Package object element list |
* count - Element count for above |
* index - Sort by which package element |
* sort_direction - Ascending or Descending sort |
* |
* RETURN: None |
* |
* DESCRIPTION: Sort the objects that are in a package element list. |
* |
* NOTE: Assumes that all NULL elements have been removed from the package, |
* and that all elements have been verified to be of type Integer. |
* |
*****************************************************************************/ |
static void |
acpi_ns_sort_list(union acpi_operand_object **elements, |
u32 count, u32 index, u8 sort_direction) |
{ |
union acpi_operand_object *obj_desc1; |
union acpi_operand_object *obj_desc2; |
union acpi_operand_object *temp_obj; |
u32 i; |
u32 j; |
/* Simple bubble sort */ |
for (i = 1; i < count; i++) { |
for (j = (count - 1); j >= i; j--) { |
obj_desc1 = elements[j - 1]->package.elements[index]; |
obj_desc2 = elements[j]->package.elements[index]; |
if (((sort_direction == ACPI_SORT_ASCENDING) && |
(obj_desc1->integer.value > |
obj_desc2->integer.value)) |
|| ((sort_direction == ACPI_SORT_DESCENDING) |
&& (obj_desc1->integer.value < |
obj_desc2->integer.value))) { |
temp_obj = elements[j - 1]; |
elements[j - 1] = elements[j]; |
elements[j] = temp_obj; |
} |
} |
} |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_remove_element |
* |
* PARAMETERS: obj_desc - Package object element list |
* index - Index of element to remove |
* |
* RETURN: None |
* |
* DESCRIPTION: Remove the requested element of a package and delete it. |
* |
*****************************************************************************/ |
static void |
acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index) |
{ |
union acpi_operand_object **source; |
union acpi_operand_object **dest; |
u32 count; |
u32 new_count; |
u32 i; |
ACPI_FUNCTION_NAME(ns_remove_element); |
count = obj_desc->package.count; |
new_count = count - 1; |
source = obj_desc->package.elements; |
dest = source; |
/* Examine all elements of the package object, remove matched index */ |
for (i = 0; i < count; i++) { |
if (i == index) { |
acpi_ut_remove_reference(*source); /* Remove one ref for being in pkg */ |
acpi_ut_remove_reference(*source); |
} else { |
*dest = *source; |
dest++; |
} |
source++; |
} |
/* NULL terminate list and update the package count */ |
*dest = NULL; |
obj_desc->package.count = new_count; |
} |
/drivers/acpi/acpica/nssearch.c |
---|
0,0 → 1,432 |
/******************************************************************************* |
* |
* Module Name: nssearch - Namespace search |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#ifdef ACPI_ASL_COMPILER |
#include "amlcode.h" |
#endif |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nssearch") |
/* Local prototypes */ |
static acpi_status |
acpi_ns_search_parent_tree(u32 target_name, |
struct acpi_namespace_node *node, |
acpi_object_type type, |
struct acpi_namespace_node **return_node); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_search_one_scope |
* |
* PARAMETERS: target_name - Ascii ACPI name to search for |
* parent_node - Starting node where search will begin |
* type - Object type to match |
* return_node - Where the matched Named obj is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Search a single level of the namespace. Performs a |
* simple search of the specified level, and does not add |
* entries or search parents. |
* |
* |
* Named object lists are built (and subsequently dumped) in the |
* order in which the names are encountered during the namespace load; |
* |
* All namespace searching is linear in this implementation, but |
* could be easily modified to support any improved search |
* algorithm. However, the linear search was chosen for simplicity |
* and because the trees are small and the other interpreter |
* execution overhead is relatively high. |
* |
* Note: CPU execution analysis has shown that the AML interpreter spends |
* a very small percentage of its time searching the namespace. Therefore, |
* the linear search seems to be sufficient, as there would seem to be |
* little value in improving the search. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_search_one_scope(u32 target_name, |
struct acpi_namespace_node *parent_node, |
acpi_object_type type, |
struct acpi_namespace_node **return_node) |
{ |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(ns_search_one_scope); |
#ifdef ACPI_DEBUG_OUTPUT |
if (ACPI_LV_NAMES & acpi_dbg_level) { |
char *scope_name; |
scope_name = acpi_ns_get_external_pathname(parent_node); |
if (scope_name) { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Searching %s (%p) For [%4.4s] (%s)\n", |
scope_name, parent_node, |
ACPI_CAST_PTR(char, &target_name), |
acpi_ut_get_type_name(type))); |
ACPI_FREE(scope_name); |
} |
} |
#endif |
/* |
* Search for name at this namespace level, which is to say that we |
* must search for the name among the children of this object |
*/ |
node = parent_node->child; |
while (node) { |
/* Check for match against the name */ |
if (node->name.integer == target_name) { |
/* Resolve a control method alias if any */ |
if (acpi_ns_get_type(node) == |
ACPI_TYPE_LOCAL_METHOD_ALIAS) { |
node = |
ACPI_CAST_PTR(struct acpi_namespace_node, |
node->object); |
} |
/* Found matching entry */ |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n", |
ACPI_CAST_PTR(char, &target_name), |
acpi_ut_get_type_name(node->type), |
node, |
acpi_ut_get_node_name(parent_node), |
parent_node)); |
*return_node = node; |
return_ACPI_STATUS(AE_OK); |
} |
/* Didn't match name, move on to the next peer object */ |
node = node->peer; |
} |
/* Searched entire namespace level, not found */ |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Name [%4.4s] (%s) not found in search in scope [%4.4s] " |
"%p first child %p\n", |
ACPI_CAST_PTR(char, &target_name), |
acpi_ut_get_type_name(type), |
acpi_ut_get_node_name(parent_node), parent_node, |
parent_node->child)); |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_search_parent_tree |
* |
* PARAMETERS: target_name - Ascii ACPI name to search for |
* node - Starting node where search will begin |
* type - Object type to match |
* return_node - Where the matched Node is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Called when a name has not been found in the current namespace |
* level. Before adding it or giving up, ACPI scope rules require |
* searching enclosing scopes in cases identified by acpi_ns_local(). |
* |
* "A name is located by finding the matching name in the current |
* name space, and then in the parent name space. If the parent |
* name space does not contain the name, the search continues |
* recursively until either the name is found or the name space |
* does not have a parent (the root of the name space). This |
* indicates that the name is not found" (From ACPI Specification, |
* section 5.3) |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_search_parent_tree(u32 target_name, |
struct acpi_namespace_node *node, |
acpi_object_type type, |
struct acpi_namespace_node **return_node) |
{ |
acpi_status status; |
struct acpi_namespace_node *parent_node; |
ACPI_FUNCTION_TRACE(ns_search_parent_tree); |
parent_node = node->parent; |
/* |
* If there is no parent (i.e., we are at the root) or type is "local", |
* we won't be searching the parent tree. |
*/ |
if (!parent_node) { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "[%4.4s] has no parent\n", |
ACPI_CAST_PTR(char, &target_name))); |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
if (acpi_ns_local(type)) { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"[%4.4s] type [%s] must be local to this scope (no parent search)\n", |
ACPI_CAST_PTR(char, &target_name), |
acpi_ut_get_type_name(type))); |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
/* Search the parent tree */ |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Searching parent [%4.4s] for [%4.4s]\n", |
acpi_ut_get_node_name(parent_node), |
ACPI_CAST_PTR(char, &target_name))); |
/* Search parents until target is found or we have backed up to the root */ |
while (parent_node) { |
/* |
* Search parent scope. Use TYPE_ANY because we don't care about the |
* object type at this point, we only care about the existence of |
* the actual name we are searching for. Typechecking comes later. |
*/ |
status = |
acpi_ns_search_one_scope(target_name, parent_node, |
ACPI_TYPE_ANY, return_node); |
if (ACPI_SUCCESS(status)) { |
return_ACPI_STATUS(status); |
} |
/* Not found here, go up another level (until we reach the root) */ |
parent_node = parent_node->parent; |
} |
/* Not found in parent tree */ |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_search_and_enter |
* |
* PARAMETERS: target_name - Ascii ACPI name to search for (4 chars) |
* walk_state - Current state of the walk |
* node - Starting node where search will begin |
* interpreter_mode - Add names only in ACPI_MODE_LOAD_PASS_x. |
* Otherwise,search only. |
* type - Object type to match |
* flags - Flags describing the search restrictions |
* return_node - Where the Node is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Search for a name segment in a single namespace level, |
* optionally adding it if it is not found. If the passed |
* Type is not Any and the type previously stored in the |
* entry was Any (i.e. unknown), update the stored type. |
* |
* In ACPI_IMODE_EXECUTE, search only. |
* In other modes, search and add if not found. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_search_and_enter(u32 target_name, |
struct acpi_walk_state *walk_state, |
struct acpi_namespace_node *node, |
acpi_interpreter_mode interpreter_mode, |
acpi_object_type type, |
u32 flags, struct acpi_namespace_node **return_node) |
{ |
acpi_status status; |
struct acpi_namespace_node *new_node; |
ACPI_FUNCTION_TRACE(ns_search_and_enter); |
/* Parameter validation */ |
if (!node || !target_name || !return_node) { |
ACPI_ERROR((AE_INFO, |
"Null parameter: Node %p Name 0x%X ReturnNode %p", |
node, target_name, return_node)); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* Name must consist of valid ACPI characters. We will repair the name if |
* necessary because we don't want to abort because of this, but we want |
* all namespace names to be printable. A warning message is appropriate. |
* |
* This issue came up because there are in fact machines that exhibit |
* this problem, and we want to be able to enable ACPI support for them, |
* even though there are a few bad names. |
*/ |
acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name)); |
/* Try to find the name in the namespace level specified by the caller */ |
*return_node = ACPI_ENTRY_NOT_FOUND; |
status = acpi_ns_search_one_scope(target_name, node, type, return_node); |
if (status != AE_NOT_FOUND) { |
/* |
* If we found it AND the request specifies that a find is an error, |
* return the error |
*/ |
if (status == AE_OK) { |
/* The node was found in the namespace */ |
/* |
* If the namespace override feature is enabled for this node, |
* delete any existing attached sub-object and make the node |
* look like a new node that is owned by the override table. |
*/ |
if (flags & ACPI_NS_OVERRIDE_IF_FOUND) { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"Namespace override: %4.4s pass %u type %X Owner %X\n", |
ACPI_CAST_PTR(char, |
&target_name), |
interpreter_mode, |
(*return_node)->type, |
walk_state->owner_id)); |
acpi_ns_delete_children(*return_node); |
if (acpi_gbl_runtime_namespace_override) { |
acpi_ut_remove_reference((*return_node)->object); |
(*return_node)->object = NULL; |
(*return_node)->owner_id = |
walk_state->owner_id; |
} else { |
acpi_ns_remove_node(*return_node); |
*return_node = ACPI_ENTRY_NOT_FOUND; |
} |
} |
/* Return an error if we don't expect to find the object */ |
else if (flags & ACPI_NS_ERROR_IF_FOUND) { |
status = AE_ALREADY_EXISTS; |
} |
} |
#ifdef ACPI_ASL_COMPILER |
if (*return_node && (*return_node)->type == ACPI_TYPE_ANY) { |
(*return_node)->flags |= ANOBJ_IS_EXTERNAL; |
} |
#endif |
/* Either found it or there was an error: finished either way */ |
return_ACPI_STATUS(status); |
} |
/* |
* The name was not found. If we are NOT performing the first pass |
* (name entry) of loading the namespace, search the parent tree (all the |
* way to the root if necessary.) We don't want to perform the parent |
* search when the namespace is actually being loaded. We want to perform |
* the search when namespace references are being resolved (load pass 2) |
* and during the execution phase. |
*/ |
if ((interpreter_mode != ACPI_IMODE_LOAD_PASS1) && |
(flags & ACPI_NS_SEARCH_PARENT)) { |
/* |
* Not found at this level - search parent tree according to the |
* ACPI specification |
*/ |
status = |
acpi_ns_search_parent_tree(target_name, node, type, |
return_node); |
if (ACPI_SUCCESS(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* In execute mode, just search, never add names. Exit now */ |
if (interpreter_mode == ACPI_IMODE_EXECUTE) { |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"%4.4s Not found in %p [Not adding]\n", |
ACPI_CAST_PTR(char, &target_name), node)); |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
/* Create the new named object */ |
new_node = acpi_ns_create_node(target_name); |
if (!new_node) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
#ifdef ACPI_ASL_COMPILER |
/* Node is an object defined by an External() statement */ |
if (flags & ACPI_NS_EXTERNAL || |
(walk_state && walk_state->opcode == AML_SCOPE_OP)) { |
new_node->flags |= ANOBJ_IS_EXTERNAL; |
} |
#endif |
if (flags & ACPI_NS_TEMPORARY) { |
new_node->flags |= ANOBJ_TEMPORARY; |
} |
/* Install the new object into the parent's list of children */ |
acpi_ns_install_node(walk_state, node, new_node, type); |
*return_node = new_node; |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/nsutils.c |
---|
0,0 → 1,746 |
/****************************************************************************** |
* |
* Module Name: nsutils - Utilities for accessing ACPI namespace, accessing |
* parents and siblings and Scope manipulation |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsutils") |
/* Local prototypes */ |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search); |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_print_node_pathname |
* |
* PARAMETERS: node - Object |
* message - Prefix message |
* |
* DESCRIPTION: Print an object's full namespace pathname |
* Manages allocation/freeing of a pathname buffer |
* |
******************************************************************************/ |
void |
acpi_ns_print_node_pathname(struct acpi_namespace_node *node, |
const char *message) |
{ |
struct acpi_buffer buffer; |
acpi_status status; |
if (!node) { |
acpi_os_printf("[NULL NAME]"); |
return; |
} |
/* Convert handle to full pathname and print it (with supplied message) */ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_ns_handle_to_pathname(node, &buffer, TRUE); |
if (ACPI_SUCCESS(status)) { |
if (message) { |
acpi_os_printf("%s ", message); |
} |
acpi_os_printf("[%s] (Node %p)", (char *)buffer.pointer, node); |
ACPI_FREE(buffer.pointer); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_type |
* |
* PARAMETERS: node - Parent Node to be examined |
* |
* RETURN: Type field from Node whose handle is passed |
* |
* DESCRIPTION: Return the type of a Namespace node |
* |
******************************************************************************/ |
acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node) |
{ |
ACPI_FUNCTION_TRACE(ns_get_type); |
if (!node) { |
ACPI_WARNING((AE_INFO, "Null Node parameter")); |
return_UINT8(ACPI_TYPE_ANY); |
} |
return_UINT8(node->type); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_local |
* |
* PARAMETERS: type - A namespace object type |
* |
* RETURN: LOCAL if names must be found locally in objects of the |
* passed type, 0 if enclosing scopes should be searched |
* |
* DESCRIPTION: Returns scope rule for the given object type. |
* |
******************************************************************************/ |
u32 acpi_ns_local(acpi_object_type type) |
{ |
ACPI_FUNCTION_TRACE(ns_local); |
if (!acpi_ut_valid_object_type(type)) { |
/* Type code out of range */ |
ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type)); |
return_UINT32(ACPI_NS_NORMAL); |
} |
return_UINT32(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_internal_name_length |
* |
* PARAMETERS: info - Info struct initialized with the |
* external name pointer. |
* |
* RETURN: None |
* |
* DESCRIPTION: Calculate the length of the internal (AML) namestring |
* corresponding to the external (ASL) namestring. |
* |
******************************************************************************/ |
void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info) |
{ |
const char *next_external_char; |
u32 i; |
ACPI_FUNCTION_ENTRY(); |
next_external_char = info->external_name; |
info->num_carats = 0; |
info->num_segments = 0; |
info->fully_qualified = FALSE; |
/* |
* For the internal name, the required length is 4 bytes per segment, plus |
* 1 each for root_prefix, multi_name_prefix_op, segment count, trailing null |
* (which is not really needed, but no there's harm in putting it there) |
* |
* strlen() + 1 covers the first name_seg, which has no path separator |
*/ |
if (ACPI_IS_ROOT_PREFIX(*next_external_char)) { |
info->fully_qualified = TRUE; |
next_external_char++; |
/* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */ |
while (ACPI_IS_ROOT_PREFIX(*next_external_char)) { |
next_external_char++; |
} |
} else { |
/* Handle Carat prefixes */ |
while (ACPI_IS_PARENT_PREFIX(*next_external_char)) { |
info->num_carats++; |
next_external_char++; |
} |
} |
/* |
* Determine the number of ACPI name "segments" by counting the number of |
* path separators within the string. Start with one segment since the |
* segment count is [(# separators) + 1], and zero separators is ok. |
*/ |
if (*next_external_char) { |
info->num_segments = 1; |
for (i = 0; next_external_char[i]; i++) { |
if (ACPI_IS_PATH_SEPARATOR(next_external_char[i])) { |
info->num_segments++; |
} |
} |
} |
info->length = (ACPI_NAME_SIZE * info->num_segments) + |
4 + info->num_carats; |
info->next_external_char = next_external_char; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_build_internal_name |
* |
* PARAMETERS: info - Info struct fully initialized |
* |
* RETURN: Status |
* |
* DESCRIPTION: Construct the internal (AML) namestring |
* corresponding to the external (ASL) namestring. |
* |
******************************************************************************/ |
acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) |
{ |
u32 num_segments = info->num_segments; |
char *internal_name = info->internal_name; |
const char *external_name = info->next_external_char; |
char *result = NULL; |
u32 i; |
ACPI_FUNCTION_TRACE(ns_build_internal_name); |
/* Setup the correct prefixes, counts, and pointers */ |
if (info->fully_qualified) { |
internal_name[0] = AML_ROOT_PREFIX; |
if (num_segments <= 1) { |
result = &internal_name[1]; |
} else if (num_segments == 2) { |
internal_name[1] = AML_DUAL_NAME_PREFIX; |
result = &internal_name[2]; |
} else { |
internal_name[1] = AML_MULTI_NAME_PREFIX_OP; |
internal_name[2] = (char)num_segments; |
result = &internal_name[3]; |
} |
} else { |
/* |
* Not fully qualified. |
* Handle Carats first, then append the name segments |
*/ |
i = 0; |
if (info->num_carats) { |
for (i = 0; i < info->num_carats; i++) { |
internal_name[i] = AML_PARENT_PREFIX; |
} |
} |
if (num_segments <= 1) { |
result = &internal_name[i]; |
} else if (num_segments == 2) { |
internal_name[i] = AML_DUAL_NAME_PREFIX; |
result = &internal_name[(acpi_size) i + 1]; |
} else { |
internal_name[i] = AML_MULTI_NAME_PREFIX_OP; |
internal_name[(acpi_size) i + 1] = (char)num_segments; |
result = &internal_name[(acpi_size) i + 2]; |
} |
} |
/* Build the name (minus path separators) */ |
for (; num_segments; num_segments--) { |
for (i = 0; i < ACPI_NAME_SIZE; i++) { |
if (ACPI_IS_PATH_SEPARATOR(*external_name) || |
(*external_name == 0)) { |
/* Pad the segment with underscore(s) if segment is short */ |
result[i] = '_'; |
} else { |
/* Convert the character to uppercase and save it */ |
result[i] = (char)toupper((int)*external_name); |
external_name++; |
} |
} |
/* Now we must have a path separator, or the pathname is bad */ |
if (!ACPI_IS_PATH_SEPARATOR(*external_name) && |
(*external_name != 0)) { |
return_ACPI_STATUS(AE_BAD_PATHNAME); |
} |
/* Move on the next segment */ |
external_name++; |
result += ACPI_NAME_SIZE; |
} |
/* Terminate the string */ |
*result = 0; |
if (info->fully_qualified) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Returning [%p] (abs) \"\\%s\"\n", |
internal_name, internal_name)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n", |
internal_name, internal_name)); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_internalize_name |
* |
* PARAMETERS: *external_name - External representation of name |
* **Converted name - Where to return the resulting |
* internal represention of the name |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0") |
* to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) |
* |
*******************************************************************************/ |
acpi_status |
acpi_ns_internalize_name(const char *external_name, char **converted_name) |
{ |
char *internal_name; |
struct acpi_namestring_info info; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_internalize_name); |
if ((!external_name) || (*external_name == 0) || (!converted_name)) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Get the length of the new internal name */ |
info.external_name = external_name; |
acpi_ns_get_internal_name_length(&info); |
/* We need a segment to store the internal name */ |
internal_name = ACPI_ALLOCATE_ZEROED(info.length); |
if (!internal_name) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Build the name */ |
info.internal_name = internal_name; |
status = acpi_ns_build_internal_name(&info); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(internal_name); |
return_ACPI_STATUS(status); |
} |
*converted_name = internal_name; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_externalize_name |
* |
* PARAMETERS: internal_name_length - Lenth of the internal name below |
* internal_name - Internal representation of name |
* converted_name_length - Where the length is returned |
* converted_name - Where the resulting external name |
* is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) |
* to its external (printable) form (e.g. "\_PR_.CPU0") |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_externalize_name(u32 internal_name_length, |
const char *internal_name, |
u32 * converted_name_length, char **converted_name) |
{ |
u32 names_index = 0; |
u32 num_segments = 0; |
u32 required_length; |
u32 prefix_length = 0; |
u32 i = 0; |
u32 j = 0; |
ACPI_FUNCTION_TRACE(ns_externalize_name); |
if (!internal_name_length || !internal_name || !converted_name) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Check for a prefix (one '\' | one or more '^') */ |
switch (internal_name[0]) { |
case AML_ROOT_PREFIX: |
prefix_length = 1; |
break; |
case AML_PARENT_PREFIX: |
for (i = 0; i < internal_name_length; i++) { |
if (ACPI_IS_PARENT_PREFIX(internal_name[i])) { |
prefix_length = i + 1; |
} else { |
break; |
} |
} |
if (i == internal_name_length) { |
prefix_length = i; |
} |
break; |
default: |
break; |
} |
/* |
* Check for object names. Note that there could be 0-255 of these |
* 4-byte elements. |
*/ |
if (prefix_length < internal_name_length) { |
switch (internal_name[prefix_length]) { |
case AML_MULTI_NAME_PREFIX_OP: |
/* <count> 4-byte names */ |
names_index = prefix_length + 2; |
num_segments = (u8) |
internal_name[(acpi_size) prefix_length + 1]; |
break; |
case AML_DUAL_NAME_PREFIX: |
/* Two 4-byte names */ |
names_index = prefix_length + 1; |
num_segments = 2; |
break; |
case 0: |
/* null_name */ |
names_index = 0; |
num_segments = 0; |
break; |
default: |
/* one 4-byte name */ |
names_index = prefix_length; |
num_segments = 1; |
break; |
} |
} |
/* |
* Calculate the length of converted_name, which equals the length |
* of the prefix, length of all object names, length of any required |
* punctuation ('.') between object names, plus the NULL terminator. |
*/ |
required_length = prefix_length + (4 * num_segments) + |
((num_segments > 0) ? (num_segments - 1) : 0) + 1; |
/* |
* Check to see if we're still in bounds. If not, there's a problem |
* with internal_name (invalid format). |
*/ |
if (required_length > internal_name_length) { |
ACPI_ERROR((AE_INFO, "Invalid internal name")); |
return_ACPI_STATUS(AE_BAD_PATHNAME); |
} |
/* Build the converted_name */ |
*converted_name = ACPI_ALLOCATE_ZEROED(required_length); |
if (!(*converted_name)) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
j = 0; |
for (i = 0; i < prefix_length; i++) { |
(*converted_name)[j++] = internal_name[i]; |
} |
if (num_segments > 0) { |
for (i = 0; i < num_segments; i++) { |
if (i > 0) { |
(*converted_name)[j++] = '.'; |
} |
/* Copy and validate the 4-char name segment */ |
ACPI_MOVE_NAME(&(*converted_name)[j], |
&internal_name[names_index]); |
acpi_ut_repair_name(&(*converted_name)[j]); |
j += ACPI_NAME_SIZE; |
names_index += ACPI_NAME_SIZE; |
} |
} |
if (converted_name_length) { |
*converted_name_length = (u32) required_length; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_validate_handle |
* |
* PARAMETERS: handle - Handle to be validated and typecast to a |
* namespace node. |
* |
* RETURN: A pointer to a namespace node |
* |
* DESCRIPTION: Convert a namespace handle to a namespace node. Handles special |
* cases for the root node. |
* |
* NOTE: Real integer handles would allow for more verification |
* and keep all pointers within this subsystem - however this introduces |
* more overhead and has not been necessary to this point. Drivers |
* holding handles are typically notified before a node becomes invalid |
* due to a table unload. |
* |
******************************************************************************/ |
struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Parameter validation */ |
if ((!handle) || (handle == ACPI_ROOT_OBJECT)) { |
return (acpi_gbl_root_node); |
} |
/* We can at least attempt to verify the handle */ |
if (ACPI_GET_DESCRIPTOR_TYPE(handle) != ACPI_DESC_TYPE_NAMED) { |
return (NULL); |
} |
return (ACPI_CAST_PTR(struct acpi_namespace_node, handle)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_terminate |
* |
* PARAMETERS: none |
* |
* RETURN: none |
* |
* DESCRIPTION: free memory allocated for namespace and ACPI table storage. |
* |
******************************************************************************/ |
void acpi_ns_terminate(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ns_terminate); |
#ifdef ACPI_EXEC_APP |
{ |
union acpi_operand_object *prev; |
union acpi_operand_object *next; |
/* Delete any module-level code blocks */ |
next = acpi_gbl_module_code_list; |
while (next) { |
prev = next; |
next = next->method.mutex; |
prev->method.mutex = NULL; /* Clear the Mutex (cheated) field */ |
acpi_ut_remove_reference(prev); |
} |
} |
#endif |
/* |
* Free the entire namespace -- all nodes and all objects |
* attached to the nodes |
*/ |
acpi_ns_delete_namespace_subtree(acpi_gbl_root_node); |
/* Delete any objects attached to the root node */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_VOID; |
} |
acpi_ns_delete_node(acpi_gbl_root_node); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n")); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_opens_scope |
* |
* PARAMETERS: type - A valid namespace type |
* |
* RETURN: NEWSCOPE if the passed type "opens a name scope" according |
* to the ACPI specification, else 0 |
* |
******************************************************************************/ |
u32 acpi_ns_opens_scope(acpi_object_type type) |
{ |
ACPI_FUNCTION_ENTRY(); |
if (type > ACPI_TYPE_LOCAL_MAX) { |
/* type code out of range */ |
ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type)); |
return (ACPI_NS_NORMAL); |
} |
return (((u32)acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_node |
* |
* PARAMETERS: *pathname - Name to be found, in external (ASL) format. The |
* \ (backslash) and ^ (carat) prefixes, and the |
* . (period) to separate segments are supported. |
* prefix_node - Root of subtree to be searched, or NS_ALL for the |
* root of the name space. If Name is fully |
* qualified (first s8 is '\'), the passed value |
* of Scope will not be accessed. |
* flags - Used to indicate whether to perform upsearch or |
* not. |
* return_node - Where the Node is returned |
* |
* DESCRIPTION: Look up a name relative to a given scope and return the |
* corresponding Node. NOTE: Scope can be null. |
* |
* MUTEX: Locks namespace |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_get_node(struct acpi_namespace_node *prefix_node, |
const char *pathname, |
u32 flags, struct acpi_namespace_node **return_node) |
{ |
union acpi_generic_state scope_info; |
acpi_status status; |
char *internal_path; |
ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname)); |
/* Simplest case is a null pathname */ |
if (!pathname) { |
*return_node = prefix_node; |
if (!prefix_node) { |
*return_node = acpi_gbl_root_node; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/* Quick check for a reference to the root */ |
if (ACPI_IS_ROOT_PREFIX(pathname[0]) && (!pathname[1])) { |
*return_node = acpi_gbl_root_node; |
return_ACPI_STATUS(AE_OK); |
} |
/* Convert path to internal representation */ |
status = acpi_ns_internalize_name(pathname, &internal_path); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Must lock namespace during lookup */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Setup lookup scope (search starting point) */ |
scope_info.scope.node = prefix_node; |
/* Lookup the name in the namespace */ |
status = acpi_ns_lookup(&scope_info, internal_path, ACPI_TYPE_ANY, |
ACPI_IMODE_EXECUTE, |
(flags | ACPI_NS_DONT_OPEN_SCOPE), NULL, |
return_node); |
if (ACPI_FAILURE(status)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s, %s\n", |
pathname, acpi_format_exception(status))); |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
cleanup: |
ACPI_FREE(internal_path); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/nswalk.c |
---|
0,0 → 1,358 |
/****************************************************************************** |
* |
* Module Name: nswalk - Functions for walking the ACPI namespace |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nswalk") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_next_node |
* |
* PARAMETERS: parent_node - Parent node whose children we are |
* getting |
* child_node - Previous child that was found. |
* The NEXT child will be returned |
* |
* RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if |
* none is found. |
* |
* DESCRIPTION: Return the next peer node within the namespace. If Handle |
* is valid, Scope is ignored. Otherwise, the first node |
* within Scope is returned. |
* |
******************************************************************************/ |
struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node |
*parent_node, |
struct acpi_namespace_node |
*child_node) |
{ |
ACPI_FUNCTION_ENTRY(); |
if (!child_node) { |
/* It's really the parent's _scope_ that we want */ |
return (parent_node->child); |
} |
/* Otherwise just return the next peer */ |
return (child_node->peer); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_next_node_typed |
* |
* PARAMETERS: type - Type of node to be searched for |
* parent_node - Parent node whose children we are |
* getting |
* child_node - Previous child that was found. |
* The NEXT child will be returned |
* |
* RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if |
* none is found. |
* |
* DESCRIPTION: Return the next peer node within the namespace. If Handle |
* is valid, Scope is ignored. Otherwise, the first node |
* within Scope is returned. |
* |
******************************************************************************/ |
struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, |
struct |
acpi_namespace_node |
*parent_node, |
struct |
acpi_namespace_node |
*child_node) |
{ |
struct acpi_namespace_node *next_node = NULL; |
ACPI_FUNCTION_ENTRY(); |
next_node = acpi_ns_get_next_node(parent_node, child_node); |
/* If any type is OK, we are done */ |
if (type == ACPI_TYPE_ANY) { |
/* next_node is NULL if we are at the end-of-list */ |
return (next_node); |
} |
/* Must search for the node -- but within this scope only */ |
while (next_node) { |
/* If type matches, we are done */ |
if (next_node->type == type) { |
return (next_node); |
} |
/* Otherwise, move on to the next peer node */ |
next_node = next_node->peer; |
} |
/* Not found */ |
return (NULL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_walk_namespace |
* |
* PARAMETERS: type - acpi_object_type to search for |
* start_node - Handle in namespace where search begins |
* max_depth - Depth to which search is to reach |
* flags - Whether to unlock the NS before invoking |
* the callback routine |
* descending_callback - Called during tree descent |
* when an object of "Type" is found |
* ascending_callback - Called during tree ascent |
* when an object of "Type" is found |
* context - Passed to user function(s) above |
* return_value - from the user_function if terminated |
* early. Otherwise, returns NULL. |
* RETURNS: Status |
* |
* DESCRIPTION: Performs a modified depth-first walk of the namespace tree, |
* starting (and ending) at the node specified by start_handle. |
* The callback function is called whenever a node that matches |
* the type parameter is found. If the callback function returns |
* a non-zero value, the search is terminated immediately and |
* this value is returned to the caller. |
* |
* The point of this procedure is to provide a generic namespace |
* walk routine that can be called from multiple places to |
* provide multiple services; the callback function(s) can be |
* tailored to each task, whether it is a print function, |
* a compare function, etc. |
* |
******************************************************************************/ |
acpi_status |
acpi_ns_walk_namespace(acpi_object_type type, |
acpi_handle start_node, |
u32 max_depth, |
u32 flags, |
acpi_walk_callback descending_callback, |
acpi_walk_callback ascending_callback, |
void *context, void **return_value) |
{ |
acpi_status status; |
acpi_status mutex_status; |
struct acpi_namespace_node *child_node; |
struct acpi_namespace_node *parent_node; |
acpi_object_type child_type; |
u32 level; |
u8 node_previously_visited = FALSE; |
ACPI_FUNCTION_TRACE(ns_walk_namespace); |
/* Special case for the namespace Root Node */ |
if (start_node == ACPI_ROOT_OBJECT) { |
start_node = acpi_gbl_root_node; |
} |
/* Null child means "get first node" */ |
parent_node = start_node; |
child_node = acpi_ns_get_next_node(parent_node, NULL); |
child_type = ACPI_TYPE_ANY; |
level = 1; |
/* |
* Traverse the tree of nodes until we bubble back up to where we |
* started. When Level is zero, the loop is done because we have |
* bubbled up to (and passed) the original parent handle (start_entry) |
*/ |
while (level > 0 && child_node) { |
status = AE_OK; |
/* Found next child, get the type if we are not searching for ANY */ |
if (type != ACPI_TYPE_ANY) { |
child_type = child_node->type; |
} |
/* |
* Ignore all temporary namespace nodes (created during control |
* method execution) unless told otherwise. These temporary nodes |
* can cause a race condition because they can be deleted during |
* the execution of the user function (if the namespace is |
* unlocked before invocation of the user function.) Only the |
* debugger namespace dump will examine the temporary nodes. |
*/ |
if ((child_node->flags & ANOBJ_TEMPORARY) && |
!(flags & ACPI_NS_WALK_TEMP_NODES)) { |
status = AE_CTRL_DEPTH; |
} |
/* Type must match requested type */ |
else if (child_type == type) { |
/* |
* Found a matching node, invoke the user callback function. |
* Unlock the namespace if flag is set. |
*/ |
if (flags & ACPI_NS_WALK_UNLOCK) { |
mutex_status = |
acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(mutex_status)) { |
return_ACPI_STATUS(mutex_status); |
} |
} |
/* |
* Invoke the user function, either descending, ascending, |
* or both. |
*/ |
if (!node_previously_visited) { |
if (descending_callback) { |
status = |
descending_callback(child_node, |
level, context, |
return_value); |
} |
} else { |
if (ascending_callback) { |
status = |
ascending_callback(child_node, |
level, context, |
return_value); |
} |
} |
if (flags & ACPI_NS_WALK_UNLOCK) { |
mutex_status = |
acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(mutex_status)) { |
return_ACPI_STATUS(mutex_status); |
} |
} |
switch (status) { |
case AE_OK: |
case AE_CTRL_DEPTH: |
/* Just keep going */ |
break; |
case AE_CTRL_TERMINATE: |
/* Exit now, with OK status */ |
return_ACPI_STATUS(AE_OK); |
default: |
/* All others are valid exceptions */ |
return_ACPI_STATUS(status); |
} |
} |
/* |
* Depth first search: Attempt to go down another level in the |
* namespace if we are allowed to. Don't go any further if we have |
* reached the caller specified maximum depth or if the user |
* function has specified that the maximum depth has been reached. |
*/ |
if (!node_previously_visited && |
(level < max_depth) && (status != AE_CTRL_DEPTH)) { |
if (child_node->child) { |
/* There is at least one child of this node, visit it */ |
level++; |
parent_node = child_node; |
child_node = |
acpi_ns_get_next_node(parent_node, NULL); |
continue; |
} |
} |
/* No more children, re-visit this node */ |
if (!node_previously_visited) { |
node_previously_visited = TRUE; |
continue; |
} |
/* No more children, visit peers */ |
child_node = acpi_ns_get_next_node(parent_node, child_node); |
if (child_node) { |
node_previously_visited = FALSE; |
} |
/* No peers, re-visit parent */ |
else { |
/* |
* No more children of this node (acpi_ns_get_next_node failed), go |
* back upwards in the namespace tree to the node's parent. |
*/ |
level--; |
child_node = parent_node; |
parent_node = parent_node->parent; |
node_previously_visited = TRUE; |
} |
} |
/* Complete walk, not terminated by user function */ |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/nsxfeval.c |
---|
0,0 → 1,995 |
/******************************************************************************* |
* |
* Module Name: nsxfeval - Public interfaces to the ACPI subsystem |
* ACPI Object evaluation interfaces |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsxfeval") |
/* Local prototypes */ |
static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); |
/******************************************************************************* |
* |
* FUNCTION: acpi_evaluate_object_typed |
* |
* PARAMETERS: handle - Object handle (optional) |
* pathname - Object pathname (optional) |
* external_params - List of parameters to pass to method, |
* terminated by NULL. May be NULL |
* if no parameters are being passed. |
* return_buffer - Where to put method's return value (if |
* any). If NULL, no value is returned. |
* return_type - Expected type of return object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Find and evaluate the given object, passing the given |
* parameters if necessary. One of "Handle" or "Pathname" must |
* be valid (non-null) |
* |
******************************************************************************/ |
acpi_status |
acpi_evaluate_object_typed(acpi_handle handle, |
acpi_string pathname, |
struct acpi_object_list *external_params, |
struct acpi_buffer *return_buffer, |
acpi_object_type return_type) |
{ |
acpi_status status; |
u8 free_buffer_on_error = FALSE; |
ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed); |
/* Return buffer must be valid */ |
if (!return_buffer) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (return_buffer->length == ACPI_ALLOCATE_BUFFER) { |
free_buffer_on_error = TRUE; |
} |
/* Evaluate the object */ |
status = acpi_evaluate_object(handle, pathname, |
external_params, return_buffer); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Type ANY means "don't care" */ |
if (return_type == ACPI_TYPE_ANY) { |
return_ACPI_STATUS(AE_OK); |
} |
if (return_buffer->length == 0) { |
/* Error because caller specifically asked for a return value */ |
ACPI_ERROR((AE_INFO, "No return value")); |
return_ACPI_STATUS(AE_NULL_OBJECT); |
} |
/* Examine the object type returned from evaluate_object */ |
if (((union acpi_object *)return_buffer->pointer)->type == return_type) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Return object type does not match requested type */ |
ACPI_ERROR((AE_INFO, |
"Incorrect return type [%s] requested [%s]", |
acpi_ut_get_type_name(((union acpi_object *)return_buffer-> |
pointer)->type), |
acpi_ut_get_type_name(return_type))); |
if (free_buffer_on_error) { |
/* |
* Free a buffer created via ACPI_ALLOCATE_BUFFER. |
* Note: We use acpi_os_free here because acpi_os_allocate was used |
* to allocate the buffer. This purposefully bypasses the |
* (optionally enabled) allocation tracking mechanism since we |
* only want to track internal allocations. |
*/ |
acpi_os_free(return_buffer->pointer); |
return_buffer->pointer = NULL; |
} |
return_buffer->length = 0; |
return_ACPI_STATUS(AE_TYPE); |
} |
ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) |
/******************************************************************************* |
* |
* FUNCTION: acpi_evaluate_object |
* |
* PARAMETERS: handle - Object handle (optional) |
* pathname - Object pathname (optional) |
* external_params - List of parameters to pass to method, |
* terminated by NULL. May be NULL |
* if no parameters are being passed. |
* return_buffer - Where to put method's return value (if |
* any). If NULL, no value is returned. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Find and evaluate the given object, passing the given |
* parameters if necessary. One of "Handle" or "Pathname" must |
* be valid (non-null) |
* |
******************************************************************************/ |
acpi_status |
acpi_evaluate_object(acpi_handle handle, |
acpi_string pathname, |
struct acpi_object_list *external_params, |
struct acpi_buffer *return_buffer) |
{ |
acpi_status status; |
struct acpi_evaluate_info *info; |
acpi_size buffer_space_needed; |
u32 i; |
ACPI_FUNCTION_TRACE(acpi_evaluate_object); |
/* Allocate and initialize the evaluation information block */ |
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Convert and validate the device handle */ |
info->prefix_node = acpi_ns_validate_handle(handle); |
if (!info->prefix_node) { |
status = AE_BAD_PARAMETER; |
goto cleanup; |
} |
/* |
* Get the actual namespace node for the target object. |
* Handles these cases: |
* |
* 1) Null node, valid pathname from root (absolute path) |
* 2) Node and valid pathname (path relative to Node) |
* 3) Node, Null pathname |
*/ |
if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) { |
/* The path is fully qualified, just evaluate by name */ |
info->prefix_node = NULL; |
} else if (!handle) { |
/* |
* A handle is optional iff a fully qualified pathname is specified. |
* Since we've already handled fully qualified names above, this is |
* an error. |
*/ |
if (!pathname) { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Both Handle and Pathname are NULL")); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Null Handle with relative pathname [%s]", |
pathname)); |
} |
status = AE_BAD_PARAMETER; |
goto cleanup; |
} |
info->relative_pathname = pathname; |
/* |
* Convert all external objects passed as arguments to the |
* internal version(s). |
*/ |
if (external_params && external_params->count) { |
info->param_count = (u16)external_params->count; |
/* Warn on impossible argument count */ |
if (info->param_count > ACPI_METHOD_NUM_ARGS) { |
ACPI_WARN_PREDEFINED((AE_INFO, pathname, |
ACPI_WARN_ALWAYS, |
"Excess arguments (%u) - using only %u", |
info->param_count, |
ACPI_METHOD_NUM_ARGS)); |
info->param_count = ACPI_METHOD_NUM_ARGS; |
} |
/* |
* Allocate a new parameter block for the internal objects |
* Add 1 to count to allow for null terminated internal list |
*/ |
info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) info-> |
param_count + |
1) * sizeof(void *)); |
if (!info->parameters) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Convert each external object in the list to an internal object */ |
for (i = 0; i < info->param_count; i++) { |
status = |
acpi_ut_copy_eobject_to_iobject(&external_params-> |
pointer[i], |
&info-> |
parameters[i]); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
} |
info->parameters[info->param_count] = NULL; |
} |
#if 0 |
/* |
* Begin incoming argument count analysis. Check for too few args |
* and too many args. |
*/ |
switch (acpi_ns_get_type(info->node)) { |
case ACPI_TYPE_METHOD: |
/* Check incoming argument count against the method definition */ |
if (info->obj_desc->method.param_count > info->param_count) { |
ACPI_ERROR((AE_INFO, |
"Insufficient arguments (%u) - %u are required", |
info->param_count, |
info->obj_desc->method.param_count)); |
status = AE_MISSING_ARGUMENTS; |
goto cleanup; |
} |
else if (info->obj_desc->method.param_count < info->param_count) { |
ACPI_WARNING((AE_INFO, |
"Excess arguments (%u) - only %u are required", |
info->param_count, |
info->obj_desc->method.param_count)); |
/* Just pass the required number of arguments */ |
info->param_count = info->obj_desc->method.param_count; |
} |
/* |
* Any incoming external objects to be passed as arguments to the |
* method must be converted to internal objects |
*/ |
if (info->param_count) { |
/* |
* Allocate a new parameter block for the internal objects |
* Add 1 to count to allow for null terminated internal list |
*/ |
info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) |
info-> |
param_count + |
1) * |
sizeof(void *)); |
if (!info->parameters) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Convert each external object in the list to an internal object */ |
for (i = 0; i < info->param_count; i++) { |
status = |
acpi_ut_copy_eobject_to_iobject |
(&external_params->pointer[i], |
&info->parameters[i]); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
} |
info->parameters[info->param_count] = NULL; |
} |
break; |
default: |
/* Warn if arguments passed to an object that is not a method */ |
if (info->param_count) { |
ACPI_WARNING((AE_INFO, |
"%u arguments were passed to a non-method ACPI object", |
info->param_count)); |
} |
break; |
} |
#endif |
/* Now we can evaluate the object */ |
status = acpi_ns_evaluate(info); |
/* |
* If we are expecting a return value, and all went well above, |
* copy the return value to an external object. |
*/ |
if (return_buffer) { |
if (!info->return_object) { |
return_buffer->length = 0; |
} else { |
if (ACPI_GET_DESCRIPTOR_TYPE(info->return_object) == |
ACPI_DESC_TYPE_NAMED) { |
/* |
* If we received a NS Node as a return object, this means that |
* the object we are evaluating has nothing interesting to |
* return (such as a mutex, etc.) We return an error because |
* these types are essentially unsupported by this interface. |
* We don't check up front because this makes it easier to add |
* support for various types at a later date if necessary. |
*/ |
status = AE_TYPE; |
info->return_object = NULL; /* No need to delete a NS Node */ |
return_buffer->length = 0; |
} |
if (ACPI_SUCCESS(status)) { |
/* Dereference Index and ref_of references */ |
acpi_ns_resolve_references(info); |
/* Get the size of the returned object */ |
status = |
acpi_ut_get_object_size(info->return_object, |
&buffer_space_needed); |
if (ACPI_SUCCESS(status)) { |
/* Validate/Allocate/Clear caller buffer */ |
status = |
acpi_ut_initialize_buffer |
(return_buffer, |
buffer_space_needed); |
if (ACPI_FAILURE(status)) { |
/* |
* Caller's buffer is too small or a new one can't |
* be allocated |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Needed buffer size %X, %s\n", |
(u32) |
buffer_space_needed, |
acpi_format_exception |
(status))); |
} else { |
/* We have enough space for the object, build it */ |
status = |
acpi_ut_copy_iobject_to_eobject |
(info->return_object, |
return_buffer); |
} |
} |
} |
} |
} |
if (info->return_object) { |
/* |
* Delete the internal return object. NOTE: Interpreter must be |
* locked to avoid race condition. |
*/ |
acpi_ex_enter_interpreter(); |
/* Remove one reference on the return object (should delete it) */ |
acpi_ut_remove_reference(info->return_object); |
acpi_ex_exit_interpreter(); |
} |
cleanup: |
/* Free the input parameter list (if we created one) */ |
if (info->parameters) { |
/* Free the allocated parameter block */ |
acpi_ut_delete_internal_object_list(info->parameters); |
} |
ACPI_FREE(info); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_evaluate_object) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_resolve_references |
* |
* PARAMETERS: info - Evaluation info block |
* |
* RETURN: Info->return_object is replaced with the dereferenced object |
* |
* DESCRIPTION: Dereference certain reference objects. Called before an |
* internal return object is converted to an external union acpi_object. |
* |
* Performs an automatic dereference of Index and ref_of reference objects. |
* These reference objects are not supported by the union acpi_object, so this is a |
* last resort effort to return something useful. Also, provides compatibility |
* with other ACPI implementations. |
* |
* NOTE: does not handle references within returned package objects or nested |
* references, but this support could be added later if found to be necessary. |
* |
******************************************************************************/ |
static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) |
{ |
union acpi_operand_object *obj_desc = NULL; |
struct acpi_namespace_node *node; |
/* We are interested in reference objects only */ |
if ((info->return_object)->common.type != ACPI_TYPE_LOCAL_REFERENCE) { |
return; |
} |
/* |
* Two types of references are supported - those created by Index and |
* ref_of operators. A name reference (AML_NAMEPATH_OP) can be converted |
* to an union acpi_object, so it is not dereferenced here. A ddb_handle |
* (AML_LOAD_OP) cannot be dereferenced, nor can it be converted to |
* an union acpi_object. |
*/ |
switch (info->return_object->reference.class) { |
case ACPI_REFCLASS_INDEX: |
obj_desc = *(info->return_object->reference.where); |
break; |
case ACPI_REFCLASS_REFOF: |
node = info->return_object->reference.object; |
if (node) { |
obj_desc = node->object; |
} |
break; |
default: |
return; |
} |
/* Replace the existing reference object */ |
if (obj_desc) { |
acpi_ut_add_reference(obj_desc); |
acpi_ut_remove_reference(info->return_object); |
info->return_object = obj_desc; |
} |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_walk_namespace |
* |
* PARAMETERS: type - acpi_object_type to search for |
* start_object - Handle in namespace where search begins |
* max_depth - Depth to which search is to reach |
* descending_callback - Called during tree descent |
* when an object of "Type" is found |
* ascending_callback - Called during tree ascent |
* when an object of "Type" is found |
* context - Passed to user function(s) above |
* return_value - Location where return value of |
* user_function is put if terminated early |
* |
* RETURNS Return value from the user_function if terminated early. |
* Otherwise, returns NULL. |
* |
* DESCRIPTION: Performs a modified depth-first walk of the namespace tree, |
* starting (and ending) at the object specified by start_handle. |
* The callback function is called whenever an object that matches |
* the type parameter is found. If the callback function returns |
* a non-zero value, the search is terminated immediately and this |
* value is returned to the caller. |
* |
* The point of this procedure is to provide a generic namespace |
* walk routine that can be called from multiple places to |
* provide multiple services; the callback function(s) can be |
* tailored to each task, whether it is a print function, |
* a compare function, etc. |
* |
******************************************************************************/ |
acpi_status |
acpi_walk_namespace(acpi_object_type type, |
acpi_handle start_object, |
u32 max_depth, |
acpi_walk_callback descending_callback, |
acpi_walk_callback ascending_callback, |
void *context, void **return_value) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_walk_namespace); |
/* Parameter validation */ |
if ((type > ACPI_TYPE_LOCAL_MAX) || |
(!max_depth) || (!descending_callback && !ascending_callback)) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* Need to acquire the namespace reader lock to prevent interference |
* with any concurrent table unloads (which causes the deletion of |
* namespace objects). We cannot allow the deletion of a namespace node |
* while the user function is using it. The exception to this are the |
* nodes created and deleted during control method execution -- these |
* nodes are marked as temporary nodes and are ignored by the namespace |
* walk. Thus, control methods can be executed while holding the |
* namespace deletion lock (and the user function can execute control |
* methods.) |
*/ |
status = acpi_ut_acquire_read_lock(&acpi_gbl_namespace_rw_lock); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Lock the namespace around the walk. The namespace will be |
* unlocked/locked around each call to the user function - since the user |
* function must be allowed to make ACPICA calls itself (for example, it |
* will typically execute control methods during device enumeration.) |
*/ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* Now we can validate the starting node */ |
if (!acpi_ns_validate_handle(start_object)) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit2; |
} |
status = acpi_ns_walk_namespace(type, start_object, max_depth, |
ACPI_NS_WALK_UNLOCK, |
descending_callback, ascending_callback, |
context, return_value); |
unlock_and_exit2: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
unlock_and_exit: |
(void)acpi_ut_release_read_lock(&acpi_gbl_namespace_rw_lock); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_walk_namespace) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ns_get_device_callback |
* |
* PARAMETERS: Callback from acpi_get_device |
* |
* RETURN: Status |
* |
* DESCRIPTION: Takes callbacks from walk_namespace and filters out all non- |
* present devices, or if they specified a HID, it filters based |
* on that. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ns_get_device_callback(acpi_handle obj_handle, |
u32 nesting_level, |
void *context, void **return_value) |
{ |
struct acpi_get_devices_info *info = context; |
acpi_status status; |
struct acpi_namespace_node *node; |
u32 flags; |
struct acpi_pnp_device_id *hid; |
struct acpi_pnp_device_id_list *cid; |
u32 i; |
u8 found; |
int no_match; |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
node = acpi_ns_validate_handle(obj_handle); |
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (!node) { |
return (AE_BAD_PARAMETER); |
} |
/* |
* First, filter based on the device HID and CID. |
* |
* 01/2010: For this case where a specific HID is requested, we don't |
* want to run _STA until we have an actual HID match. Thus, we will |
* not unnecessarily execute _STA on devices for which the caller |
* doesn't care about. Previously, _STA was executed unconditionally |
* on all devices found here. |
* |
* A side-effect of this change is that now we will continue to search |
* for a matching HID even under device trees where the parent device |
* would have returned a _STA that indicates it is not present or |
* not functioning (thus aborting the search on that branch). |
*/ |
if (info->hid != NULL) { |
status = acpi_ut_execute_HID(node, &hid); |
if (status == AE_NOT_FOUND) { |
return (AE_OK); |
} else if (ACPI_FAILURE(status)) { |
return (AE_CTRL_DEPTH); |
} |
no_match = strcmp(hid->string, info->hid); |
ACPI_FREE(hid); |
if (no_match) { |
/* |
* HID does not match, attempt match within the |
* list of Compatible IDs (CIDs) |
*/ |
status = acpi_ut_execute_CID(node, &cid); |
if (status == AE_NOT_FOUND) { |
return (AE_OK); |
} else if (ACPI_FAILURE(status)) { |
return (AE_CTRL_DEPTH); |
} |
/* Walk the CID list */ |
found = FALSE; |
for (i = 0; i < cid->count; i++) { |
if (strcmp(cid->ids[i].string, info->hid) == 0) { |
/* Found a matching CID */ |
found = TRUE; |
break; |
} |
} |
ACPI_FREE(cid); |
if (!found) { |
return (AE_OK); |
} |
} |
} |
/* Run _STA to determine if device is present */ |
status = acpi_ut_execute_STA(node, &flags); |
if (ACPI_FAILURE(status)) { |
return (AE_CTRL_DEPTH); |
} |
if (!(flags & ACPI_STA_DEVICE_PRESENT) && |
!(flags & ACPI_STA_DEVICE_FUNCTIONING)) { |
/* |
* Don't examine the children of the device only when the |
* device is neither present nor functional. See ACPI spec, |
* description of _STA for more information. |
*/ |
return (AE_CTRL_DEPTH); |
} |
/* We have a valid device, invoke the user function */ |
status = info->user_function(obj_handle, nesting_level, info->context, |
return_value); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_devices |
* |
* PARAMETERS: HID - HID to search for. Can be NULL. |
* user_function - Called when a matching object is found |
* context - Passed to user function |
* return_value - Location where return value of |
* user_function is put if terminated early |
* |
* RETURNS Return value from the user_function if terminated early. |
* Otherwise, returns NULL. |
* |
* DESCRIPTION: Performs a modified depth-first walk of the namespace tree, |
* starting (and ending) at the object specified by start_handle. |
* The user_function is called whenever an object of type |
* Device is found. If the user function returns |
* a non-zero value, the search is terminated immediately and this |
* value is returned to the caller. |
* |
* This is a wrapper for walk_namespace, but the callback performs |
* additional filtering. Please see acpi_ns_get_device_callback. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_devices(const char *HID, |
acpi_walk_callback user_function, |
void *context, void **return_value) |
{ |
acpi_status status; |
struct acpi_get_devices_info info; |
ACPI_FUNCTION_TRACE(acpi_get_devices); |
/* Parameter validation */ |
if (!user_function) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* We're going to call their callback from OUR callback, so we need |
* to know what it is, and their context parameter. |
*/ |
info.hid = HID; |
info.context = context; |
info.user_function = user_function; |
/* |
* Lock the namespace around the walk. |
* The namespace will be unlocked/locked around each call |
* to the user function - since this function |
* must be allowed to make Acpi calls itself. |
*/ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, |
acpi_ns_get_device_callback, NULL, |
&info, return_value); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_devices) |
/******************************************************************************* |
* |
* FUNCTION: acpi_attach_data |
* |
* PARAMETERS: obj_handle - Namespace node |
* handler - Handler for this attachment |
* data - Pointer to data to be attached |
* |
* RETURN: Status |
* |
* DESCRIPTION: Attach arbitrary data and handler to a namespace node. |
* |
******************************************************************************/ |
acpi_status |
acpi_attach_data(acpi_handle obj_handle, |
acpi_object_handler handler, void *data) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
/* Parameter validation */ |
if (!obj_handle || !handler || !data) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Convert and validate the handle */ |
node = acpi_ns_validate_handle(obj_handle); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
status = acpi_ns_attach_data(node, handler, data); |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_attach_data) |
/******************************************************************************* |
* |
* FUNCTION: acpi_detach_data |
* |
* PARAMETERS: obj_handle - Namespace node handle |
* handler - Handler used in call to acpi_attach_data |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove data that was previously attached to a node. |
* |
******************************************************************************/ |
acpi_status |
acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
/* Parameter validation */ |
if (!obj_handle || !handler) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Convert and validate the handle */ |
node = acpi_ns_validate_handle(obj_handle); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
status = acpi_ns_detach_data(node, handler); |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_detach_data) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_data_full |
* |
* PARAMETERS: obj_handle - Namespace node |
* handler - Handler used in call to attach_data |
* data - Where the data is returned |
* callback - function to execute before returning |
* |
* RETURN: Status |
* |
* DESCRIPTION: Retrieve data that was previously attached to a namespace node |
* and execute a callback before returning. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler, |
void **data, void (*callback)(void *)) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
/* Parameter validation */ |
if (!obj_handle || !handler || !data) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Convert and validate the handle */ |
node = acpi_ns_validate_handle(obj_handle); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
status = acpi_ns_get_attached_data(node, handler, data); |
if (ACPI_SUCCESS(status) && callback) { |
callback(*data); |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_data_full) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_data |
* |
* PARAMETERS: obj_handle - Namespace node |
* handler - Handler used in call to attach_data |
* data - Where the data is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Retrieve data that was previously attached to a namespace node. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) |
{ |
return acpi_get_data_full(obj_handle, handler, data, NULL); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_data) |
/drivers/acpi/acpica/nsxfname.c |
---|
0,0 → 1,684 |
/****************************************************************************** |
* |
* Module Name: nsxfname - Public interfaces to the ACPI subsystem |
* ACPI Namespace oriented interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acparser.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsxfname") |
/* Local prototypes */ |
static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, |
struct acpi_pnp_device_id *source, |
char *string_area); |
/****************************************************************************** |
* |
* FUNCTION: acpi_get_handle |
* |
* PARAMETERS: parent - Object to search under (search scope). |
* pathname - Pointer to an asciiz string containing the |
* name |
* ret_handle - Where the return handle is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This routine will search for a caller specified name in the |
* name space. The caller can restrict the search region by |
* specifying a non NULL parent. The parent value is itself a |
* namespace handle. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_handle(acpi_handle parent, |
acpi_string pathname, acpi_handle * ret_handle) |
{ |
acpi_status status; |
struct acpi_namespace_node *node = NULL; |
struct acpi_namespace_node *prefix_node = NULL; |
ACPI_FUNCTION_ENTRY(); |
/* Parameter Validation */ |
if (!ret_handle || !pathname) { |
return (AE_BAD_PARAMETER); |
} |
/* Convert a parent handle to a prefix node */ |
if (parent) { |
prefix_node = acpi_ns_validate_handle(parent); |
if (!prefix_node) { |
return (AE_BAD_PARAMETER); |
} |
} |
/* |
* Valid cases are: |
* 1) Fully qualified pathname |
* 2) Parent + Relative pathname |
* |
* Error for <null Parent + relative path> |
*/ |
if (ACPI_IS_ROOT_PREFIX(pathname[0])) { |
/* Pathname is fully qualified (starts with '\') */ |
/* Special case for root-only, since we can't search for it */ |
if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) { |
*ret_handle = |
ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); |
return (AE_OK); |
} |
} else if (!prefix_node) { |
/* Relative path with null prefix is disallowed */ |
return (AE_BAD_PARAMETER); |
} |
/* Find the Node and convert to a handle */ |
status = |
acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); |
if (ACPI_SUCCESS(status)) { |
*ret_handle = ACPI_CAST_PTR(acpi_handle, node); |
} |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_handle) |
/****************************************************************************** |
* |
* FUNCTION: acpi_get_name |
* |
* PARAMETERS: handle - Handle to be converted to a pathname |
* name_type - Full pathname or single segment |
* buffer - Buffer for returned path |
* |
* RETURN: Pointer to a string containing the fully qualified Name. |
* |
* DESCRIPTION: This routine returns the fully qualified name associated with |
* the Handle parameter. This and the acpi_pathname_to_handle are |
* complementary functions. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
char *node_name; |
/* Parameter validation */ |
if (name_type > ACPI_NAME_TYPE_MAX) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_ut_validate_buffer(buffer); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (name_type == ACPI_FULL_PATHNAME || |
name_type == ACPI_FULL_PATHNAME_NO_TRAILING) { |
/* Get the full pathname (From the namespace root) */ |
status = acpi_ns_handle_to_pathname(handle, buffer, |
name_type == |
ACPI_FULL_PATHNAME ? FALSE : |
TRUE); |
return (status); |
} |
/* |
* Wants the single segment ACPI name. |
* Validate handle and convert to a namespace Node |
*/ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
node = acpi_ns_validate_handle(handle); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Validate/Allocate/Clear caller buffer */ |
status = acpi_ut_initialize_buffer(buffer, ACPI_PATH_SEGMENT_LENGTH); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* Just copy the ACPI name from the Node and zero terminate it */ |
node_name = acpi_ut_get_node_name(node); |
ACPI_MOVE_NAME(buffer->pointer, node_name); |
((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; |
status = AE_OK; |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_name) |
/****************************************************************************** |
* |
* FUNCTION: acpi_ns_copy_device_id |
* |
* PARAMETERS: dest - Pointer to the destination PNP_DEVICE_ID |
* source - Pointer to the source PNP_DEVICE_ID |
* string_area - Pointer to where to copy the dest string |
* |
* RETURN: Pointer to the next string area |
* |
* DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. |
* |
******************************************************************************/ |
static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, |
struct acpi_pnp_device_id *source, |
char *string_area) |
{ |
/* Create the destination PNP_DEVICE_ID */ |
dest->string = string_area; |
dest->length = source->length; |
/* Copy actual string and return a pointer to the next string area */ |
memcpy(string_area, source->string, source->length); |
return (string_area + source->length); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_get_object_info |
* |
* PARAMETERS: handle - Object Handle |
* return_buffer - Where the info is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Returns information about an object as gleaned from the |
* namespace node and possibly by running several standard |
* control methods (Such as in the case of a device.) |
* |
* For Device and Processor objects, run the Device _HID, _UID, _CID, _SUB, |
* _CLS, _STA, _ADR, _sx_w, and _sx_d methods. |
* |
* Note: Allocates the return buffer, must be freed by the caller. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_object_info(acpi_handle handle, |
struct acpi_device_info **return_buffer) |
{ |
struct acpi_namespace_node *node; |
struct acpi_device_info *info; |
struct acpi_pnp_device_id_list *cid_list = NULL; |
struct acpi_pnp_device_id *hid = NULL; |
struct acpi_pnp_device_id *uid = NULL; |
struct acpi_pnp_device_id *sub = NULL; |
struct acpi_pnp_device_id *cls = NULL; |
char *next_id_string; |
acpi_object_type type; |
acpi_name name; |
u8 param_count = 0; |
u16 valid = 0; |
u32 info_size; |
u32 i; |
acpi_status status; |
/* Parameter validation */ |
if (!handle || !return_buffer) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
node = acpi_ns_validate_handle(handle); |
if (!node) { |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (AE_BAD_PARAMETER); |
} |
/* Get the namespace node data while the namespace is locked */ |
info_size = sizeof(struct acpi_device_info); |
type = node->type; |
name = node->name.integer; |
if (node->type == ACPI_TYPE_METHOD) { |
param_count = node->object->method.param_count; |
} |
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { |
/* |
* Get extra info for ACPI Device/Processor objects only: |
* Run the Device _HID, _UID, _SUB, _CID, and _CLS methods. |
* |
* Note: none of these methods are required, so they may or may |
* not be present for this device. The Info->Valid bitfield is used |
* to indicate which methods were found and run successfully. |
*/ |
/* Execute the Device._HID method */ |
status = acpi_ut_execute_HID(node, &hid); |
if (ACPI_SUCCESS(status)) { |
info_size += hid->length; |
valid |= ACPI_VALID_HID; |
} |
/* Execute the Device._UID method */ |
status = acpi_ut_execute_UID(node, &uid); |
if (ACPI_SUCCESS(status)) { |
info_size += uid->length; |
valid |= ACPI_VALID_UID; |
} |
/* Execute the Device._SUB method */ |
status = acpi_ut_execute_SUB(node, &sub); |
if (ACPI_SUCCESS(status)) { |
info_size += sub->length; |
valid |= ACPI_VALID_SUB; |
} |
/* Execute the Device._CID method */ |
status = acpi_ut_execute_CID(node, &cid_list); |
if (ACPI_SUCCESS(status)) { |
/* Add size of CID strings and CID pointer array */ |
info_size += |
(cid_list->list_size - |
sizeof(struct acpi_pnp_device_id_list)); |
valid |= ACPI_VALID_CID; |
} |
/* Execute the Device._CLS method */ |
status = acpi_ut_execute_CLS(node, &cls); |
if (ACPI_SUCCESS(status)) { |
info_size += cls->length; |
valid |= ACPI_VALID_CLS; |
} |
} |
/* |
* Now that we have the variable-length data, we can allocate the |
* return buffer |
*/ |
info = ACPI_ALLOCATE_ZEROED(info_size); |
if (!info) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Get the fixed-length data */ |
if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { |
/* |
* Get extra info for ACPI Device/Processor objects only: |
* Run the _STA, _ADR and, sx_w, and _sx_d methods. |
* |
* Notes: none of these methods are required, so they may or may |
* not be present for this device. The Info->Valid bitfield is used |
* to indicate which methods were found and run successfully. |
* |
* For _STA, if the method does not exist, then (as per the ACPI |
* specification), the returned current_status flags will indicate |
* that the device is present/functional/enabled. Otherwise, the |
* current_status flags reflect the value returned from _STA. |
*/ |
/* Execute the Device._STA method */ |
status = acpi_ut_execute_STA(node, &info->current_status); |
if (ACPI_SUCCESS(status)) { |
valid |= ACPI_VALID_STA; |
} |
/* Execute the Device._ADR method */ |
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, |
&info->address); |
if (ACPI_SUCCESS(status)) { |
valid |= ACPI_VALID_ADR; |
} |
/* Execute the Device._sx_w methods */ |
status = acpi_ut_execute_power_methods(node, |
acpi_gbl_lowest_dstate_names, |
ACPI_NUM_sx_w_METHODS, |
info->lowest_dstates); |
if (ACPI_SUCCESS(status)) { |
valid |= ACPI_VALID_SXWS; |
} |
/* Execute the Device._sx_d methods */ |
status = acpi_ut_execute_power_methods(node, |
acpi_gbl_highest_dstate_names, |
ACPI_NUM_sx_d_METHODS, |
info->highest_dstates); |
if (ACPI_SUCCESS(status)) { |
valid |= ACPI_VALID_SXDS; |
} |
} |
/* |
* Create a pointer to the string area of the return buffer. |
* Point to the end of the base struct acpi_device_info structure. |
*/ |
next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids); |
if (cid_list) { |
/* Point past the CID PNP_DEVICE_ID array */ |
next_id_string += |
((acpi_size) cid_list->count * |
sizeof(struct acpi_pnp_device_id)); |
} |
/* |
* Copy the HID, UID, SUB, and CIDs to the return buffer. |
* The variable-length strings are copied to the reserved area |
* at the end of the buffer. |
* |
* For HID and CID, check if the ID is a PCI Root Bridge. |
*/ |
if (hid) { |
next_id_string = acpi_ns_copy_device_id(&info->hardware_id, |
hid, next_id_string); |
if (acpi_ut_is_pci_root_bridge(hid->string)) { |
info->flags |= ACPI_PCI_ROOT_BRIDGE; |
} |
} |
if (uid) { |
next_id_string = acpi_ns_copy_device_id(&info->unique_id, |
uid, next_id_string); |
} |
if (sub) { |
next_id_string = acpi_ns_copy_device_id(&info->subsystem_id, |
sub, next_id_string); |
} |
if (cid_list) { |
info->compatible_id_list.count = cid_list->count; |
info->compatible_id_list.list_size = cid_list->list_size; |
/* Copy each CID */ |
for (i = 0; i < cid_list->count; i++) { |
next_id_string = |
acpi_ns_copy_device_id(&info->compatible_id_list. |
ids[i], &cid_list->ids[i], |
next_id_string); |
if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) { |
info->flags |= ACPI_PCI_ROOT_BRIDGE; |
} |
} |
} |
if (cls) { |
next_id_string = acpi_ns_copy_device_id(&info->class_code, |
cls, next_id_string); |
} |
/* Copy the fixed-length data */ |
info->info_size = info_size; |
info->type = type; |
info->name = name; |
info->param_count = param_count; |
info->valid = valid; |
*return_buffer = info; |
status = AE_OK; |
cleanup: |
if (hid) { |
ACPI_FREE(hid); |
} |
if (uid) { |
ACPI_FREE(uid); |
} |
if (sub) { |
ACPI_FREE(sub); |
} |
if (cid_list) { |
ACPI_FREE(cid_list); |
} |
if (cls) { |
ACPI_FREE(cls); |
} |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_object_info) |
/****************************************************************************** |
* |
* FUNCTION: acpi_install_method |
* |
* PARAMETERS: buffer - An ACPI table containing one control method |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a control method into the namespace. If the method |
* name already exists in the namespace, it is overwritten. The |
* input buffer must contain a valid DSDT or SSDT containing a |
* single control method. |
* |
******************************************************************************/ |
acpi_status acpi_install_method(u8 *buffer) |
{ |
struct acpi_table_header *table = |
ACPI_CAST_PTR(struct acpi_table_header, buffer); |
u8 *aml_buffer; |
u8 *aml_start; |
char *path; |
struct acpi_namespace_node *node; |
union acpi_operand_object *method_obj; |
struct acpi_parse_state parser_state; |
u32 aml_length; |
u16 opcode; |
u8 method_flags; |
acpi_status status; |
/* Parameter validation */ |
if (!buffer) { |
return (AE_BAD_PARAMETER); |
} |
/* Table must be a DSDT or SSDT */ |
if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) && |
!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { |
return (AE_BAD_HEADER); |
} |
/* First AML opcode in the table must be a control method */ |
parser_state.aml = buffer + sizeof(struct acpi_table_header); |
opcode = acpi_ps_peek_opcode(&parser_state); |
if (opcode != AML_METHOD_OP) { |
return (AE_BAD_PARAMETER); |
} |
/* Extract method information from the raw AML */ |
parser_state.aml += acpi_ps_get_opcode_size(opcode); |
parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); |
path = acpi_ps_get_next_namestring(&parser_state); |
method_flags = *parser_state.aml++; |
aml_start = parser_state.aml; |
aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); |
/* |
* Allocate resources up-front. We don't want to have to delete a new |
* node from the namespace if we cannot allocate memory. |
*/ |
aml_buffer = ACPI_ALLOCATE(aml_length); |
if (!aml_buffer) { |
return (AE_NO_MEMORY); |
} |
method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); |
if (!method_obj) { |
ACPI_FREE(aml_buffer); |
return (AE_NO_MEMORY); |
} |
/* Lock namespace for acpi_ns_lookup, we may be creating a new node */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
/* The lookup either returns an existing node or creates a new one */ |
status = |
acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, |
ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, |
NULL, &node); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { /* ns_lookup */ |
if (status != AE_ALREADY_EXISTS) { |
goto error_exit; |
} |
/* Node existed previously, make sure it is a method node */ |
if (node->type != ACPI_TYPE_METHOD) { |
status = AE_TYPE; |
goto error_exit; |
} |
} |
/* Copy the method AML to the local buffer */ |
memcpy(aml_buffer, aml_start, aml_length); |
/* Initialize the method object with the new method's information */ |
method_obj->method.aml_start = aml_buffer; |
method_obj->method.aml_length = aml_length; |
method_obj->method.param_count = (u8) |
(method_flags & AML_METHOD_ARG_COUNT); |
if (method_flags & AML_METHOD_SERIALIZED) { |
method_obj->method.info_flags = ACPI_METHOD_SERIALIZED; |
method_obj->method.sync_level = (u8) |
((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); |
} |
/* |
* Now that it is complete, we can attach the new method object to |
* the method Node (detaches/deletes any existing object) |
*/ |
status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); |
/* |
* Flag indicates AML buffer is dynamic, must be deleted later. |
* Must be set only after attach above. |
*/ |
node->flags |= ANOBJ_ALLOCATED_BUFFER; |
/* Remove local reference to the method object */ |
acpi_ut_remove_reference(method_obj); |
return (status); |
error_exit: |
ACPI_FREE(aml_buffer); |
ACPI_FREE(method_obj); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_method) |
/drivers/acpi/acpica/nsxfobj.c |
---|
0,0 → 1,246 |
/******************************************************************************* |
* |
* Module Name: nsxfobj - Public interfaces to the ACPI subsystem |
* ACPI Object oriented interfaces |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_NAMESPACE |
ACPI_MODULE_NAME("nsxfobj") |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_type |
* |
* PARAMETERS: handle - Handle of object whose type is desired |
* ret_type - Where the type will be placed |
* |
* RETURN: Status |
* |
* DESCRIPTION: This routine returns the type associatd with a particular handle |
* |
******************************************************************************/ |
acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type) |
{ |
struct acpi_namespace_node *node; |
acpi_status status; |
/* Parameter Validation */ |
if (!ret_type) { |
return (AE_BAD_PARAMETER); |
} |
/* |
* Special case for the predefined Root Node |
* (return type ANY) |
*/ |
if (handle == ACPI_ROOT_OBJECT) { |
*ret_type = ACPI_TYPE_ANY; |
return (AE_OK); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Convert and validate the handle */ |
node = acpi_ns_validate_handle(handle); |
if (!node) { |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (AE_BAD_PARAMETER); |
} |
*ret_type = node->type; |
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_type) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_parent |
* |
* PARAMETERS: handle - Handle of object whose parent is desired |
* ret_handle - Where the parent handle will be placed |
* |
* RETURN: Status |
* |
* DESCRIPTION: Returns a handle to the parent of the object represented by |
* Handle. |
* |
******************************************************************************/ |
acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) |
{ |
struct acpi_namespace_node *node; |
struct acpi_namespace_node *parent_node; |
acpi_status status; |
if (!ret_handle) { |
return (AE_BAD_PARAMETER); |
} |
/* Special case for the predefined Root Node (no parent) */ |
if (handle == ACPI_ROOT_OBJECT) { |
return (AE_NULL_ENTRY); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Convert and validate the handle */ |
node = acpi_ns_validate_handle(handle); |
if (!node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
/* Get the parent entry */ |
parent_node = node->parent; |
*ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node); |
/* Return exception if parent is null */ |
if (!parent_node) { |
status = AE_NULL_ENTRY; |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_parent) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_next_object |
* |
* PARAMETERS: type - Type of object to be searched for |
* parent - Parent object whose children we are getting |
* last_child - Previous child that was found. |
* The NEXT child will be returned |
* ret_handle - Where handle to the next object is placed |
* |
* RETURN: Status |
* |
* DESCRIPTION: Return the next peer object within the namespace. If Handle is |
* valid, Scope is ignored. Otherwise, the first object within |
* Scope is returned. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_next_object(acpi_object_type type, |
acpi_handle parent, |
acpi_handle child, acpi_handle * ret_handle) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
struct acpi_namespace_node *parent_node = NULL; |
struct acpi_namespace_node *child_node = NULL; |
/* Parameter validation */ |
if (type > ACPI_TYPE_EXTERNAL_MAX) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* If null handle, use the parent */ |
if (!child) { |
/* Start search at the beginning of the specified scope */ |
parent_node = acpi_ns_validate_handle(parent); |
if (!parent_node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
} else { |
/* Non-null handle, ignore the parent */ |
/* Convert and validate the handle */ |
child_node = acpi_ns_validate_handle(child); |
if (!child_node) { |
status = AE_BAD_PARAMETER; |
goto unlock_and_exit; |
} |
} |
/* Internal function does the real work */ |
node = acpi_ns_get_next_node_typed(type, parent_node, child_node); |
if (!node) { |
status = AE_NOT_FOUND; |
goto unlock_and_exit; |
} |
if (ret_handle) { |
*ret_handle = ACPI_CAST_PTR(acpi_handle, node); |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_next_object) |
/drivers/acpi/acpica/osunixxf.c |
---|
0,0 → 1,1297 |
/****************************************************************************** |
* |
* Module Name: osunixxf - UNIX OSL interfaces |
* |
*****************************************************************************/ |
/****************************************************************************** |
* |
* 1. Copyright Notice |
* |
* Some or all of this work - Copyright (c) 1999 - 2011, 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 "acpi.h" |
#include "accommon.h" |
#include "amlcode.h" |
#include "acparser.h" |
#include "acdebug.h" |
/* |
* These interfaces are required in order to compile the ASL compiler under |
* Linux or other Unix-like system. |
*/ |
/* |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdarg.h> |
#include <unistd.h> |
#include <sys/time.h> |
#include <semaphore.h> |
#include <pthread.h> |
*/ |
#define _COMPONENT ACPI_OS_SERVICES |
ACPI_MODULE_NAME ("oskolibri") |
extern void *AcpiGbl_DebugFile; |
void *AcpiGbl_OutputFile; |
static UINT32 sACPIRoot = 0; |
void |
AeTableOverride ( |
ACPI_TABLE_HEADER *ExistingTable, |
ACPI_TABLE_HEADER **NewTable); |
typedef void* (*PTHREAD_CALLBACK) (void *); |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsInitialize, AcpiOsTerminate |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Init and terminate. Nothing to do. |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsInitialize (void) |
{ |
if(!dbg_open("/rd/1/drivers/acpi.log")) |
{ |
dbgprintf("Can't open /rd/1/drivers/acpi.log\nExit\n"); |
return AE_ERROR; |
} |
return (AE_OK); |
} |
ACPI_STATUS |
AcpiOsTerminate (void) |
{ |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsGetRootPointer |
* |
* PARAMETERS: None |
* |
* RETURN: RSDP physical address |
* |
* DESCRIPTION: Gets the root pointer (RSDP) |
* |
*****************************************************************************/ |
ACPI_PHYSICAL_ADDRESS |
AcpiOsGetRootPointer ( |
void) |
{ |
ACPI_SIZE address; |
ACPI_STATUS status; |
if (sACPIRoot == 0) { |
status = AcpiFindRootPointer(&address); |
if (status == AE_OK) |
sACPIRoot = address; |
} |
dbgprintf("AcpiOsGetRootPointer returning %p\n", (void *)sACPIRoot); |
return sACPIRoot; |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsPredefinedOverride |
* |
* PARAMETERS: InitVal - Initial value of the predefined object |
* NewVal - The new value for the object |
* |
* RETURN: Status, pointer to value. Null pointer returned if not |
* overriding. |
* |
* DESCRIPTION: Allow the OS to override predefined names |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsPredefinedOverride ( |
const ACPI_PREDEFINED_NAMES *InitVal, |
ACPI_STRING *NewVal) |
{ |
if (!InitVal || !NewVal) |
{ |
return (AE_BAD_PARAMETER); |
} |
*NewVal = NULL; |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsTableOverride |
* |
* PARAMETERS: ExistingTable - Header of current table (probably |
* firmware) |
* NewTable - Where an entire new table is returned. |
* |
* RETURN: Status, pointer to new table. Null pointer returned if no |
* table is available to override |
* |
* DESCRIPTION: Return a different version of a table if one is available |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsTableOverride ( |
ACPI_TABLE_HEADER *ExistingTable, |
ACPI_TABLE_HEADER **NewTable) |
{ |
if (!ExistingTable || !NewTable) |
{ |
return (AE_BAD_PARAMETER); |
} |
*NewTable = NULL; |
#ifdef ACPI_EXEC_APP |
AeTableOverride (ExistingTable, NewTable); |
return (AE_OK); |
#else |
return (AE_NO_ACPI_TABLES); |
#endif |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsRedirectOutput |
* |
* PARAMETERS: Destination - An open file handle/pointer |
* |
* RETURN: None |
* |
* DESCRIPTION: Causes redirect of AcpiOsPrintf and AcpiOsVprintf |
* |
*****************************************************************************/ |
void |
AcpiOsRedirectOutput ( |
void *Destination) |
{ |
AcpiGbl_OutputFile = Destination; |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsPrintf |
* |
* PARAMETERS: fmt, ... - Standard printf format |
* |
* RETURN: None |
* |
* DESCRIPTION: Formatted output |
* |
*****************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
AcpiOsPrintf ( |
const char *Fmt, |
...) |
{ |
va_list Args; |
va_start (Args, Fmt); |
AcpiOsVprintf (Fmt, Args); |
va_end (Args); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsVprintf |
* |
* PARAMETERS: fmt - Standard printf format |
* args - Argument list |
* |
* RETURN: None |
* |
* DESCRIPTION: Formatted output with argument list pointer |
* |
*****************************************************************************/ |
void |
AcpiOsVprintf ( |
const char *Fmt, |
va_list Args) |
{ |
// INT32 Count = 0; |
// UINT8 Flags; |
// static char outputBuffer[1024]; |
// vsnprintf(outputBuffer, 1024, Fmt, Args); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsMapMemory |
* |
* PARAMETERS: where - Physical address of memory to be mapped |
* length - How much memory to map |
* |
* RETURN: Pointer to mapped memory. Null on error. |
* |
* DESCRIPTION: Map physical memory into caller's address space |
* |
*****************************************************************************/ |
void * |
AcpiOsMapMemory ( |
ACPI_PHYSICAL_ADDRESS where, |
ACPI_SIZE length) |
{ |
void* retval=NULL; |
if( (UINT64)where+length <= 0x100000000ULL) |
retval = (void*)MapIoMem(where, 4096+(UINT32)length, 0x07); |
// dbgprintf("%s %x-> %x %x\n",__FUNCTION__, |
// where, retval, length); |
return retval; |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsUnmapMemory |
* |
* PARAMETERS: where - Logical address of memory to be unmapped |
* length - How much memory to unmap |
* |
* RETURN: None. |
* |
* DESCRIPTION: Delete a previously created mapping. Where and Length must |
* correspond to a previous mapping exactly. |
* |
*****************************************************************************/ |
void |
AcpiOsUnmapMemory ( |
void *where, |
ACPI_SIZE length) |
{ |
FreeKernelSpace( 0xFFFFF000 & (UINT32)where); |
return; |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsAllocate |
* |
* PARAMETERS: Size - Amount to allocate, in bytes |
* |
* RETURN: Pointer to the new allocation. Null on error. |
* |
* DESCRIPTION: Allocate memory. Algorithm is dependent on the OS. |
* |
*****************************************************************************/ |
void * |
AcpiOsAllocate ( |
ACPI_SIZE size) |
{ |
void *Mem; |
Mem = (void *) malloc ((size_t) size); |
return (Mem); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsFree |
* |
* PARAMETERS: mem - Pointer to previously allocated memory |
* |
* RETURN: None. |
* |
* DESCRIPTION: Free memory allocated via AcpiOsAllocate |
* |
*****************************************************************************/ |
void |
AcpiOsFree ( |
void *mem) |
{ |
free (mem); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsCreateSemaphore |
* |
* PARAMETERS: InitialUnits - Units to be assigned to the new semaphore |
* OutHandle - Where a handle will be returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create an OS semaphore |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsCreateSemaphore ( |
UINT32 MaxUnits, |
UINT32 InitialUnits, |
ACPI_HANDLE *OutHandle) |
{ |
if (!OutHandle) |
{ |
return (AE_BAD_PARAMETER); |
} |
*OutHandle = (ACPI_HANDLE) 1; |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsDeleteSemaphore |
* |
* PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore |
* |
* RETURN: Status |
* |
* DESCRIPTION: Delete an OS semaphore |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsDeleteSemaphore ( |
ACPI_HANDLE Handle) |
{ |
if (!Handle) |
{ |
return (AE_BAD_PARAMETER); |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsWaitSemaphore |
* |
* PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore |
* Units - How many units to wait for |
* Timeout - How long to wait |
* |
* RETURN: Status |
* |
* DESCRIPTION: Wait for units |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsWaitSemaphore ( |
ACPI_HANDLE Handle, |
UINT32 Units, |
UINT16 Timeout) |
{ |
ACPI_STATUS Status = AE_OK; |
#if 0 |
if (!Sem) |
{ |
return (AE_BAD_PARAMETER); |
} |
switch (Timeout) |
{ |
/* |
* No Wait: |
* -------- |
* A zero timeout value indicates that we shouldn't wait - just |
* acquire the semaphore if available otherwise return AE_TIME |
* (a.k.a. 'would block'). |
*/ |
case 0: |
if (sem_trywait(Sem) == -1) |
{ |
Status = (AE_TIME); |
} |
break; |
/* Wait Indefinitely */ |
case ACPI_WAIT_FOREVER: |
if (sem_wait (Sem)) |
{ |
Status = (AE_TIME); |
} |
break; |
/* Wait with Timeout */ |
default: |
T.tv_sec = Timeout / 1000; |
T.tv_nsec = (Timeout - (T.tv_sec * 1000)) * 1000000; |
#ifdef ACPI_USE_ALTERNATE_TIMEOUT |
/* |
* Alternate timeout mechanism for environments where |
* sem_timedwait is not available or does not work properly. |
*/ |
while (Timeout) |
{ |
if (sem_trywait (Sem) == 0) |
{ |
/* Got the semaphore */ |
return (AE_OK); |
} |
usleep (1000); /* one millisecond */ |
Timeout--; |
} |
Status = (AE_TIME); |
#else |
if (sem_timedwait (Sem, &T)) |
{ |
Status = (AE_TIME); |
} |
#endif |
break; |
} |
#endif |
return (Status); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsSignalSemaphore |
* |
* PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore |
* Units - Number of units to send |
* |
* RETURN: Status |
* |
* DESCRIPTION: Send units |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsSignalSemaphore ( |
ACPI_HANDLE Handle, |
UINT32 Units) |
{ |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: Spinlock interfaces |
* |
* DESCRIPTION: Map these interfaces to semaphore interfaces |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsCreateLock ( |
ACPI_SPINLOCK *OutHandle) |
{ |
if (!OutHandle) |
{ |
return (AE_BAD_PARAMETER); |
} |
*OutHandle = (ACPI_HANDLE)malloc(sizeof(u32_t)); |
if (*OutHandle == NULL) |
return AE_NO_MEMORY; |
*((UINT32*)(*OutHandle)) = 0; |
return AE_OK; |
} |
void |
AcpiOsDeleteLock ( |
ACPI_SPINLOCK Handle) |
{ |
free (Handle); |
} |
ACPI_CPU_FLAGS |
AcpiOsAcquireLock ( |
ACPI_HANDLE Handle) |
{ |
AcpiOsWaitSemaphore (Handle, 1, 0xFFFF); |
return (0); |
} |
void |
AcpiOsReleaseLock ( |
ACPI_SPINLOCK Handle, |
ACPI_CPU_FLAGS Flags) |
{ |
AcpiOsSignalSemaphore (Handle, 1); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsInstallInterruptHandler |
* |
* PARAMETERS: InterruptNumber Level handler should respond to. |
* Isr Address of the ACPI interrupt handler |
* ExceptPtr Where status is returned |
* |
* RETURN: Handle to the newly installed handler. |
* |
* DESCRIPTION: Install an interrupt handler. Used to install the ACPI |
* OS-independent handler. |
* |
*****************************************************************************/ |
UINT32 |
AcpiOsInstallInterruptHandler ( |
UINT32 InterruptNumber, |
ACPI_OSD_HANDLER ServiceRoutine, |
void *Context) |
{ |
dbgprintf("%s irq %d\n", InterruptNumber ); |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsRemoveInterruptHandler |
* |
* PARAMETERS: Handle Returned when handler was installed |
* |
* RETURN: Status |
* |
* DESCRIPTION: Uninstalls an interrupt handler. |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsRemoveInterruptHandler ( |
UINT32 InterruptNumber, |
ACPI_OSD_HANDLER ServiceRoutine) |
{ |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsExecute |
* |
* PARAMETERS: Type - Type of execution |
* Function - Address of the function to execute |
* Context - Passed as a parameter to the function |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Execute a new thread |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsExecute ( |
ACPI_EXECUTE_TYPE Type, |
ACPI_OSD_EXEC_CALLBACK Function, |
void *Context) |
{ |
// pthread_t thread; |
// int ret; |
// ret = pthread_create (&thread, NULL, (PTHREAD_CALLBACK) Function, Context); |
// if (ret) |
// { |
// AcpiOsPrintf("Create thread failed"); |
// } |
return (0); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsStall |
* |
* PARAMETERS: microseconds - Time to sleep |
* |
* RETURN: Blocks until sleep is completed. |
* |
* DESCRIPTION: Sleep at microsecond granularity |
* |
*****************************************************************************/ |
void |
AcpiOsStall ( |
UINT32 microseconds) |
{ |
if (microseconds) |
{ |
usleep (microseconds); |
} |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsSleep |
* |
* PARAMETERS: milliseconds - Time to sleep |
* |
* RETURN: Blocks until sleep is completed. |
* |
* DESCRIPTION: Sleep at millisecond granularity |
* |
*****************************************************************************/ |
void |
AcpiOsSleep ( |
UINT64 milliseconds) |
{ |
delay(milliseconds / 8); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsGetTimer |
* |
* PARAMETERS: None |
* |
* RETURN: Current time in 100 nanosecond units |
* |
* DESCRIPTION: Get the current system time |
* |
*****************************************************************************/ |
UINT64 |
AcpiOsGetTimer (void) |
{ |
// struct timeval time; |
// gettimeofday (&time, NULL); |
/* Seconds * 10^7 = 100ns(10^-7), Microseconds(10^-6) * 10^1 = 100ns */ |
// return (((UINT64) time.tv_sec * 10000000) + ((UINT64) time.tv_usec * 10)); |
return 0; |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsReadPciConfiguration |
* |
* PARAMETERS: PciId - Seg/Bus/Dev |
* Register - Device Register |
* Value - Buffer where value is placed |
* Width - Number of bits |
* |
* RETURN: Status |
* |
* DESCRIPTION: Read data from PCI configuration space |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsReadPciConfiguration ( |
ACPI_PCI_ID *PciId, |
UINT32 Register, |
UINT64 *Value, |
UINT32 Width) |
{ |
UINT32 devfn = ((PciId->Device & 0x1f)<<3)|(PciId->Function & 0x07); |
switch (Width) |
{ |
case 8: |
*(UINT8 *)Value = PciRead8(PciId->Bus,devfn,Register); |
break; |
case 16: |
*(UINT16 *)Value = PciRead16(PciId->Bus,devfn,Register); |
break; |
case 32: |
*(UINT32 *)Value = PciRead32(PciId->Bus,devfn,Register); |
break; |
default: |
dbgprintf("AcpiOsReadPciConfiguration unhandled value width: %u\n", |
Width); |
return AE_ERROR; |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsWritePciConfiguration |
* |
* PARAMETERS: PciId - Seg/Bus/Dev |
* Register - Device Register |
* Value - Value to be written |
* Width - Number of bits |
* |
* RETURN: Status. |
* |
* DESCRIPTION: Write data to PCI configuration space |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsWritePciConfiguration ( |
ACPI_PCI_ID *PciId, |
UINT32 Register, |
UINT64 Value, |
UINT32 Width) |
{ |
UINT32 devfn = ((PciId->Device & 0x1f)<<3)|(PciId->Function & 0x07); |
switch (Width) |
{ |
case 8: |
PciWrite8(PciId->Bus,devfn,Register,Value); |
break; |
case 16: |
PciWrite16(PciId->Bus,devfn,Register,Value); |
break; |
case 32: |
PciWrite32(PciId->Bus,devfn,Register,Value); |
break; |
default: |
dbgprintf("AcpiOsReadPciConfiguration unhandled value width: %u\n", |
Width); |
return AE_ERROR; |
} |
return (AE_OK); |
} |
/* TEMPORARY STUB FUNCTION */ |
void |
AcpiOsDerivePciId( |
ACPI_HANDLE Device, |
ACPI_HANDLE Region, |
ACPI_PCI_ID **PciId) |
{ |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsReadPort |
* |
* PARAMETERS: Address - Address of I/O port/register to read |
* Value - Where value is placed |
* Width - Number of bits |
* |
* RETURN: Value read from port |
* |
* DESCRIPTION: Read data from an I/O port or register |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsReadPort ( |
ACPI_IO_ADDRESS Address, |
UINT32 *Value, |
UINT32 Width) |
{ |
switch (Width) |
{ |
case 8: |
*Value = in8(Address); |
break; |
case 16: |
*Value = in16(Address); |
break; |
case 32: |
*Value = in32(Address); |
break; |
default: |
return (AE_BAD_PARAMETER); |
} |
// dbgprintf("%s %x, %x\n",__FUNCTION__, Address, *Value); |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsWritePort |
* |
* PARAMETERS: Address - Address of I/O port/register to write |
* Value - Value to write |
* Width - Number of bits |
* |
* RETURN: None |
* |
* DESCRIPTION: Write data to an I/O port or register |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsWritePort ( |
ACPI_IO_ADDRESS Address, |
UINT32 Value, |
UINT32 Width) |
{ |
switch (Width) { |
case 8: |
out8(Address, Value); |
break; |
case 16: |
out16(Address,Value); |
break; |
case 32: |
out32(Address,Value); |
break; |
default: |
return (AE_ERROR); |
} |
// dbgprintf("%s %x, %x\n",__FUNCTION__, Address, Value); |
return (AE_OK); |
}; |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsReadMemory |
* |
* PARAMETERS: Address - Physical Memory Address to read |
* Value - Where value is placed |
* Width - Number of bits |
* |
* RETURN: Value read from physical memory address |
* |
* DESCRIPTION: Read data from a physical memory address |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsReadMemory ( |
ACPI_PHYSICAL_ADDRESS Address, |
UINT32 *Value, |
UINT32 Width) |
{ |
void *memptr; |
ACPI_STATUS status = AE_ERROR; |
// dbgprintf("%s %x\n",__FUNCTION__, Address); |
if( (UINT64)Address+Width > 0x100000000ULL) |
return (AE_BAD_PARAMETER); |
if( Address >= 0x400000) |
{ |
memptr = AcpiOsMapMemory(Address, Width); |
if(memptr) |
{ |
status = AE_OK; |
switch (Width) |
{ |
case 8: |
*Value = *(UINT8*)Address; |
break; |
case 16: |
*Value = *(UINT16*)Address; |
break; |
case 32: |
*Value = *(UINT32*)Address; |
break; |
default: |
status = (AE_BAD_PARAMETER); |
} |
FreeKernelSpace(memptr); |
} |
return status; |
} |
else |
Address+= 0x80000000; |
switch (Width) |
{ |
case 8: |
*Value = *(UINT8*)Address; |
break; |
case 16: |
*Value = *(UINT16*)Address; |
break; |
case 32: |
*Value = *(UINT32*)Address; |
break; |
default: |
return (AE_BAD_PARAMETER); |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsWriteMemory |
* |
* PARAMETERS: Address - Physical Memory Address to write |
* Value - Value to write |
* Width - Number of bits |
* |
* RETURN: None |
* |
* DESCRIPTION: Write data to a physical memory address |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsWriteMemory ( |
ACPI_PHYSICAL_ADDRESS Address, |
UINT32 Value, |
UINT32 Width) |
{ |
void *memptr; |
ACPI_STATUS status = AE_ERROR; |
// dbgprintf("%s %x, %x\n",__FUNCTION__, Address, Value); |
if( (UINT64)Address+Width > 0x100000000ULL) |
return (AE_BAD_PARAMETER); |
if( Address >= 0x400000) |
{ |
memptr = AcpiOsMapMemory(Address, Width); |
if(memptr) |
{ |
status = AE_OK; |
switch (Width) |
{ |
case 8: |
*(UINT8*)Address = (UINT8)Value; |
break; |
case 16: |
*(UINT16*)Address = (UINT16)Value; |
break; |
case 32: |
*(UINT32*)Address = Value; |
break; |
default: |
status = (AE_BAD_PARAMETER); |
} |
FreeKernelSpace(memptr); |
} |
return status; |
} |
else |
Address+= 0x80000000; |
switch (Width) |
{ |
case 8: |
*(UINT8*)Address = (UINT8)Value; |
break; |
case 16: |
*(UINT16*)Address = (UINT16)Value; |
break; |
case 32: |
*(UINT32*)Address = Value; |
break; |
default: |
return (AE_BAD_PARAMETER); |
} |
return (AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsReadable |
* |
* PARAMETERS: Pointer - Area to be verified |
* Length - Size of area |
* |
* RETURN: TRUE if readable for entire length |
* |
* DESCRIPTION: Verify that a pointer is valid for reading |
* |
*****************************************************************************/ |
BOOLEAN |
AcpiOsReadable ( |
void *Pointer, |
ACPI_SIZE Length) |
{ |
return (TRUE); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsWritable |
* |
* PARAMETERS: Pointer - Area to be verified |
* Length - Size of area |
* |
* RETURN: TRUE if writable for entire length |
* |
* DESCRIPTION: Verify that a pointer is valid for writing |
* |
*****************************************************************************/ |
BOOLEAN |
AcpiOsWritable ( |
void *Pointer, |
ACPI_SIZE Length) |
{ |
return (TRUE); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsGetThreadId |
* |
* PARAMETERS: None |
* |
* RETURN: Id of the running thread |
* |
* DESCRIPTION: Get the Id of the current (running) thread |
* |
* NOTE: The environment header should contain this line: |
* #define ACPI_THREAD_ID pthread_t |
* |
*****************************************************************************/ |
ACPI_THREAD_ID |
AcpiOsGetThreadId (void) |
{ |
return ( 1 ); |
} |
/****************************************************************************** |
* |
* FUNCTION: AcpiOsSignal |
* |
* PARAMETERS: Function - ACPI CA signal function code |
* Info - Pointer to function-dependent structure |
* |
* RETURN: Status |
* |
* DESCRIPTION: Miscellaneous functions. Example implementation only. |
* |
*****************************************************************************/ |
ACPI_STATUS |
AcpiOsSignal ( |
UINT32 Function, |
void *Info) |
{ |
switch (Function) |
{ |
case ACPI_SIGNAL_FATAL: |
break; |
case ACPI_SIGNAL_BREAKPOINT: |
break; |
default: |
break; |
} |
return (AE_OK); |
} |
/drivers/acpi/acpica/psargs.c |
---|
0,0 → 1,876 |
/****************************************************************************** |
* |
* Module Name: psargs - Parse AML opcode arguments |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#include "acnamesp.h" |
#include "acdispat.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psargs") |
/* Local prototypes */ |
static u32 |
acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state); |
static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state |
*parser_state); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_next_package_length |
* |
* PARAMETERS: parser_state - Current parser state object |
* |
* RETURN: Decoded package length. On completion, the AML pointer points |
* past the length byte or bytes. |
* |
* DESCRIPTION: Decode and return a package length field. |
* Note: Largest package length is 28 bits, from ACPI specification |
* |
******************************************************************************/ |
static u32 |
acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state) |
{ |
u8 *aml = parser_state->aml; |
u32 package_length = 0; |
u32 byte_count; |
u8 byte_zero_mask = 0x3F; /* Default [0:5] */ |
ACPI_FUNCTION_TRACE(ps_get_next_package_length); |
/* |
* Byte 0 bits [6:7] contain the number of additional bytes |
* used to encode the package length, either 0,1,2, or 3 |
*/ |
byte_count = (aml[0] >> 6); |
parser_state->aml += ((acpi_size) byte_count + 1); |
/* Get bytes 3, 2, 1 as needed */ |
while (byte_count) { |
/* |
* Final bit positions for the package length bytes: |
* Byte3->[20:27] |
* Byte2->[12:19] |
* Byte1->[04:11] |
* Byte0->[00:03] |
*/ |
package_length |= (aml[byte_count] << ((byte_count << 3) - 4)); |
byte_zero_mask = 0x0F; /* Use bits [0:3] of byte 0 */ |
byte_count--; |
} |
/* Byte 0 is a special case, either bits [0:3] or [0:5] are used */ |
package_length |= (aml[0] & byte_zero_mask); |
return_UINT32(package_length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_next_package_end |
* |
* PARAMETERS: parser_state - Current parser state object |
* |
* RETURN: Pointer to end-of-package +1 |
* |
* DESCRIPTION: Get next package length and return a pointer past the end of |
* the package. Consumes the package length field |
* |
******************************************************************************/ |
u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state) |
{ |
u8 *start = parser_state->aml; |
u32 package_length; |
ACPI_FUNCTION_TRACE(ps_get_next_package_end); |
/* Function below updates parser_state->Aml */ |
package_length = acpi_ps_get_next_package_length(parser_state); |
return_PTR(start + package_length); /* end of package */ |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_next_namestring |
* |
* PARAMETERS: parser_state - Current parser state object |
* |
* RETURN: Pointer to the start of the name string (pointer points into |
* the AML. |
* |
* DESCRIPTION: Get next raw namestring within the AML stream. Handles all name |
* prefix characters. Set parser state to point past the string. |
* (Name is consumed from the AML.) |
* |
******************************************************************************/ |
char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state) |
{ |
u8 *start = parser_state->aml; |
u8 *end = parser_state->aml; |
ACPI_FUNCTION_TRACE(ps_get_next_namestring); |
/* Point past any namestring prefix characters (backslash or carat) */ |
while (ACPI_IS_ROOT_PREFIX(*end) || ACPI_IS_PARENT_PREFIX(*end)) { |
end++; |
} |
/* Decode the path prefix character */ |
switch (*end) { |
case 0: |
/* null_name */ |
if (end == start) { |
start = NULL; |
} |
end++; |
break; |
case AML_DUAL_NAME_PREFIX: |
/* Two name segments */ |
end += 1 + (2 * ACPI_NAME_SIZE); |
break; |
case AML_MULTI_NAME_PREFIX_OP: |
/* Multiple name segments, 4 chars each, count in next byte */ |
end += 2 + (*(end + 1) * ACPI_NAME_SIZE); |
break; |
default: |
/* Single name segment */ |
end += ACPI_NAME_SIZE; |
break; |
} |
parser_state->aml = end; |
return_PTR((char *)start); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_next_namepath |
* |
* PARAMETERS: parser_state - Current parser state object |
* arg - Where the namepath will be stored |
* arg_count - If the namepath points to a control method |
* the method's argument is returned here. |
* possible_method_call - Whether the namepath can possibly be the |
* start of a method call |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get next name (if method call, return # of required args). |
* Names are looked up in the internal namespace to determine |
* if the name represents a control method. If a method |
* is found, the number of arguments to the method is returned. |
* This information is critical for parsing to continue correctly. |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, |
struct acpi_parse_state *parser_state, |
union acpi_parse_object *arg, u8 possible_method_call) |
{ |
acpi_status status; |
char *path; |
union acpi_parse_object *name_op; |
union acpi_operand_object *method_desc; |
struct acpi_namespace_node *node; |
u8 *start = parser_state->aml; |
ACPI_FUNCTION_TRACE(ps_get_next_namepath); |
path = acpi_ps_get_next_namestring(parser_state); |
acpi_ps_init_op(arg, AML_INT_NAMEPATH_OP); |
/* Null path case is allowed, just exit */ |
if (!path) { |
arg->common.value.name = path; |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Lookup the name in the internal namespace, starting with the current |
* scope. We don't want to add anything new to the namespace here, |
* however, so we use MODE_EXECUTE. |
* Allow searching of the parent tree, but don't open a new scope - |
* we just want to lookup the object (must be mode EXECUTE to perform |
* the upsearch) |
*/ |
status = acpi_ns_lookup(walk_state->scope_info, path, |
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, |
ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, |
NULL, &node); |
/* |
* If this name is a control method invocation, we must |
* setup the method call |
*/ |
if (ACPI_SUCCESS(status) && |
possible_method_call && (node->type == ACPI_TYPE_METHOD)) { |
if (walk_state->opcode == AML_UNLOAD_OP) { |
/* |
* acpi_ps_get_next_namestring has increased the AML pointer, |
* so we need to restore the saved AML pointer for method call. |
*/ |
walk_state->parser_state.aml = start; |
walk_state->arg_count = 1; |
acpi_ps_init_op(arg, AML_INT_METHODCALL_OP); |
return_ACPI_STATUS(AE_OK); |
} |
/* This name is actually a control method invocation */ |
method_desc = acpi_ns_get_attached_object(node); |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Control Method - %p Desc %p Path=%p\n", node, |
method_desc, path)); |
name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start); |
if (!name_op) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Change Arg into a METHOD CALL and attach name to it */ |
acpi_ps_init_op(arg, AML_INT_METHODCALL_OP); |
name_op->common.value.name = path; |
/* Point METHODCALL/NAME to the METHOD Node */ |
name_op->common.node = node; |
acpi_ps_append_arg(arg, name_op); |
if (!method_desc) { |
ACPI_ERROR((AE_INFO, |
"Control Method %p has no attached object", |
node)); |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Control Method - %p Args %X\n", |
node, method_desc->method.param_count)); |
/* Get the number of arguments to expect */ |
walk_state->arg_count = method_desc->method.param_count; |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Special handling if the name was not found during the lookup - |
* some not_found cases are allowed |
*/ |
if (status == AE_NOT_FOUND) { |
/* 1) not_found is ok during load pass 1/2 (allow forward references) */ |
if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) != |
ACPI_PARSE_EXECUTE) { |
status = AE_OK; |
} |
/* 2) not_found during a cond_ref_of(x) is ok by definition */ |
else if (walk_state->op->common.aml_opcode == |
AML_COND_REF_OF_OP) { |
status = AE_OK; |
} |
/* |
* 3) not_found while building a Package is ok at this point, we |
* may flag as an error later if slack mode is not enabled. |
* (Some ASL code depends on allowing this behavior) |
*/ |
else if ((arg->common.parent) && |
((arg->common.parent->common.aml_opcode == |
AML_PACKAGE_OP) |
|| (arg->common.parent->common.aml_opcode == |
AML_VAR_PACKAGE_OP))) { |
status = AE_OK; |
} |
} |
/* Final exception check (may have been changed from code above) */ |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR_NAMESPACE(path, status); |
if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == |
ACPI_PARSE_EXECUTE) { |
/* Report a control method execution error */ |
status = acpi_ds_method_error(status, walk_state); |
} |
} |
/* Save the namepath */ |
arg->common.value.name = path; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_next_simple_arg |
* |
* PARAMETERS: parser_state - Current parser state object |
* arg_type - The argument type (AML_*_ARG) |
* arg - Where the argument is returned |
* |
* RETURN: None |
* |
* DESCRIPTION: Get the next simple argument (constant, string, or namestring) |
* |
******************************************************************************/ |
void |
acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, |
u32 arg_type, union acpi_parse_object *arg) |
{ |
u32 length; |
u16 opcode; |
u8 *aml = parser_state->aml; |
ACPI_FUNCTION_TRACE_U32(ps_get_next_simple_arg, arg_type); |
switch (arg_type) { |
case ARGP_BYTEDATA: |
/* Get 1 byte from the AML stream */ |
opcode = AML_BYTE_OP; |
arg->common.value.integer = (u64) *aml; |
length = 1; |
break; |
case ARGP_WORDDATA: |
/* Get 2 bytes from the AML stream */ |
opcode = AML_WORD_OP; |
ACPI_MOVE_16_TO_64(&arg->common.value.integer, aml); |
length = 2; |
break; |
case ARGP_DWORDDATA: |
/* Get 4 bytes from the AML stream */ |
opcode = AML_DWORD_OP; |
ACPI_MOVE_32_TO_64(&arg->common.value.integer, aml); |
length = 4; |
break; |
case ARGP_QWORDDATA: |
/* Get 8 bytes from the AML stream */ |
opcode = AML_QWORD_OP; |
ACPI_MOVE_64_TO_64(&arg->common.value.integer, aml); |
length = 8; |
break; |
case ARGP_CHARLIST: |
/* Get a pointer to the string, point past the string */ |
opcode = AML_STRING_OP; |
arg->common.value.string = ACPI_CAST_PTR(char, aml); |
/* Find the null terminator */ |
length = 0; |
while (aml[length]) { |
length++; |
} |
length++; |
break; |
case ARGP_NAME: |
case ARGP_NAMESTRING: |
acpi_ps_init_op(arg, AML_INT_NAMEPATH_OP); |
arg->common.value.name = |
acpi_ps_get_next_namestring(parser_state); |
return_VOID; |
default: |
ACPI_ERROR((AE_INFO, "Invalid ArgType 0x%X", arg_type)); |
return_VOID; |
} |
acpi_ps_init_op(arg, opcode); |
parser_state->aml += length; |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_next_field |
* |
* PARAMETERS: parser_state - Current parser state object |
* |
* RETURN: A newly allocated FIELD op |
* |
* DESCRIPTION: Get next field (named_field, reserved_field, or access_field) |
* |
******************************************************************************/ |
static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state |
*parser_state) |
{ |
u8 *aml; |
union acpi_parse_object *field; |
union acpi_parse_object *arg = NULL; |
u16 opcode; |
u32 name; |
u8 access_type; |
u8 access_attribute; |
u8 access_length; |
u32 pkg_length; |
u8 *pkg_end; |
u32 buffer_length; |
ACPI_FUNCTION_TRACE(ps_get_next_field); |
aml = parser_state->aml; |
/* Determine field type */ |
switch (ACPI_GET8(parser_state->aml)) { |
case AML_FIELD_OFFSET_OP: |
opcode = AML_INT_RESERVEDFIELD_OP; |
parser_state->aml++; |
break; |
case AML_FIELD_ACCESS_OP: |
opcode = AML_INT_ACCESSFIELD_OP; |
parser_state->aml++; |
break; |
case AML_FIELD_CONNECTION_OP: |
opcode = AML_INT_CONNECTION_OP; |
parser_state->aml++; |
break; |
case AML_FIELD_EXT_ACCESS_OP: |
opcode = AML_INT_EXTACCESSFIELD_OP; |
parser_state->aml++; |
break; |
default: |
opcode = AML_INT_NAMEDFIELD_OP; |
break; |
} |
/* Allocate a new field op */ |
field = acpi_ps_alloc_op(opcode, aml); |
if (!field) { |
return_PTR(NULL); |
} |
/* Decode the field type */ |
switch (opcode) { |
case AML_INT_NAMEDFIELD_OP: |
/* Get the 4-character name */ |
ACPI_MOVE_32_TO_32(&name, parser_state->aml); |
acpi_ps_set_name(field, name); |
parser_state->aml += ACPI_NAME_SIZE; |
/* Get the length which is encoded as a package length */ |
field->common.value.size = |
acpi_ps_get_next_package_length(parser_state); |
break; |
case AML_INT_RESERVEDFIELD_OP: |
/* Get the length which is encoded as a package length */ |
field->common.value.size = |
acpi_ps_get_next_package_length(parser_state); |
break; |
case AML_INT_ACCESSFIELD_OP: |
case AML_INT_EXTACCESSFIELD_OP: |
/* |
* Get access_type and access_attrib and merge into the field Op |
* access_type is first operand, access_attribute is second. stuff |
* these bytes into the node integer value for convenience. |
*/ |
/* Get the two bytes (Type/Attribute) */ |
access_type = ACPI_GET8(parser_state->aml); |
parser_state->aml++; |
access_attribute = ACPI_GET8(parser_state->aml); |
parser_state->aml++; |
field->common.value.integer = (u8)access_type; |
field->common.value.integer |= (u16)(access_attribute << 8); |
/* This opcode has a third byte, access_length */ |
if (opcode == AML_INT_EXTACCESSFIELD_OP) { |
access_length = ACPI_GET8(parser_state->aml); |
parser_state->aml++; |
field->common.value.integer |= |
(u32)(access_length << 16); |
} |
break; |
case AML_INT_CONNECTION_OP: |
/* |
* Argument for Connection operator can be either a Buffer |
* (resource descriptor), or a name_string. |
*/ |
aml = parser_state->aml; |
if (ACPI_GET8(parser_state->aml) == AML_BUFFER_OP) { |
parser_state->aml++; |
pkg_end = parser_state->aml; |
pkg_length = |
acpi_ps_get_next_package_length(parser_state); |
pkg_end += pkg_length; |
if (parser_state->aml < pkg_end) { |
/* Non-empty list */ |
arg = |
acpi_ps_alloc_op(AML_INT_BYTELIST_OP, aml); |
if (!arg) { |
acpi_ps_free_op(field); |
return_PTR(NULL); |
} |
/* Get the actual buffer length argument */ |
opcode = ACPI_GET8(parser_state->aml); |
parser_state->aml++; |
switch (opcode) { |
case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ |
buffer_length = |
ACPI_GET8(parser_state->aml); |
parser_state->aml += 1; |
break; |
case AML_WORD_OP: /* AML_WORDDATA_ARG */ |
buffer_length = |
ACPI_GET16(parser_state->aml); |
parser_state->aml += 2; |
break; |
case AML_DWORD_OP: /* AML_DWORDATA_ARG */ |
buffer_length = |
ACPI_GET32(parser_state->aml); |
parser_state->aml += 4; |
break; |
default: |
buffer_length = 0; |
break; |
} |
/* Fill in bytelist data */ |
arg->named.value.size = buffer_length; |
arg->named.data = parser_state->aml; |
} |
/* Skip to End of byte data */ |
parser_state->aml = pkg_end; |
} else { |
arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, aml); |
if (!arg) { |
acpi_ps_free_op(field); |
return_PTR(NULL); |
} |
/* Get the Namestring argument */ |
arg->common.value.name = |
acpi_ps_get_next_namestring(parser_state); |
} |
/* Link the buffer/namestring to parent (CONNECTION_OP) */ |
acpi_ps_append_arg(field, arg); |
break; |
default: |
/* Opcode was set in previous switch */ |
break; |
} |
return_PTR(field); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_next_arg |
* |
* PARAMETERS: walk_state - Current state |
* parser_state - Current parser state object |
* arg_type - The argument type (AML_*_ARG) |
* return_arg - Where the next arg is returned |
* |
* RETURN: Status, and an op object containing the next argument. |
* |
* DESCRIPTION: Get next argument (including complex list arguments that require |
* pushing the parser stack) |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, |
struct acpi_parse_state *parser_state, |
u32 arg_type, union acpi_parse_object **return_arg) |
{ |
union acpi_parse_object *arg = NULL; |
union acpi_parse_object *prev = NULL; |
union acpi_parse_object *field; |
u32 subop; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state); |
switch (arg_type) { |
case ARGP_BYTEDATA: |
case ARGP_WORDDATA: |
case ARGP_DWORDDATA: |
case ARGP_CHARLIST: |
case ARGP_NAME: |
case ARGP_NAMESTRING: |
/* Constants, strings, and namestrings are all the same size */ |
arg = acpi_ps_alloc_op(AML_BYTE_OP, parser_state->aml); |
if (!arg) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
acpi_ps_get_next_simple_arg(parser_state, arg_type, arg); |
break; |
case ARGP_PKGLENGTH: |
/* Package length, nothing returned */ |
parser_state->pkg_end = |
acpi_ps_get_next_package_end(parser_state); |
break; |
case ARGP_FIELDLIST: |
if (parser_state->aml < parser_state->pkg_end) { |
/* Non-empty list */ |
while (parser_state->aml < parser_state->pkg_end) { |
field = acpi_ps_get_next_field(parser_state); |
if (!field) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
if (prev) { |
prev->common.next = field; |
} else { |
arg = field; |
} |
prev = field; |
} |
/* Skip to End of byte data */ |
parser_state->aml = parser_state->pkg_end; |
} |
break; |
case ARGP_BYTELIST: |
if (parser_state->aml < parser_state->pkg_end) { |
/* Non-empty list */ |
arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP, |
parser_state->aml); |
if (!arg) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Fill in bytelist data */ |
arg->common.value.size = (u32) |
ACPI_PTR_DIFF(parser_state->pkg_end, |
parser_state->aml); |
arg->named.data = parser_state->aml; |
/* Skip to End of byte data */ |
parser_state->aml = parser_state->pkg_end; |
} |
break; |
case ARGP_TARGET: |
case ARGP_SUPERNAME: |
case ARGP_SIMPLENAME: |
subop = acpi_ps_peek_opcode(parser_state); |
if (subop == 0 || |
acpi_ps_is_leading_char(subop) || |
ACPI_IS_ROOT_PREFIX(subop) || |
ACPI_IS_PARENT_PREFIX(subop)) { |
/* null_name or name_string */ |
arg = |
acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, |
parser_state->aml); |
if (!arg) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* To support super_name arg of Unload */ |
if (walk_state->opcode == AML_UNLOAD_OP) { |
status = |
acpi_ps_get_next_namepath(walk_state, |
parser_state, arg, |
1); |
/* |
* If the super_name arg of Unload is a method call, |
* we have restored the AML pointer, just free this Arg |
*/ |
if (arg->common.aml_opcode == |
AML_INT_METHODCALL_OP) { |
acpi_ps_free_op(arg); |
arg = NULL; |
} |
} else { |
status = |
acpi_ps_get_next_namepath(walk_state, |
parser_state, arg, |
0); |
} |
} else { |
/* Single complex argument, nothing returned */ |
walk_state->arg_count = 1; |
} |
break; |
case ARGP_DATAOBJ: |
case ARGP_TERMARG: |
/* Single complex argument, nothing returned */ |
walk_state->arg_count = 1; |
break; |
case ARGP_DATAOBJLIST: |
case ARGP_TERMLIST: |
case ARGP_OBJLIST: |
if (parser_state->aml < parser_state->pkg_end) { |
/* Non-empty list of variable arguments, nothing returned */ |
walk_state->arg_count = ACPI_VAR_ARGS; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Invalid ArgType: 0x%X", arg_type)); |
status = AE_AML_OPERAND_TYPE; |
break; |
} |
*return_arg = arg; |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/psloop.c |
---|
0,0 → 1,626 |
/****************************************************************************** |
* |
* Module Name: psloop - Main AML parse loop |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
/* |
* Parse the AML and build an operation tree as most interpreters, (such as |
* Perl) do. Parsing is done by hand rather than with a YACC generated parser |
* to tightly constrain stack and dynamic memory usage. Parsing is kept |
* flexible and the code fairly compact by parsing based on a list of AML |
* opcode templates in aml_op_info[]. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "acparser.h" |
#include "acdispat.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psloop") |
/* Local prototypes */ |
static acpi_status |
acpi_ps_get_arguments(struct acpi_walk_state *walk_state, |
u8 * aml_op_start, union acpi_parse_object *op); |
static void |
acpi_ps_link_module_code(union acpi_parse_object *parent_op, |
u8 *aml_start, u32 aml_length, acpi_owner_id owner_id); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_arguments |
* |
* PARAMETERS: walk_state - Current state |
* aml_op_start - Op start in AML |
* op - Current Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get arguments for passed Op. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ps_get_arguments(struct acpi_walk_state *walk_state, |
u8 * aml_op_start, union acpi_parse_object *op) |
{ |
acpi_status status = AE_OK; |
union acpi_parse_object *arg = NULL; |
const struct acpi_opcode_info *op_info; |
ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); |
switch (op->common.aml_opcode) { |
case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ |
case AML_WORD_OP: /* AML_WORDDATA_ARG */ |
case AML_DWORD_OP: /* AML_DWORDATA_ARG */ |
case AML_QWORD_OP: /* AML_QWORDATA_ARG */ |
case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ |
/* Fill in constant or string argument directly */ |
acpi_ps_get_next_simple_arg(&(walk_state->parser_state), |
GET_CURRENT_ARG_TYPE(walk_state-> |
arg_types), |
op); |
break; |
case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ |
status = |
acpi_ps_get_next_namepath(walk_state, |
&(walk_state->parser_state), op, |
1); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
walk_state->arg_types = 0; |
break; |
default: |
/* |
* Op is not a constant or string, append each argument to the Op |
*/ |
while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) |
&& !walk_state->arg_count) { |
walk_state->aml = walk_state->parser_state.aml; |
status = |
acpi_ps_get_next_arg(walk_state, |
&(walk_state->parser_state), |
GET_CURRENT_ARG_TYPE |
(walk_state->arg_types), &arg); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (arg) { |
acpi_ps_append_arg(op, arg); |
} |
INCREMENT_ARG_LIST(walk_state->arg_types); |
} |
/* |
* Handle executable code at "module-level". This refers to |
* executable opcodes that appear outside of any control method. |
*/ |
if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) && |
((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { |
/* |
* We want to skip If/Else/While constructs during Pass1 because we |
* want to actually conditionally execute the code during Pass2. |
* |
* Except for disassembly, where we always want to walk the |
* If/Else/While packages |
*/ |
switch (op->common.aml_opcode) { |
case AML_IF_OP: |
case AML_ELSE_OP: |
case AML_WHILE_OP: |
/* |
* Currently supported module-level opcodes are: |
* IF/ELSE/WHILE. These appear to be the most common, |
* and easiest to support since they open an AML |
* package. |
*/ |
if (walk_state->pass_number == |
ACPI_IMODE_LOAD_PASS1) { |
acpi_ps_link_module_code(op->common. |
parent, |
aml_op_start, |
(u32) |
(walk_state-> |
parser_state. |
pkg_end - |
aml_op_start), |
walk_state-> |
owner_id); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Pass1: Skipping an If/Else/While body\n")); |
/* Skip body of if/else/while in pass 1 */ |
walk_state->parser_state.aml = |
walk_state->parser_state.pkg_end; |
walk_state->arg_count = 0; |
break; |
default: |
/* |
* Check for an unsupported executable opcode at module |
* level. We must be in PASS1, the parent must be a SCOPE, |
* The opcode class must be EXECUTE, and the opcode must |
* not be an argument to another opcode. |
*/ |
if ((walk_state->pass_number == |
ACPI_IMODE_LOAD_PASS1) |
&& (op->common.parent->common.aml_opcode == |
AML_SCOPE_OP)) { |
op_info = |
acpi_ps_get_opcode_info(op->common. |
aml_opcode); |
if ((op_info->class == |
AML_CLASS_EXECUTE) && (!arg)) { |
ACPI_WARNING((AE_INFO, |
"Unsupported module-level executable opcode " |
"0x%.2X at table offset 0x%.4X", |
op->common. |
aml_opcode, |
(u32) |
(ACPI_PTR_DIFF |
(aml_op_start, |
walk_state-> |
parser_state. |
aml_start) + |
sizeof(struct |
acpi_table_header)))); |
} |
} |
break; |
} |
} |
/* Special processing for certain opcodes */ |
switch (op->common.aml_opcode) { |
case AML_METHOD_OP: |
/* |
* Skip parsing of control method because we don't have enough |
* info in the first pass to parse it correctly. |
* |
* Save the length and address of the body |
*/ |
op->named.data = walk_state->parser_state.aml; |
op->named.length = (u32) |
(walk_state->parser_state.pkg_end - |
walk_state->parser_state.aml); |
/* Skip body of method */ |
walk_state->parser_state.aml = |
walk_state->parser_state.pkg_end; |
walk_state->arg_count = 0; |
break; |
case AML_BUFFER_OP: |
case AML_PACKAGE_OP: |
case AML_VAR_PACKAGE_OP: |
if ((op->common.parent) && |
(op->common.parent->common.aml_opcode == |
AML_NAME_OP) |
&& (walk_state->pass_number <= |
ACPI_IMODE_LOAD_PASS2)) { |
/* |
* Skip parsing of Buffers and Packages because we don't have |
* enough info in the first pass to parse them correctly. |
*/ |
op->named.data = aml_op_start; |
op->named.length = (u32) |
(walk_state->parser_state.pkg_end - |
aml_op_start); |
/* Skip body */ |
walk_state->parser_state.aml = |
walk_state->parser_state.pkg_end; |
walk_state->arg_count = 0; |
} |
break; |
case AML_WHILE_OP: |
if (walk_state->control_state) { |
walk_state->control_state->control.package_end = |
walk_state->parser_state.pkg_end; |
} |
break; |
default: |
/* No action for all other opcodes */ |
break; |
} |
break; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_link_module_code |
* |
* PARAMETERS: parent_op - Parent parser op |
* aml_start - Pointer to the AML |
* aml_length - Length of executable AML |
* owner_id - owner_id of module level code |
* |
* RETURN: None. |
* |
* DESCRIPTION: Wrap the module-level code with a method object and link the |
* object to the global list. Note, the mutex field of the method |
* object is used to link multiple module-level code objects. |
* |
******************************************************************************/ |
static void |
acpi_ps_link_module_code(union acpi_parse_object *parent_op, |
u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) |
{ |
union acpi_operand_object *prev; |
union acpi_operand_object *next; |
union acpi_operand_object *method_obj; |
struct acpi_namespace_node *parent_node; |
ACPI_FUNCTION_TRACE(ps_link_module_code); |
/* Get the tail of the list */ |
prev = next = acpi_gbl_module_code_list; |
while (next) { |
prev = next; |
next = next->method.mutex; |
} |
/* |
* Insert the module level code into the list. Merge it if it is |
* adjacent to the previous element. |
*/ |
if (!prev || |
((prev->method.aml_start + prev->method.aml_length) != aml_start)) { |
/* Create, initialize, and link a new temporary method object */ |
method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); |
if (!method_obj) { |
return_VOID; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Create/Link new code block: %p\n", |
method_obj)); |
if (parent_op->common.node) { |
parent_node = parent_op->common.node; |
} else { |
parent_node = acpi_gbl_root_node; |
} |
method_obj->method.aml_start = aml_start; |
method_obj->method.aml_length = aml_length; |
method_obj->method.owner_id = owner_id; |
method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL; |
/* |
* Save the parent node in next_object. This is cheating, but we |
* don't want to expand the method object. |
*/ |
method_obj->method.next_object = |
ACPI_CAST_PTR(union acpi_operand_object, parent_node); |
if (!prev) { |
acpi_gbl_module_code_list = method_obj; |
} else { |
prev->method.mutex = method_obj; |
} |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Appending to existing code block: %p\n", |
prev)); |
prev->method.aml_length += aml_length; |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_parse_loop |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Parse AML (pointed to by the current parser state) and return |
* a tree of ops. |
* |
******************************************************************************/ |
acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
union acpi_parse_object *op = NULL; /* current op */ |
struct acpi_parse_state *parser_state; |
u8 *aml_op_start = NULL; |
ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); |
if (walk_state->descending_callback == NULL) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
parser_state = &walk_state->parser_state; |
walk_state->arg_types = 0; |
#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) |
if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { |
/* We are restarting a preempted control method */ |
if (acpi_ps_has_completed_scope(parser_state)) { |
/* |
* We must check if a predicate to an IF or WHILE statement |
* was just completed |
*/ |
if ((parser_state->scope->parse_scope.op) && |
((parser_state->scope->parse_scope.op->common. |
aml_opcode == AML_IF_OP) |
|| (parser_state->scope->parse_scope.op->common. |
aml_opcode == AML_WHILE_OP)) |
&& (walk_state->control_state) |
&& (walk_state->control_state->common.state == |
ACPI_CONTROL_PREDICATE_EXECUTING)) { |
/* |
* A predicate was just completed, get the value of the |
* predicate and branch based on that value |
*/ |
walk_state->op = NULL; |
status = |
acpi_ds_get_predicate_value(walk_state, |
ACPI_TO_POINTER |
(TRUE)); |
if (ACPI_FAILURE(status) |
&& ((status & AE_CODE_MASK) != |
AE_CODE_CONTROL)) { |
if (status == AE_AML_NO_RETURN_VALUE) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Invoked method did not return a value")); |
} |
ACPI_EXCEPTION((AE_INFO, status, |
"GetPredicate Failed")); |
return_ACPI_STATUS(status); |
} |
status = |
acpi_ps_next_parse_state(walk_state, op, |
status); |
} |
acpi_ps_pop_scope(parser_state, &op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Popped scope, Op=%p\n", op)); |
} else if (walk_state->prev_op) { |
/* We were in the middle of an op */ |
op = walk_state->prev_op; |
walk_state->arg_types = walk_state->prev_arg_types; |
} |
} |
#endif |
/* Iterative parsing loop, while there is more AML to process: */ |
while ((parser_state->aml < parser_state->aml_end) || (op)) { |
aml_op_start = parser_state->aml; |
if (!op) { |
status = |
acpi_ps_create_op(walk_state, aml_op_start, &op); |
if (ACPI_FAILURE(status)) { |
if (status == AE_CTRL_PARSE_CONTINUE) { |
continue; |
} |
if (status == AE_CTRL_PARSE_PENDING) { |
status = AE_OK; |
} |
if (status == AE_CTRL_TERMINATE) { |
return_ACPI_STATUS(status); |
} |
status = |
acpi_ps_complete_op(walk_state, &op, |
status); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
continue; |
} |
acpi_ex_start_trace_opcode(op, walk_state); |
} |
/* |
* Start arg_count at zero because we don't know if there are |
* any args yet |
*/ |
walk_state->arg_count = 0; |
/* Are there any arguments that must be processed? */ |
if (walk_state->arg_types) { |
/* Get arguments */ |
status = |
acpi_ps_get_arguments(walk_state, aml_op_start, op); |
if (ACPI_FAILURE(status)) { |
status = |
acpi_ps_complete_op(walk_state, &op, |
status); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
continue; |
} |
} |
/* Check for arguments that need to be processed */ |
if (walk_state->arg_count) { |
/* |
* There are arguments (complex ones), push Op and |
* prepare for argument |
*/ |
status = acpi_ps_push_scope(parser_state, op, |
walk_state->arg_types, |
walk_state->arg_count); |
if (ACPI_FAILURE(status)) { |
status = |
acpi_ps_complete_op(walk_state, &op, |
status); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
continue; |
} |
op = NULL; |
continue; |
} |
/* |
* All arguments have been processed -- Op is complete, |
* prepare for next |
*/ |
walk_state->op_info = |
acpi_ps_get_opcode_info(op->common.aml_opcode); |
if (walk_state->op_info->flags & AML_NAMED) { |
if (op->common.aml_opcode == AML_REGION_OP || |
op->common.aml_opcode == AML_DATA_REGION_OP) { |
/* |
* Skip parsing of control method or opregion body, |
* because we don't have enough info in the first pass |
* to parse them correctly. |
* |
* Completed parsing an op_region declaration, we now |
* know the length. |
*/ |
op->named.length = |
(u32) (parser_state->aml - op->named.data); |
} |
} |
if (walk_state->op_info->flags & AML_CREATE) { |
/* |
* Backup to beginning of create_XXXfield declaration (1 for |
* Opcode) |
* |
* body_length is unknown until we parse the body |
*/ |
op->named.length = |
(u32) (parser_state->aml - op->named.data); |
} |
if (op->common.aml_opcode == AML_BANK_FIELD_OP) { |
/* |
* Backup to beginning of bank_field declaration |
* |
* body_length is unknown until we parse the body |
*/ |
op->named.length = |
(u32) (parser_state->aml - op->named.data); |
} |
/* This op complete, notify the dispatcher */ |
if (walk_state->ascending_callback != NULL) { |
walk_state->op = op; |
walk_state->opcode = op->common.aml_opcode; |
status = walk_state->ascending_callback(walk_state); |
status = |
acpi_ps_next_parse_state(walk_state, op, status); |
if (status == AE_CTRL_PENDING) { |
status = AE_OK; |
} |
} |
status = acpi_ps_complete_op(walk_state, &op, status); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} /* while parser_state->Aml */ |
status = acpi_ps_complete_final_op(walk_state, op, status); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/psobject.c |
---|
0,0 → 1,654 |
/****************************************************************************** |
* |
* Module Name: psobject - Support for parse objects |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psobject") |
/* Local prototypes */ |
static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_aml_opcode |
* |
* PARAMETERS: walk_state - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Extract the next AML opcode from the input stream. |
* |
******************************************************************************/ |
static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) |
{ |
u32 aml_offset; |
ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); |
walk_state->aml = walk_state->parser_state.aml; |
walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); |
/* |
* First cut to determine what we have found: |
* 1) A valid AML opcode |
* 2) A name string |
* 3) An unknown/invalid opcode |
*/ |
walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); |
switch (walk_state->op_info->class) { |
case AML_CLASS_ASCII: |
case AML_CLASS_PREFIX: |
/* |
* Starts with a valid prefix or ASCII char, this is a name |
* string. Convert the bare name string to a namepath. |
*/ |
walk_state->opcode = AML_INT_NAMEPATH_OP; |
walk_state->arg_types = ARGP_NAMESTRING; |
break; |
case AML_CLASS_UNKNOWN: |
/* The opcode is unrecognized. Complain and skip unknown opcodes */ |
if (walk_state->pass_number == 2) { |
aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml, |
walk_state-> |
parser_state.aml_start); |
ACPI_ERROR((AE_INFO, |
"Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", |
walk_state->opcode, |
(u32)(aml_offset + |
sizeof(struct acpi_table_header)))); |
ACPI_DUMP_BUFFER((walk_state->parser_state.aml - 16), |
48); |
#ifdef ACPI_ASL_COMPILER |
/* |
* This is executed for the disassembler only. Output goes |
* to the disassembled ASL output file. |
*/ |
acpi_os_printf |
("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", |
walk_state->opcode, |
(u32)(aml_offset + |
sizeof(struct acpi_table_header))); |
/* Dump the context surrounding the invalid opcode */ |
acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. |
aml - 16), 48, DB_BYTE_DISPLAY, |
(aml_offset + |
sizeof(struct acpi_table_header) - |
16)); |
acpi_os_printf(" */\n"); |
#endif |
} |
/* Increment past one-byte or two-byte opcode */ |
walk_state->parser_state.aml++; |
if (walk_state->opcode > 0xFF) { /* Can only happen if first byte is 0x5B */ |
walk_state->parser_state.aml++; |
} |
return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); |
default: |
/* Found opcode info, this is a normal opcode */ |
walk_state->parser_state.aml += |
acpi_ps_get_opcode_size(walk_state->opcode); |
walk_state->arg_types = walk_state->op_info->parse_args; |
break; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_build_named_op |
* |
* PARAMETERS: walk_state - Current state |
* aml_op_start - Begin of named Op in AML |
* unnamed_op - Early Op (not a named Op) |
* op - Returned Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Parse a named Op |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_build_named_op(struct acpi_walk_state *walk_state, |
u8 *aml_op_start, |
union acpi_parse_object *unnamed_op, |
union acpi_parse_object **op) |
{ |
acpi_status status = AE_OK; |
union acpi_parse_object *arg = NULL; |
ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); |
unnamed_op->common.value.arg = NULL; |
unnamed_op->common.arg_list_length = 0; |
unnamed_op->common.aml_opcode = walk_state->opcode; |
/* |
* Get and append arguments until we find the node that contains |
* the name (the type ARGP_NAME). |
*/ |
while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && |
(GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { |
status = |
acpi_ps_get_next_arg(walk_state, |
&(walk_state->parser_state), |
GET_CURRENT_ARG_TYPE(walk_state-> |
arg_types), &arg); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_ps_append_arg(unnamed_op, arg); |
INCREMENT_ARG_LIST(walk_state->arg_types); |
} |
/* |
* Make sure that we found a NAME and didn't run out of arguments |
*/ |
if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { |
return_ACPI_STATUS(AE_AML_NO_OPERAND); |
} |
/* We know that this arg is a name, move to next arg */ |
INCREMENT_ARG_LIST(walk_state->arg_types); |
/* |
* Find the object. This will either insert the object into |
* the namespace or simply look it up |
*/ |
walk_state->op = NULL; |
status = walk_state->descending_callback(walk_state, op); |
if (ACPI_FAILURE(status)) { |
if (status != AE_CTRL_TERMINATE) { |
ACPI_EXCEPTION((AE_INFO, status, |
"During name lookup/catalog")); |
} |
return_ACPI_STATUS(status); |
} |
if (!*op) { |
return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); |
} |
status = acpi_ps_next_parse_state(walk_state, *op, status); |
if (ACPI_FAILURE(status)) { |
if (status == AE_CTRL_PENDING) { |
status = AE_CTRL_PARSE_PENDING; |
} |
return_ACPI_STATUS(status); |
} |
acpi_ps_append_arg(*op, unnamed_op->common.value.arg); |
if ((*op)->common.aml_opcode == AML_REGION_OP || |
(*op)->common.aml_opcode == AML_DATA_REGION_OP) { |
/* |
* Defer final parsing of an operation_region body, because we don't |
* have enough info in the first pass to parse it correctly (i.e., |
* there may be method calls within the term_arg elements of the body.) |
* |
* However, we must continue parsing because the opregion is not a |
* standalone package -- we don't know where the end is at this point. |
* |
* (Length is unknown until parse of the body complete) |
*/ |
(*op)->named.data = aml_op_start; |
(*op)->named.length = 0; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_create_op |
* |
* PARAMETERS: walk_state - Current state |
* aml_op_start - Op start in AML |
* new_op - Returned Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get Op from AML |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_create_op(struct acpi_walk_state *walk_state, |
u8 *aml_op_start, union acpi_parse_object **new_op) |
{ |
acpi_status status = AE_OK; |
union acpi_parse_object *op; |
union acpi_parse_object *named_op = NULL; |
union acpi_parse_object *parent_scope; |
u8 argument_count; |
const struct acpi_opcode_info *op_info; |
ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); |
status = acpi_ps_get_aml_opcode(walk_state); |
if (status == AE_CTRL_PARSE_CONTINUE) { |
return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); |
} |
/* Create Op structure and append to parent's argument list */ |
walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); |
op = acpi_ps_alloc_op(walk_state->opcode, aml_op_start); |
if (!op) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
if (walk_state->op_info->flags & AML_NAMED) { |
status = |
acpi_ps_build_named_op(walk_state, aml_op_start, op, |
&named_op); |
acpi_ps_free_op(op); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
*new_op = named_op; |
return_ACPI_STATUS(AE_OK); |
} |
/* Not a named opcode, just allocate Op and append to parent */ |
if (walk_state->op_info->flags & AML_CREATE) { |
/* |
* Backup to beginning of create_XXXfield declaration |
* body_length is unknown until we parse the body |
*/ |
op->named.data = aml_op_start; |
op->named.length = 0; |
} |
if (walk_state->opcode == AML_BANK_FIELD_OP) { |
/* |
* Backup to beginning of bank_field declaration |
* body_length is unknown until we parse the body |
*/ |
op->named.data = aml_op_start; |
op->named.length = 0; |
} |
parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state)); |
acpi_ps_append_arg(parent_scope, op); |
if (parent_scope) { |
op_info = |
acpi_ps_get_opcode_info(parent_scope->common.aml_opcode); |
if (op_info->flags & AML_HAS_TARGET) { |
argument_count = |
acpi_ps_get_argument_count(op_info->type); |
if (parent_scope->common.arg_list_length > |
argument_count) { |
op->common.flags |= ACPI_PARSEOP_TARGET; |
} |
} else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { |
op->common.flags |= ACPI_PARSEOP_TARGET; |
} |
} |
if (walk_state->descending_callback != NULL) { |
/* |
* Find the object. This will either insert the object into |
* the namespace or simply look it up |
*/ |
walk_state->op = *new_op = op; |
status = walk_state->descending_callback(walk_state, &op); |
status = acpi_ps_next_parse_state(walk_state, op, status); |
if (status == AE_CTRL_PENDING) { |
status = AE_CTRL_PARSE_PENDING; |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_complete_op |
* |
* PARAMETERS: walk_state - Current state |
* op - Returned Op |
* status - Parse status before complete Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Complete Op |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_complete_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object **op, acpi_status status) |
{ |
acpi_status status2; |
ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state); |
/* |
* Finished one argument of the containing scope |
*/ |
walk_state->parser_state.scope->parse_scope.arg_count--; |
/* Close this Op (will result in parse subtree deletion) */ |
status2 = acpi_ps_complete_this_op(walk_state, *op); |
if (ACPI_FAILURE(status2)) { |
return_ACPI_STATUS(status2); |
} |
*op = NULL; |
switch (status) { |
case AE_OK: |
break; |
case AE_CTRL_TRANSFER: |
/* We are about to transfer to a called method */ |
walk_state->prev_op = NULL; |
walk_state->prev_arg_types = walk_state->arg_types; |
return_ACPI_STATUS(status); |
case AE_CTRL_END: |
acpi_ps_pop_scope(&(walk_state->parser_state), op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
if (*op) { |
walk_state->op = *op; |
walk_state->op_info = |
acpi_ps_get_opcode_info((*op)->common.aml_opcode); |
walk_state->opcode = (*op)->common.aml_opcode; |
status = walk_state->ascending_callback(walk_state); |
status = |
acpi_ps_next_parse_state(walk_state, *op, status); |
status2 = acpi_ps_complete_this_op(walk_state, *op); |
if (ACPI_FAILURE(status2)) { |
return_ACPI_STATUS(status2); |
} |
} |
status = AE_OK; |
break; |
case AE_CTRL_BREAK: |
case AE_CTRL_CONTINUE: |
/* Pop off scopes until we find the While */ |
while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) { |
acpi_ps_pop_scope(&(walk_state->parser_state), op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
} |
/* Close this iteration of the While loop */ |
walk_state->op = *op; |
walk_state->op_info = |
acpi_ps_get_opcode_info((*op)->common.aml_opcode); |
walk_state->opcode = (*op)->common.aml_opcode; |
status = walk_state->ascending_callback(walk_state); |
status = acpi_ps_next_parse_state(walk_state, *op, status); |
status2 = acpi_ps_complete_this_op(walk_state, *op); |
if (ACPI_FAILURE(status2)) { |
return_ACPI_STATUS(status2); |
} |
status = AE_OK; |
break; |
case AE_CTRL_TERMINATE: |
/* Clean up */ |
do { |
if (*op) { |
status2 = |
acpi_ps_complete_this_op(walk_state, *op); |
if (ACPI_FAILURE(status2)) { |
return_ACPI_STATUS(status2); |
} |
acpi_ut_delete_generic_state |
(acpi_ut_pop_generic_state |
(&walk_state->control_state)); |
} |
acpi_ps_pop_scope(&(walk_state->parser_state), op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
} while (*op); |
return_ACPI_STATUS(AE_OK); |
default: /* All other non-AE_OK status */ |
do { |
if (*op) { |
status2 = |
acpi_ps_complete_this_op(walk_state, *op); |
if (ACPI_FAILURE(status2)) { |
return_ACPI_STATUS(status2); |
} |
} |
acpi_ps_pop_scope(&(walk_state->parser_state), op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
} while (*op); |
#if 0 |
/* |
* TBD: Cleanup parse ops on error |
*/ |
if (*op == NULL) { |
acpi_ps_pop_scope(parser_state, op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
} |
#endif |
walk_state->prev_op = NULL; |
walk_state->prev_arg_types = walk_state->arg_types; |
return_ACPI_STATUS(status); |
} |
/* This scope complete? */ |
if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) { |
acpi_ps_pop_scope(&(walk_state->parser_state), op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op)); |
} else { |
*op = NULL; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_complete_final_op |
* |
* PARAMETERS: walk_state - Current state |
* op - Current Op |
* status - Current parse status before complete last |
* Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Complete last Op. |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, acpi_status status) |
{ |
acpi_status status2; |
ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); |
/* |
* Complete the last Op (if not completed), and clear the scope stack. |
* It is easily possible to end an AML "package" with an unbounded number |
* of open scopes (such as when several ASL blocks are closed with |
* sequential closing braces). We want to terminate each one cleanly. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n", |
op)); |
do { |
if (op) { |
if (walk_state->ascending_callback != NULL) { |
walk_state->op = op; |
walk_state->op_info = |
acpi_ps_get_opcode_info(op->common. |
aml_opcode); |
walk_state->opcode = op->common.aml_opcode; |
status = |
walk_state->ascending_callback(walk_state); |
status = |
acpi_ps_next_parse_state(walk_state, op, |
status); |
if (status == AE_CTRL_PENDING) { |
status = |
acpi_ps_complete_op(walk_state, &op, |
AE_OK); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
if (status == AE_CTRL_TERMINATE) { |
status = AE_OK; |
/* Clean up */ |
do { |
if (op) { |
status2 = |
acpi_ps_complete_this_op |
(walk_state, op); |
if (ACPI_FAILURE |
(status2)) { |
return_ACPI_STATUS |
(status2); |
} |
} |
acpi_ps_pop_scope(& |
(walk_state-> |
parser_state), |
&op, |
&walk_state-> |
arg_types, |
&walk_state-> |
arg_count); |
} while (op); |
return_ACPI_STATUS(status); |
} |
else if (ACPI_FAILURE(status)) { |
/* First error is most important */ |
(void) |
acpi_ps_complete_this_op(walk_state, |
op); |
return_ACPI_STATUS(status); |
} |
} |
status2 = acpi_ps_complete_this_op(walk_state, op); |
if (ACPI_FAILURE(status2)) { |
return_ACPI_STATUS(status2); |
} |
} |
acpi_ps_pop_scope(&(walk_state->parser_state), &op, |
&walk_state->arg_types, |
&walk_state->arg_count); |
} while (op); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/psopcode.c |
---|
0,0 → 1,658 |
/****************************************************************************** |
* |
* Module Name: psopcode - Parser/Interpreter opcode information table |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acopcode.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psopcode") |
/******************************************************************************* |
* |
* NAME: acpi_gbl_aml_op_info |
* |
* DESCRIPTION: Opcode table. Each entry contains <opcode, type, name, operands> |
* The name is a simple ascii string, the operand specifier is an |
* ascii string with one letter per operand. The letter specifies |
* the operand type. |
* |
******************************************************************************/ |
/* |
* Summary of opcode types/flags |
* |
Opcodes that have associated namespace objects (AML_NSOBJECT flag) |
AML_SCOPE_OP |
AML_DEVICE_OP |
AML_THERMAL_ZONE_OP |
AML_METHOD_OP |
AML_POWER_RES_OP |
AML_PROCESSOR_OP |
AML_FIELD_OP |
AML_INDEX_FIELD_OP |
AML_BANK_FIELD_OP |
AML_NAME_OP |
AML_ALIAS_OP |
AML_MUTEX_OP |
AML_EVENT_OP |
AML_REGION_OP |
AML_CREATE_FIELD_OP |
AML_CREATE_BIT_FIELD_OP |
AML_CREATE_BYTE_FIELD_OP |
AML_CREATE_WORD_FIELD_OP |
AML_CREATE_DWORD_FIELD_OP |
AML_CREATE_QWORD_FIELD_OP |
AML_INT_NAMEDFIELD_OP |
AML_INT_METHODCALL_OP |
AML_INT_NAMEPATH_OP |
Opcodes that are "namespace" opcodes (AML_NSOPCODE flag) |
AML_SCOPE_OP |
AML_DEVICE_OP |
AML_THERMAL_ZONE_OP |
AML_METHOD_OP |
AML_POWER_RES_OP |
AML_PROCESSOR_OP |
AML_FIELD_OP |
AML_INDEX_FIELD_OP |
AML_BANK_FIELD_OP |
AML_NAME_OP |
AML_ALIAS_OP |
AML_MUTEX_OP |
AML_EVENT_OP |
AML_REGION_OP |
AML_INT_NAMEDFIELD_OP |
Opcodes that have an associated namespace node (AML_NSNODE flag) |
AML_SCOPE_OP |
AML_DEVICE_OP |
AML_THERMAL_ZONE_OP |
AML_METHOD_OP |
AML_POWER_RES_OP |
AML_PROCESSOR_OP |
AML_NAME_OP |
AML_ALIAS_OP |
AML_MUTEX_OP |
AML_EVENT_OP |
AML_REGION_OP |
AML_CREATE_FIELD_OP |
AML_CREATE_BIT_FIELD_OP |
AML_CREATE_BYTE_FIELD_OP |
AML_CREATE_WORD_FIELD_OP |
AML_CREATE_DWORD_FIELD_OP |
AML_CREATE_QWORD_FIELD_OP |
AML_INT_NAMEDFIELD_OP |
AML_INT_METHODCALL_OP |
AML_INT_NAMEPATH_OP |
Opcodes that define named ACPI objects (AML_NAMED flag) |
AML_SCOPE_OP |
AML_DEVICE_OP |
AML_THERMAL_ZONE_OP |
AML_METHOD_OP |
AML_POWER_RES_OP |
AML_PROCESSOR_OP |
AML_NAME_OP |
AML_ALIAS_OP |
AML_MUTEX_OP |
AML_EVENT_OP |
AML_REGION_OP |
AML_INT_NAMEDFIELD_OP |
Opcodes that contain executable AML as part of the definition that |
must be deferred until needed |
AML_METHOD_OP |
AML_VAR_PACKAGE_OP |
AML_CREATE_FIELD_OP |
AML_CREATE_BIT_FIELD_OP |
AML_CREATE_BYTE_FIELD_OP |
AML_CREATE_WORD_FIELD_OP |
AML_CREATE_DWORD_FIELD_OP |
AML_CREATE_QWORD_FIELD_OP |
AML_REGION_OP |
AML_BUFFER_OP |
Field opcodes |
AML_CREATE_FIELD_OP |
AML_FIELD_OP |
AML_INDEX_FIELD_OP |
AML_BANK_FIELD_OP |
Field "Create" opcodes |
AML_CREATE_FIELD_OP |
AML_CREATE_BIT_FIELD_OP |
AML_CREATE_BYTE_FIELD_OP |
AML_CREATE_WORD_FIELD_OP |
AML_CREATE_DWORD_FIELD_OP |
AML_CREATE_QWORD_FIELD_OP |
******************************************************************************/ |
/* |
* Master Opcode information table. A summary of everything we know about each |
* opcode, all in one place. |
*/ |
const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { |
/*! [Begin] no source code translation */ |
/* Index Name Parser Args Interpreter Args ObjectType Class Type Flags */ |
/* 00 */ ACPI_OP("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, ACPI_TYPE_INTEGER, |
AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), |
/* 01 */ ACPI_OP("One", ARGP_ONE_OP, ARGI_ONE_OP, ACPI_TYPE_INTEGER, |
AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), |
/* 02 */ ACPI_OP("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP, |
ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_SIMPLE, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 03 */ ACPI_OP("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY, |
AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 04 */ ACPI_OP("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP, |
ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, |
AML_TYPE_LITERAL, AML_CONSTANT), |
/* 05 */ ACPI_OP("WordConst", ARGP_WORD_OP, ARGI_WORD_OP, |
ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, |
AML_TYPE_LITERAL, AML_CONSTANT), |
/* 06 */ ACPI_OP("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP, |
ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, |
AML_TYPE_LITERAL, AML_CONSTANT), |
/* 07 */ ACPI_OP("String", ARGP_STRING_OP, ARGI_STRING_OP, |
ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, |
AML_TYPE_LITERAL, AML_CONSTANT), |
/* 08 */ ACPI_OP("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP, |
ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_NO_OBJ, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 09 */ ACPI_OP("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP, |
ACPI_TYPE_BUFFER, AML_CLASS_CREATE, |
AML_TYPE_CREATE_OBJECT, |
AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), |
/* 0A */ ACPI_OP("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP, |
ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, |
AML_TYPE_CREATE_OBJECT, |
AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), |
/* 0B */ ACPI_OP("Method", ARGP_METHOD_OP, ARGI_METHOD_OP, |
ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_COMPLEX, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED | AML_DEFER), |
/* 0C */ ACPI_OP("Local0", ARGP_LOCAL0, ARGI_LOCAL0, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 0D */ ACPI_OP("Local1", ARGP_LOCAL1, ARGI_LOCAL1, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 0E */ ACPI_OP("Local2", ARGP_LOCAL2, ARGI_LOCAL2, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 0F */ ACPI_OP("Local3", ARGP_LOCAL3, ARGI_LOCAL3, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 10 */ ACPI_OP("Local4", ARGP_LOCAL4, ARGI_LOCAL4, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 11 */ ACPI_OP("Local5", ARGP_LOCAL5, ARGI_LOCAL5, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 12 */ ACPI_OP("Local6", ARGP_LOCAL6, ARGI_LOCAL6, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 13 */ ACPI_OP("Local7", ARGP_LOCAL7, ARGI_LOCAL7, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LOCAL_VARIABLE, 0), |
/* 14 */ ACPI_OP("Arg0", ARGP_ARG0, ARGI_ARG0, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_METHOD_ARGUMENT, 0), |
/* 15 */ ACPI_OP("Arg1", ARGP_ARG1, ARGI_ARG1, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_METHOD_ARGUMENT, 0), |
/* 16 */ ACPI_OP("Arg2", ARGP_ARG2, ARGI_ARG2, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_METHOD_ARGUMENT, 0), |
/* 17 */ ACPI_OP("Arg3", ARGP_ARG3, ARGI_ARG3, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_METHOD_ARGUMENT, 0), |
/* 18 */ ACPI_OP("Arg4", ARGP_ARG4, ARGI_ARG4, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_METHOD_ARGUMENT, 0), |
/* 19 */ ACPI_OP("Arg5", ARGP_ARG5, ARGI_ARG5, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_METHOD_ARGUMENT, 0), |
/* 1A */ ACPI_OP("Arg6", ARGP_ARG6, ARGI_ARG6, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_METHOD_ARGUMENT, 0), |
/* 1B */ ACPI_OP("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R), |
/* 1C */ ACPI_OP("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, |
AML_FLAGS_EXEC_1A_0T_1R), |
/* 1D */ ACPI_OP("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 1E */ ACPI_OP("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), |
/* 1F */ ACPI_OP("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 20 */ ACPI_OP("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_1R, |
AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), |
/* 21 */ ACPI_OP("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_1R, |
AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), |
/* 22 */ ACPI_OP("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 23 */ ACPI_OP("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_2T_1R, |
AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT), |
/* 24 */ ACPI_OP("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 25 */ ACPI_OP("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 26 */ ACPI_OP("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 27 */ ACPI_OP("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 28 */ ACPI_OP("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 29 */ ACPI_OP("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 2A */ ACPI_OP("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), |
/* 2B */ ACPI_OP("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 2C */ ACPI_OP("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP, |
ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 2D */ ACPI_OP("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP, |
ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 2E */ ACPI_OP("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), |
/* 2F */ ACPI_OP("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), |
/* 30 */ ACPI_OP("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_1R, |
AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), |
/* 31 */ ACPI_OP("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R), |
/* 32 */ ACPI_OP("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, |
AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT), |
/* 33 */ ACPI_OP("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP, |
ARGI_CREATE_DWORD_FIELD_OP, |
ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, |
AML_TYPE_CREATE_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | |
AML_DEFER | AML_CREATE), |
/* 34 */ ACPI_OP("CreateWordField", ARGP_CREATE_WORD_FIELD_OP, |
ARGI_CREATE_WORD_FIELD_OP, |
ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, |
AML_TYPE_CREATE_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | |
AML_DEFER | AML_CREATE), |
/* 35 */ ACPI_OP("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP, |
ARGI_CREATE_BYTE_FIELD_OP, |
ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, |
AML_TYPE_CREATE_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | |
AML_DEFER | AML_CREATE), |
/* 36 */ ACPI_OP("CreateBitField", ARGP_CREATE_BIT_FIELD_OP, |
ARGI_CREATE_BIT_FIELD_OP, |
ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, |
AML_TYPE_CREATE_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | |
AML_DEFER | AML_CREATE), |
/* 37 */ ACPI_OP("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_1R, |
AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), |
/* 38 */ ACPI_OP("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, |
AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | |
AML_CONSTANT), |
/* 39 */ ACPI_OP("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, |
AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | |
AML_CONSTANT), |
/* 3A */ ACPI_OP("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, |
AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), |
/* 3B */ ACPI_OP("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_0T_1R, |
AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), |
/* 3C */ ACPI_OP("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_0T_1R, |
AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), |
/* 3D */ ACPI_OP("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, |
AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), |
/* 3E */ ACPI_OP("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY, |
AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), |
/* 3F */ ACPI_OP("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY, |
AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), |
/* 40 */ ACPI_OP("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY, |
AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), |
/* 41 */ ACPI_OP("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY, |
AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), |
/* 42 */ ACPI_OP("Return", ARGP_RETURN_OP, ARGI_RETURN_OP, |
ACPI_TYPE_ANY, AML_CLASS_CONTROL, |
AML_TYPE_CONTROL, AML_HAS_ARGS), |
/* 43 */ ACPI_OP("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY, |
AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), |
/* 44 */ ACPI_OP("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP, |
ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), |
/* 45 */ ACPI_OP("Ones", ARGP_ONES_OP, ARGI_ONES_OP, ACPI_TYPE_INTEGER, |
AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), |
/* Prefixed opcodes (Two-byte opcodes with a prefix op) */ |
/* 46 */ ACPI_OP("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX, |
AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 47 */ ACPI_OP("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT, |
AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, |
AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), |
/* 48 */ ACPI_OP("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), |
/* 49 */ ACPI_OP("CreateField", ARGP_CREATE_FIELD_OP, |
ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, |
AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | |
AML_DEFER | AML_FIELD | AML_CREATE), |
/* 4A */ ACPI_OP("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, |
AML_FLAGS_EXEC_1A_1T_0R), |
/* 4B */ ACPI_OP("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, |
AML_FLAGS_EXEC_1A_0T_0R), |
/* 4C */ ACPI_OP("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, |
AML_FLAGS_EXEC_1A_0T_0R), |
/* 4D */ ACPI_OP("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), |
/* 4E */ ACPI_OP("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), |
/* 4F */ ACPI_OP("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, |
AML_FLAGS_EXEC_2A_0T_1R), |
/* 50 */ ACPI_OP("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, |
AML_FLAGS_EXEC_1A_0T_0R), |
/* 51 */ ACPI_OP("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), |
/* 52 */ ACPI_OP("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 53 */ ACPI_OP("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 54 */ ACPI_OP("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), |
/* 55 */ ACPI_OP("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP, |
ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, |
AML_TYPE_CONSTANT, 0), |
/* 56 */ ACPI_OP("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_CONSTANT, 0), |
/* 57 */ ACPI_OP("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, |
AML_FLAGS_EXEC_3A_0T_0R), |
/* 58 */ ACPI_OP("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP, |
ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_COMPLEX, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED | AML_DEFER), |
/* 59 */ ACPI_OP("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY, |
AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_FIELD), |
/* 5A */ ACPI_OP("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, |
ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_NO_OBJ, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 5B */ ACPI_OP("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP, |
ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_SIMPLE, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 5C */ ACPI_OP("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP, |
ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_SIMPLE, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 5D */ ACPI_OP("ThermalZone", ARGP_THERMAL_ZONE_OP, |
ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, |
AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED), |
/* 5E */ ACPI_OP("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, |
ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_FIELD), |
/* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, |
ACPI_TYPE_LOCAL_BANK_FIELD, |
AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_FIELD | AML_DEFER), |
/* Internal opcodes that map to invalid AML opcodes */ |
/* 60 */ ACPI_OP("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP, |
ACPI_TYPE_ANY, AML_CLASS_INTERNAL, |
AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), |
/* 61 */ ACPI_OP("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP, |
ACPI_TYPE_ANY, AML_CLASS_INTERNAL, |
AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), |
/* 62 */ ACPI_OP("LGreaterEqual", ARGP_LGREATEREQUAL_OP, |
ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, |
AML_CLASS_INTERNAL, AML_TYPE_BOGUS, |
AML_HAS_ARGS | AML_CONSTANT), |
/* 63 */ ACPI_OP("-NamePath-", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP, |
ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, |
AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE), |
/* 64 */ ACPI_OP("-MethodCall-", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP, |
ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, |
AML_TYPE_METHOD_CALL, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), |
/* 65 */ ACPI_OP("-ByteList-", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP, |
ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, |
AML_TYPE_LITERAL, 0), |
/* 66 */ ACPI_OP("-ReservedField-", ARGP_RESERVEDFIELD_OP, |
ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, |
AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), |
/* 67 */ ACPI_OP("-NamedField-", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP, |
ACPI_TYPE_ANY, AML_CLASS_INTERNAL, |
AML_TYPE_BOGUS, |
AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), |
/* 68 */ ACPI_OP("-AccessField-", ARGP_ACCESSFIELD_OP, |
ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, |
AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), |
/* 69 */ ACPI_OP("-StaticString", ARGP_STATICSTRING_OP, |
ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, |
AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), |
/* 6A */ ACPI_OP("-Return Value-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, |
AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, |
AML_HAS_ARGS | AML_HAS_RETVAL), |
/* 6B */ ACPI_OP("-UNKNOWN_OP-", ARG_NONE, ARG_NONE, ACPI_TYPE_INVALID, |
AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), |
/* 6C */ ACPI_OP("-ASCII_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, |
AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), |
/* 6D */ ACPI_OP("-PREFIX_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, |
AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), |
/* ACPI 2.0 opcodes */ |
/* 6E */ ACPI_OP("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP, |
ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, |
AML_TYPE_LITERAL, AML_CONSTANT), |
/* 6F */ ACPI_OP("Package", /* Var */ ARGP_VAR_PACKAGE_OP, |
ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE, |
AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, |
AML_HAS_ARGS | AML_DEFER), |
/* 70 */ ACPI_OP("ConcatenateResTemplate", ARGP_CONCAT_RES_OP, |
ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), |
/* 71 */ ACPI_OP("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), |
/* 72 */ ACPI_OP("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP, |
ARGI_CREATE_QWORD_FIELD_OP, |
ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, |
AML_TYPE_CREATE_FIELD, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | |
AML_DEFER | AML_CREATE), |
/* 73 */ ACPI_OP("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 74 */ ACPI_OP("ToDecimalString", ARGP_TO_DEC_STR_OP, |
ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 75 */ ACPI_OP("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 76 */ ACPI_OP("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_1T_1R, |
AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), |
/* 77 */ ACPI_OP("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_2A_1T_1R, |
AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), |
/* 78 */ ACPI_OP("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), |
/* 79 */ ACPI_OP("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, |
AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT), |
/* 7A */ ACPI_OP("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP, |
ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), |
/* 7B */ ACPI_OP("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, |
AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), |
/* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP, |
ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, |
AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE | AML_NAMED | AML_DEFER), |
/* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, |
ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, |
AML_TYPE_NAMED_NO_OBJ, |
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | |
AML_NSNODE), |
/* ACPI 3.0 opcodes */ |
/* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, |
AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, |
AML_FLAGS_EXEC_0A_0T_1R), |
/* ACPI 5.0 opcodes */ |
/* 7F */ ACPI_OP("-ConnectField-", ARGP_CONNECTFIELD_OP, |
ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, |
AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS), |
/* 80 */ ACPI_OP("-ExtAccessField-", ARGP_CONNECTFIELD_OP, |
ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, |
AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), |
/* ACPI 6.0 opcodes */ |
/* 81 */ ACPI_OP("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, |
ACPI_TYPE_ANY, AML_CLASS_EXECUTE, /* ? */ |
AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R) |
/*! [End] no source code translation !*/ |
}; |
/drivers/acpi/acpica/psopinfo.c |
---|
0,0 → 1,267 |
/****************************************************************************** |
* |
* Module Name: psopinfo - AML opcode information functions and dispatch tables |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "acopcode.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psopinfo") |
static const u8 acpi_gbl_argument_count[] = |
{ 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 }; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_opcode_info |
* |
* PARAMETERS: opcode - The AML opcode |
* |
* RETURN: A pointer to the info about the opcode. |
* |
* DESCRIPTION: Find AML opcode description based on the opcode. |
* NOTE: This procedure must ALWAYS return a valid pointer! |
* |
******************************************************************************/ |
const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) |
{ |
#ifdef ACPI_DEBUG_OUTPUT |
const char *opcode_name = "Unknown AML opcode"; |
#endif |
ACPI_FUNCTION_NAME(ps_get_opcode_info); |
/* |
* Detect normal 8-bit opcode or extended 16-bit opcode |
*/ |
if (!(opcode & 0xFF00)) { |
/* Simple (8-bit) opcode: 0-255, can't index beyond table */ |
return (&acpi_gbl_aml_op_info |
[acpi_gbl_short_op_index[(u8)opcode]]); |
} |
if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) && |
(((u8)opcode) <= MAX_EXTENDED_OPCODE)) { |
/* Valid extended (16-bit) opcode */ |
return (&acpi_gbl_aml_op_info |
[acpi_gbl_long_op_index[(u8)opcode]]); |
} |
#if defined ACPI_ASL_COMPILER && defined ACPI_DEBUG_OUTPUT |
#include "asldefine.h" |
switch (opcode) { |
case AML_RAW_DATA_BYTE: |
opcode_name = "-Raw Data Byte-"; |
break; |
case AML_RAW_DATA_WORD: |
opcode_name = "-Raw Data Word-"; |
break; |
case AML_RAW_DATA_DWORD: |
opcode_name = "-Raw Data Dword-"; |
break; |
case AML_RAW_DATA_QWORD: |
opcode_name = "-Raw Data Qword-"; |
break; |
case AML_RAW_DATA_BUFFER: |
opcode_name = "-Raw Data Buffer-"; |
break; |
case AML_RAW_DATA_CHAIN: |
opcode_name = "-Raw Data Buffer Chain-"; |
break; |
case AML_PACKAGE_LENGTH: |
opcode_name = "-Package Length-"; |
break; |
case AML_UNASSIGNED_OPCODE: |
opcode_name = "-Unassigned Opcode-"; |
break; |
case AML_DEFAULT_ARG_OP: |
opcode_name = "-Default Arg-"; |
break; |
default: |
break; |
} |
#endif |
/* Unknown AML opcode */ |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%4.4X]\n", opcode_name, opcode)); |
return (&acpi_gbl_aml_op_info[_UNK]); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_opcode_name |
* |
* PARAMETERS: opcode - The AML opcode |
* |
* RETURN: A pointer to the name of the opcode (ASCII String) |
* Note: Never returns NULL. |
* |
* DESCRIPTION: Translate an opcode into a human-readable string |
* |
******************************************************************************/ |
char *acpi_ps_get_opcode_name(u16 opcode) |
{ |
#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT) |
const struct acpi_opcode_info *op; |
op = acpi_ps_get_opcode_info(opcode); |
/* Always guaranteed to return a valid pointer */ |
return (op->name); |
#else |
return ("OpcodeName unavailable"); |
#endif |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_argument_count |
* |
* PARAMETERS: op_type - Type associated with the AML opcode |
* |
* RETURN: Argument count |
* |
* DESCRIPTION: Obtain the number of expected arguments for an AML opcode |
* |
******************************************************************************/ |
u8 acpi_ps_get_argument_count(u32 op_type) |
{ |
if (op_type <= AML_TYPE_EXEC_6A_0T_1R) { |
return (acpi_gbl_argument_count[op_type]); |
} |
return (0); |
} |
/* |
* This table is directly indexed by the opcodes It returns |
* an index into the opcode table (acpi_gbl_aml_op_info) |
*/ |
const u8 acpi_gbl_short_op_index[256] = { |
/* 0 1 2 3 4 5 6 7 */ |
/* 8 9 A B C D E F */ |
/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK, |
/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK, |
/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, 0x81, _UNK, _UNK, |
/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, |
/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D, |
/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, |
/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, |
/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, |
/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC, |
/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, |
/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK, |
/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, |
/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, |
/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30, |
/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72, |
/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74, |
/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A, |
/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61, |
/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK, |
/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45, |
}; |
/* |
* This table is indexed by the second opcode of the extended opcode |
* pair. It returns an index into the opcode table (acpi_gbl_aml_op_info) |
*/ |
const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = { |
/* 0 1 2 3 4 5 6 7 */ |
/* 8 9 A B C D E F */ |
/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK, |
/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B, |
/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, |
/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x30 */ 0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK, |
/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, |
/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, |
/* 0x88 */ 0x7C, |
}; |
/drivers/acpi/acpica/psparse.c |
---|
0,0 → 1,694 |
/****************************************************************************** |
* |
* Module Name: psparse - Parser top level AML parse routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
/* |
* Parse the AML and build an operation tree as most interpreters, |
* like Perl, do. Parsing is done by hand rather than with a YACC |
* generated parser to tightly constrain stack and dynamic memory |
* usage. At the same time, parsing is kept flexible and the code |
* fairly compact by parsing based on a list of AML opcode |
* templates in aml_op_info[] |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "acdispat.h" |
#include "amlcode.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psparse") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_opcode_size |
* |
* PARAMETERS: opcode - An AML opcode |
* |
* RETURN: Size of the opcode, in bytes (1 or 2) |
* |
* DESCRIPTION: Get the size of the current opcode. |
* |
******************************************************************************/ |
u32 acpi_ps_get_opcode_size(u32 opcode) |
{ |
/* Extended (2-byte) opcode if > 255 */ |
if (opcode > 0x00FF) { |
return (2); |
} |
/* Otherwise, just a single byte opcode */ |
return (1); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_peek_opcode |
* |
* PARAMETERS: parser_state - A parser state object |
* |
* RETURN: Next AML opcode |
* |
* DESCRIPTION: Get next AML opcode (without incrementing AML pointer) |
* |
******************************************************************************/ |
u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state) |
{ |
u8 *aml; |
u16 opcode; |
aml = parser_state->aml; |
opcode = (u16) ACPI_GET8(aml); |
if (opcode == AML_EXTENDED_OP_PREFIX) { |
/* Extended opcode, get the second opcode byte */ |
aml++; |
opcode = (u16) ((opcode << 8) | ACPI_GET8(aml)); |
} |
return (opcode); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_complete_this_op |
* |
* PARAMETERS: walk_state - Current State |
* op - Op to complete |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform any cleanup at the completion of an Op. |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, |
union acpi_parse_object * op) |
{ |
union acpi_parse_object *prev; |
union acpi_parse_object *next; |
const struct acpi_opcode_info *parent_info; |
union acpi_parse_object *replacement_op = NULL; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op); |
/* Check for null Op, can happen if AML code is corrupt */ |
if (!op) { |
return_ACPI_STATUS(AE_OK); /* OK for now */ |
} |
acpi_ex_stop_trace_opcode(op, walk_state); |
/* Delete this op and the subtree below it if asked to */ |
if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != |
ACPI_PARSE_DELETE_TREE) |
|| (walk_state->op_info->class == AML_CLASS_ARGUMENT)) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Make sure that we only delete this subtree */ |
if (op->common.parent) { |
prev = op->common.parent->common.value.arg; |
if (!prev) { |
/* Nothing more to do */ |
goto cleanup; |
} |
/* |
* Check if we need to replace the operator and its subtree |
* with a return value op (placeholder op) |
*/ |
parent_info = |
acpi_ps_get_opcode_info(op->common.parent->common. |
aml_opcode); |
switch (parent_info->class) { |
case AML_CLASS_CONTROL: |
break; |
case AML_CLASS_CREATE: |
/* |
* These opcodes contain term_arg operands. The current |
* op must be replaced by a placeholder return op |
*/ |
replacement_op = |
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, |
op->common.aml); |
if (!replacement_op) { |
status = AE_NO_MEMORY; |
} |
break; |
case AML_CLASS_NAMED_OBJECT: |
/* |
* These opcodes contain term_arg operands. The current |
* op must be replaced by a placeholder return op |
*/ |
if ((op->common.parent->common.aml_opcode == |
AML_REGION_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_DATA_REGION_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_BUFFER_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_PACKAGE_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_BANK_FIELD_OP) |
|| (op->common.parent->common.aml_opcode == |
AML_VAR_PACKAGE_OP)) { |
replacement_op = |
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, |
op->common.aml); |
if (!replacement_op) { |
status = AE_NO_MEMORY; |
} |
} else |
if ((op->common.parent->common.aml_opcode == |
AML_NAME_OP) |
&& (walk_state->pass_number <= |
ACPI_IMODE_LOAD_PASS2)) { |
if ((op->common.aml_opcode == AML_BUFFER_OP) |
|| (op->common.aml_opcode == AML_PACKAGE_OP) |
|| (op->common.aml_opcode == |
AML_VAR_PACKAGE_OP)) { |
replacement_op = |
acpi_ps_alloc_op(op->common. |
aml_opcode, |
op->common.aml); |
if (!replacement_op) { |
status = AE_NO_MEMORY; |
} else { |
replacement_op->named.data = |
op->named.data; |
replacement_op->named.length = |
op->named.length; |
} |
} |
} |
break; |
default: |
replacement_op = |
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, |
op->common.aml); |
if (!replacement_op) { |
status = AE_NO_MEMORY; |
} |
} |
/* We must unlink this op from the parent tree */ |
if (prev == op) { |
/* This op is the first in the list */ |
if (replacement_op) { |
replacement_op->common.parent = |
op->common.parent; |
replacement_op->common.value.arg = NULL; |
replacement_op->common.node = op->common.node; |
op->common.parent->common.value.arg = |
replacement_op; |
replacement_op->common.next = op->common.next; |
} else { |
op->common.parent->common.value.arg = |
op->common.next; |
} |
} |
/* Search the parent list */ |
else |
while (prev) { |
/* Traverse all siblings in the parent's argument list */ |
next = prev->common.next; |
if (next == op) { |
if (replacement_op) { |
replacement_op->common.parent = |
op->common.parent; |
replacement_op->common.value. |
arg = NULL; |
replacement_op->common.node = |
op->common.node; |
prev->common.next = |
replacement_op; |
replacement_op->common.next = |
op->common.next; |
next = NULL; |
} else { |
prev->common.next = |
op->common.next; |
next = NULL; |
} |
} |
prev = next; |
} |
} |
cleanup: |
/* Now we can actually delete the subtree rooted at Op */ |
acpi_ps_delete_parse_tree(op); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_next_parse_state |
* |
* PARAMETERS: walk_state - Current state |
* op - Current parse op |
* callback_status - Status from previous operation |
* |
* RETURN: Status |
* |
* DESCRIPTION: Update the parser state based upon the return exception from |
* the parser callback. |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, |
union acpi_parse_object *op, |
acpi_status callback_status) |
{ |
struct acpi_parse_state *parser_state = &walk_state->parser_state; |
acpi_status status = AE_CTRL_PENDING; |
ACPI_FUNCTION_TRACE_PTR(ps_next_parse_state, op); |
switch (callback_status) { |
case AE_CTRL_TERMINATE: |
/* |
* A control method was terminated via a RETURN statement. |
* The walk of this method is complete. |
*/ |
parser_state->aml = parser_state->aml_end; |
status = AE_CTRL_TERMINATE; |
break; |
case AE_CTRL_BREAK: |
parser_state->aml = walk_state->aml_last_while; |
walk_state->control_state->common.value = FALSE; |
status = AE_CTRL_BREAK; |
break; |
case AE_CTRL_CONTINUE: |
parser_state->aml = walk_state->aml_last_while; |
status = AE_CTRL_CONTINUE; |
break; |
case AE_CTRL_PENDING: |
parser_state->aml = walk_state->aml_last_while; |
break; |
#if 0 |
case AE_CTRL_SKIP: |
parser_state->aml = parser_state->scope->parse_scope.pkg_end; |
status = AE_OK; |
break; |
#endif |
case AE_CTRL_TRUE: |
/* |
* Predicate of an IF was true, and we are at the matching ELSE. |
* Just close out this package |
*/ |
parser_state->aml = acpi_ps_get_next_package_end(parser_state); |
status = AE_CTRL_PENDING; |
break; |
case AE_CTRL_FALSE: |
/* |
* Either an IF/WHILE Predicate was false or we encountered a BREAK |
* opcode. In both cases, we do not execute the rest of the |
* package; We simply close out the parent (finishing the walk of |
* this branch of the tree) and continue execution at the parent |
* level. |
*/ |
parser_state->aml = parser_state->scope->parse_scope.pkg_end; |
/* In the case of a BREAK, just force a predicate (if any) to FALSE */ |
walk_state->control_state->common.value = FALSE; |
status = AE_CTRL_END; |
break; |
case AE_CTRL_TRANSFER: |
/* A method call (invocation) -- transfer control */ |
status = AE_CTRL_TRANSFER; |
walk_state->prev_op = op; |
walk_state->method_call_op = op; |
walk_state->method_call_node = |
(op->common.value.arg)->common.node; |
/* Will return value (if any) be used by the caller? */ |
walk_state->return_used = |
acpi_ds_is_result_used(op, walk_state); |
break; |
default: |
status = callback_status; |
if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) { |
status = AE_OK; |
} |
break; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_parse_aml |
* |
* PARAMETERS: walk_state - Current state |
* |
* |
* RETURN: Status |
* |
* DESCRIPTION: Parse raw AML and return a tree of ops |
* |
******************************************************************************/ |
acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) |
{ |
acpi_status status; |
struct acpi_thread_state *thread; |
struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list; |
struct acpi_walk_state *previous_walk_state; |
ACPI_FUNCTION_TRACE(ps_parse_aml); |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Entered with WalkState=%p Aml=%p size=%X\n", |
walk_state, walk_state->parser_state.aml, |
walk_state->parser_state.aml_size)); |
if (!walk_state->parser_state.aml) { |
return_ACPI_STATUS(AE_NULL_OBJECT); |
} |
/* Create and initialize a new thread state */ |
thread = acpi_ut_create_thread_state(); |
if (!thread) { |
if (walk_state->method_desc) { |
/* Executing a control method - additional cleanup */ |
acpi_ds_terminate_control_method(walk_state-> |
method_desc, |
walk_state); |
} |
acpi_ds_delete_walk_state(walk_state); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
walk_state->thread = thread; |
/* |
* If executing a method, the starting sync_level is this method's |
* sync_level |
*/ |
if (walk_state->method_desc) { |
walk_state->thread->current_sync_level = |
walk_state->method_desc->method.sync_level; |
} |
acpi_ds_push_walk_state(walk_state, thread); |
/* |
* This global allows the AML debugger to get a handle to the currently |
* executing control method. |
*/ |
acpi_gbl_current_walk_list = thread; |
/* |
* Execute the walk loop as long as there is a valid Walk State. This |
* handles nested control method invocations without recursion. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "State=%p\n", walk_state)); |
status = AE_OK; |
while (walk_state) { |
if (ACPI_SUCCESS(status)) { |
/* |
* The parse_loop executes AML until the method terminates |
* or calls another method. |
*/ |
status = acpi_ps_parse_loop(walk_state); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Completed one call to walk loop, %s State=%p\n", |
acpi_format_exception(status), walk_state)); |
if (status == AE_CTRL_TRANSFER) { |
/* |
* A method call was detected. |
* Transfer control to the called control method |
*/ |
status = |
acpi_ds_call_control_method(thread, walk_state, |
NULL); |
if (ACPI_FAILURE(status)) { |
status = |
acpi_ds_method_error(status, walk_state); |
} |
/* |
* If the transfer to the new method method call worked, a new walk |
* state was created -- get it |
*/ |
walk_state = acpi_ds_get_current_walk_state(thread); |
continue; |
} else if (status == AE_CTRL_TERMINATE) { |
status = AE_OK; |
} else if ((status != AE_OK) && (walk_state->method_desc)) { |
/* Either the method parse or actual execution failed */ |
ACPI_ERROR_METHOD("Method parse/execution failed", |
walk_state->method_node, NULL, |
status); |
/* Check for possible multi-thread reentrancy problem */ |
if ((status == AE_ALREADY_EXISTS) && |
(!(walk_state->method_desc->method. |
info_flags & ACPI_METHOD_SERIALIZED))) { |
/* |
* Method is not serialized and tried to create an object |
* twice. The probable cause is that the method cannot |
* handle reentrancy. Mark as "pending serialized" now, and |
* then mark "serialized" when the last thread exits. |
*/ |
walk_state->method_desc->method.info_flags |= |
ACPI_METHOD_SERIALIZED_PENDING; |
} |
} |
/* We are done with this walk, move on to the parent if any */ |
walk_state = acpi_ds_pop_walk_state(thread); |
/* Reset the current scope to the beginning of scope stack */ |
acpi_ds_scope_stack_clear(walk_state); |
/* |
* If we just returned from the execution of a control method or if we |
* encountered an error during the method parse phase, there's lots of |
* cleanup to do |
*/ |
if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == |
ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) { |
acpi_ds_terminate_control_method(walk_state-> |
method_desc, |
walk_state); |
} |
/* Delete this walk state and all linked control states */ |
acpi_ps_cleanup_scope(&walk_state->parser_state); |
previous_walk_state = walk_state; |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"ReturnValue=%p, ImplicitValue=%p State=%p\n", |
walk_state->return_desc, |
walk_state->implicit_return_obj, walk_state)); |
/* Check if we have restarted a preempted walk */ |
walk_state = acpi_ds_get_current_walk_state(thread); |
if (walk_state) { |
if (ACPI_SUCCESS(status)) { |
/* |
* There is another walk state, restart it. |
* If the method return value is not used by the parent, |
* The object is deleted |
*/ |
if (!previous_walk_state->return_desc) { |
/* |
* In slack mode execution, if there is no return value |
* we should implicitly return zero (0) as a default value. |
*/ |
if (acpi_gbl_enable_interpreter_slack && |
!previous_walk_state-> |
implicit_return_obj) { |
previous_walk_state-> |
implicit_return_obj = |
acpi_ut_create_integer_object |
((u64) 0); |
if (!previous_walk_state-> |
implicit_return_obj) { |
return_ACPI_STATUS |
(AE_NO_MEMORY); |
} |
} |
/* Restart the calling control method */ |
status = |
acpi_ds_restart_control_method |
(walk_state, |
previous_walk_state-> |
implicit_return_obj); |
} else { |
/* |
* We have a valid return value, delete any implicit |
* return value. |
*/ |
acpi_ds_clear_implicit_return |
(previous_walk_state); |
status = |
acpi_ds_restart_control_method |
(walk_state, |
previous_walk_state->return_desc); |
} |
if (ACPI_SUCCESS(status)) { |
walk_state->walk_type |= |
ACPI_WALK_METHOD_RESTART; |
} |
} else { |
/* On error, delete any return object or implicit return */ |
acpi_ut_remove_reference(previous_walk_state-> |
return_desc); |
acpi_ds_clear_implicit_return |
(previous_walk_state); |
} |
} |
/* |
* Just completed a 1st-level method, save the final internal return |
* value (if any) |
*/ |
else if (previous_walk_state->caller_return_desc) { |
if (previous_walk_state->implicit_return_obj) { |
*(previous_walk_state->caller_return_desc) = |
previous_walk_state->implicit_return_obj; |
} else { |
/* NULL if no return value */ |
*(previous_walk_state->caller_return_desc) = |
previous_walk_state->return_desc; |
} |
} else { |
if (previous_walk_state->return_desc) { |
/* Caller doesn't want it, must delete it */ |
acpi_ut_remove_reference(previous_walk_state-> |
return_desc); |
} |
if (previous_walk_state->implicit_return_obj) { |
/* Caller doesn't want it, must delete it */ |
acpi_ut_remove_reference(previous_walk_state-> |
implicit_return_obj); |
} |
} |
acpi_ds_delete_walk_state(previous_walk_state); |
} |
/* Normal exit */ |
acpi_ex_release_all_mutexes(thread); |
acpi_ut_delete_generic_state(ACPI_CAST_PTR |
(union acpi_generic_state, thread)); |
acpi_gbl_current_walk_list = prev_walk_list; |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/psscope.c |
---|
0,0 → 1,265 |
/****************************************************************************** |
* |
* Module Name: psscope - Parser scope stack management routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psscope") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_parent_scope |
* |
* PARAMETERS: parser_state - Current parser state object |
* |
* RETURN: Pointer to an Op object |
* |
* DESCRIPTION: Get parent of current op being parsed |
* |
******************************************************************************/ |
union acpi_parse_object *acpi_ps_get_parent_scope(struct acpi_parse_state |
*parser_state) |
{ |
return (parser_state->scope->parse_scope.op); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_has_completed_scope |
* |
* PARAMETERS: parser_state - Current parser state object |
* |
* RETURN: Boolean, TRUE = scope completed. |
* |
* DESCRIPTION: Is parsing of current argument complete? Determined by |
* 1) AML pointer is at or beyond the end of the scope |
* 2) The scope argument count has reached zero. |
* |
******************************************************************************/ |
u8 acpi_ps_has_completed_scope(struct acpi_parse_state * parser_state) |
{ |
return ((u8) |
((parser_state->aml >= parser_state->scope->parse_scope.arg_end |
|| !parser_state->scope->parse_scope.arg_count))); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_init_scope |
* |
* PARAMETERS: parser_state - Current parser state object |
* root - the Root Node of this new scope |
* |
* RETURN: Status |
* |
* DESCRIPTION: Allocate and init a new scope object |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_init_scope(struct acpi_parse_state * parser_state, |
union acpi_parse_object * root_op) |
{ |
union acpi_generic_state *scope; |
ACPI_FUNCTION_TRACE_PTR(ps_init_scope, root_op); |
scope = acpi_ut_create_generic_state(); |
if (!scope) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
scope->common.descriptor_type = ACPI_DESC_TYPE_STATE_RPSCOPE; |
scope->parse_scope.op = root_op; |
scope->parse_scope.arg_count = ACPI_VAR_ARGS; |
scope->parse_scope.arg_end = parser_state->aml_end; |
scope->parse_scope.pkg_end = parser_state->aml_end; |
parser_state->scope = scope; |
parser_state->start_op = root_op; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_push_scope |
* |
* PARAMETERS: parser_state - Current parser state object |
* op - Current op to be pushed |
* remaining_args - List of args remaining |
* arg_count - Fixed or variable number of args |
* |
* RETURN: Status |
* |
* DESCRIPTION: Push current op to begin parsing its argument |
* |
******************************************************************************/ |
acpi_status |
acpi_ps_push_scope(struct acpi_parse_state *parser_state, |
union acpi_parse_object *op, |
u32 remaining_args, u32 arg_count) |
{ |
union acpi_generic_state *scope; |
ACPI_FUNCTION_TRACE_PTR(ps_push_scope, op); |
scope = acpi_ut_create_generic_state(); |
if (!scope) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
scope->common.descriptor_type = ACPI_DESC_TYPE_STATE_PSCOPE; |
scope->parse_scope.op = op; |
scope->parse_scope.arg_list = remaining_args; |
scope->parse_scope.arg_count = arg_count; |
scope->parse_scope.pkg_end = parser_state->pkg_end; |
/* Push onto scope stack */ |
acpi_ut_push_generic_state(&parser_state->scope, scope); |
if (arg_count == ACPI_VAR_ARGS) { |
/* Multiple arguments */ |
scope->parse_scope.arg_end = parser_state->pkg_end; |
} else { |
/* Single argument */ |
scope->parse_scope.arg_end = ACPI_TO_POINTER(ACPI_MAX_PTR); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_pop_scope |
* |
* PARAMETERS: parser_state - Current parser state object |
* op - Where the popped op is returned |
* arg_list - Where the popped "next argument" is |
* returned |
* arg_count - Count of objects in arg_list |
* |
* RETURN: Status |
* |
* DESCRIPTION: Return to parsing a previous op |
* |
******************************************************************************/ |
void |
acpi_ps_pop_scope(struct acpi_parse_state *parser_state, |
union acpi_parse_object **op, u32 * arg_list, u32 * arg_count) |
{ |
union acpi_generic_state *scope = parser_state->scope; |
ACPI_FUNCTION_TRACE(ps_pop_scope); |
/* Only pop the scope if there is in fact a next scope */ |
if (scope->common.next) { |
scope = acpi_ut_pop_generic_state(&parser_state->scope); |
/* Return to parsing previous op */ |
*op = scope->parse_scope.op; |
*arg_list = scope->parse_scope.arg_list; |
*arg_count = scope->parse_scope.arg_count; |
parser_state->pkg_end = scope->parse_scope.pkg_end; |
/* All done with this scope state structure */ |
acpi_ut_delete_generic_state(scope); |
} else { |
/* Empty parse stack, prepare to fetch next opcode */ |
*op = NULL; |
*arg_list = 0; |
*arg_count = 0; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"Popped Op %p Args %X\n", *op, *arg_count)); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_cleanup_scope |
* |
* PARAMETERS: parser_state - Current parser state object |
* |
* RETURN: None |
* |
* DESCRIPTION: Destroy available list, remaining stack levels, and return |
* root scope |
* |
******************************************************************************/ |
void acpi_ps_cleanup_scope(struct acpi_parse_state *parser_state) |
{ |
union acpi_generic_state *scope; |
ACPI_FUNCTION_TRACE_PTR(ps_cleanup_scope, parser_state); |
if (!parser_state) { |
return_VOID; |
} |
/* Delete anything on the scope stack */ |
while (parser_state->scope) { |
scope = acpi_ut_pop_generic_state(&parser_state->scope); |
acpi_ut_delete_generic_state(scope); |
} |
return_VOID; |
} |
/drivers/acpi/acpica/pstree.c |
---|
0,0 → 1,318 |
/****************************************************************************** |
* |
* Module Name: pstree - Parser op tree manipulation/traversal/search |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("pstree") |
/* Local prototypes */ |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op); |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_arg |
* |
* PARAMETERS: op - Get an argument for this op |
* argn - Nth argument to get |
* |
* RETURN: The argument (as an Op object). NULL if argument does not exist |
* |
* DESCRIPTION: Get the specified op's argument. |
* |
******************************************************************************/ |
union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn) |
{ |
union acpi_parse_object *arg = NULL; |
const struct acpi_opcode_info *op_info; |
ACPI_FUNCTION_ENTRY(); |
/* |
if (Op->Common.aml_opcode == AML_INT_CONNECTION_OP) |
{ |
return (Op->Common.Value.Arg); |
} |
*/ |
/* Get the info structure for this opcode */ |
op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); |
if (op_info->class == AML_CLASS_UNKNOWN) { |
/* Invalid opcode or ASCII character */ |
return (NULL); |
} |
/* Check if this opcode requires argument sub-objects */ |
if (!(op_info->flags & AML_HAS_ARGS)) { |
/* Has no linked argument objects */ |
return (NULL); |
} |
/* Get the requested argument object */ |
arg = op->common.value.arg; |
while (arg && argn) { |
argn--; |
arg = arg->common.next; |
} |
return (arg); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_append_arg |
* |
* PARAMETERS: op - Append an argument to this Op. |
* arg - Argument Op to append |
* |
* RETURN: None. |
* |
* DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK) |
* |
******************************************************************************/ |
void |
acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) |
{ |
union acpi_parse_object *prev_arg; |
const struct acpi_opcode_info *op_info; |
ACPI_FUNCTION_ENTRY(); |
if (!op) { |
return; |
} |
/* Get the info structure for this opcode */ |
op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); |
if (op_info->class == AML_CLASS_UNKNOWN) { |
/* Invalid opcode */ |
ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X", |
op->common.aml_opcode)); |
return; |
} |
/* Check if this opcode requires argument sub-objects */ |
if (!(op_info->flags & AML_HAS_ARGS)) { |
/* Has no linked argument objects */ |
return; |
} |
/* Append the argument to the linked argument list */ |
if (op->common.value.arg) { |
/* Append to existing argument list */ |
prev_arg = op->common.value.arg; |
while (prev_arg->common.next) { |
prev_arg = prev_arg->common.next; |
} |
prev_arg->common.next = arg; |
} else { |
/* No argument list, this will be the first argument */ |
op->common.value.arg = arg; |
} |
/* Set the parent in this arg and any args linked after it */ |
while (arg) { |
arg->common.parent = op; |
arg = arg->common.next; |
op->common.arg_list_length++; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_depth_next |
* |
* PARAMETERS: origin - Root of subtree to search |
* op - Last (previous) Op that was found |
* |
* RETURN: Next Op found in the search. |
* |
* DESCRIPTION: Get next op in tree (walking the tree in depth-first order) |
* Return NULL when reaching "origin" or when walking up from root |
* |
******************************************************************************/ |
union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, |
union acpi_parse_object *op) |
{ |
union acpi_parse_object *next = NULL; |
union acpi_parse_object *parent; |
union acpi_parse_object *arg; |
ACPI_FUNCTION_ENTRY(); |
if (!op) { |
return (NULL); |
} |
/* Look for an argument or child */ |
next = acpi_ps_get_arg(op, 0); |
if (next) { |
return (next); |
} |
/* Look for a sibling */ |
next = op->common.next; |
if (next) { |
return (next); |
} |
/* Look for a sibling of parent */ |
parent = op->common.parent; |
while (parent) { |
arg = acpi_ps_get_arg(parent, 0); |
while (arg && (arg != origin) && (arg != op)) { |
arg = arg->common.next; |
} |
if (arg == origin) { |
/* Reached parent of origin, end search */ |
return (NULL); |
} |
if (parent->common.next) { |
/* Found sibling of parent */ |
return (parent->common.next); |
} |
op = parent; |
parent = parent->common.parent; |
} |
return (next); |
} |
#ifdef ACPI_OBSOLETE_FUNCTIONS |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_get_child |
* |
* PARAMETERS: op - Get the child of this Op |
* |
* RETURN: Child Op, Null if none is found. |
* |
* DESCRIPTION: Get op's children or NULL if none |
* |
******************************************************************************/ |
union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op) |
{ |
union acpi_parse_object *child = NULL; |
ACPI_FUNCTION_ENTRY(); |
switch (op->common.aml_opcode) { |
case AML_SCOPE_OP: |
case AML_ELSE_OP: |
case AML_DEVICE_OP: |
case AML_THERMAL_ZONE_OP: |
case AML_INT_METHODCALL_OP: |
child = acpi_ps_get_arg(op, 0); |
break; |
case AML_BUFFER_OP: |
case AML_PACKAGE_OP: |
case AML_METHOD_OP: |
case AML_IF_OP: |
case AML_WHILE_OP: |
case AML_FIELD_OP: |
child = acpi_ps_get_arg(op, 1); |
break; |
case AML_POWER_RES_OP: |
case AML_INDEX_FIELD_OP: |
child = acpi_ps_get_arg(op, 2); |
break; |
case AML_PROCESSOR_OP: |
case AML_BANK_FIELD_OP: |
child = acpi_ps_get_arg(op, 3); |
break; |
default: |
/* All others have no children */ |
break; |
} |
return (child); |
} |
#endif |
/drivers/acpi/acpica/psutils.c |
---|
0,0 → 1,235 |
/****************************************************************************** |
* |
* Module Name: psutils - Parser miscellaneous utilities (Parser only) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "amlcode.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psutils") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_create_scope_op |
* |
* PARAMETERS: None |
* |
* RETURN: A new Scope object, null on failure |
* |
* DESCRIPTION: Create a Scope and associated namepath op with the root name |
* |
******************************************************************************/ |
union acpi_parse_object *acpi_ps_create_scope_op(u8 *aml) |
{ |
union acpi_parse_object *scope_op; |
scope_op = acpi_ps_alloc_op(AML_SCOPE_OP, aml); |
if (!scope_op) { |
return (NULL); |
} |
scope_op->named.name = ACPI_ROOT_NAME; |
return (scope_op); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_init_op |
* |
* PARAMETERS: op - A newly allocated Op object |
* opcode - Opcode to store in the Op |
* |
* RETURN: None |
* |
* DESCRIPTION: Initialize a parse (Op) object |
* |
******************************************************************************/ |
void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) |
{ |
ACPI_FUNCTION_ENTRY(); |
op->common.descriptor_type = ACPI_DESC_TYPE_PARSER; |
op->common.aml_opcode = opcode; |
ACPI_DISASM_ONLY_MEMBERS(strncpy(op->common.aml_op_name, |
(acpi_ps_get_opcode_info(opcode))-> |
name, sizeof(op->common.aml_op_name))); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_alloc_op |
* |
* PARAMETERS: opcode - Opcode that will be stored in the new Op |
* aml - Address of the opcode |
* |
* RETURN: Pointer to the new Op, null on failure |
* |
* DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on |
* opcode. A cache of opcodes is available for the pure |
* GENERIC_OP, since this is by far the most commonly used. |
* |
******************************************************************************/ |
union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml) |
{ |
union acpi_parse_object *op; |
const struct acpi_opcode_info *op_info; |
u8 flags = ACPI_PARSEOP_GENERIC; |
ACPI_FUNCTION_ENTRY(); |
op_info = acpi_ps_get_opcode_info(opcode); |
/* Determine type of parse_op required */ |
if (op_info->flags & AML_DEFER) { |
flags = ACPI_PARSEOP_DEFERRED; |
} else if (op_info->flags & AML_NAMED) { |
flags = ACPI_PARSEOP_NAMED; |
} else if (opcode == AML_INT_BYTELIST_OP) { |
flags = ACPI_PARSEOP_BYTELIST; |
} |
/* Allocate the minimum required size object */ |
if (flags == ACPI_PARSEOP_GENERIC) { |
/* The generic op (default) is by far the most common (16 to 1) */ |
op = acpi_os_acquire_object(acpi_gbl_ps_node_cache); |
} else { |
/* Extended parseop */ |
op = acpi_os_acquire_object(acpi_gbl_ps_node_ext_cache); |
} |
/* Initialize the Op */ |
if (op) { |
acpi_ps_init_op(op, opcode); |
op->common.aml = aml; |
op->common.flags = flags; |
} |
return (op); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_free_op |
* |
* PARAMETERS: op - Op to be freed |
* |
* RETURN: None. |
* |
* DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list |
* or actually free it. |
* |
******************************************************************************/ |
void acpi_ps_free_op(union acpi_parse_object *op) |
{ |
ACPI_FUNCTION_NAME(ps_free_op); |
if (op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", |
op)); |
} |
if (op->common.flags & ACPI_PARSEOP_GENERIC) { |
(void)acpi_os_release_object(acpi_gbl_ps_node_cache, op); |
} else { |
(void)acpi_os_release_object(acpi_gbl_ps_node_ext_cache, op); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: Utility functions |
* |
* DESCRIPTION: Low level character and object functions |
* |
******************************************************************************/ |
/* |
* Is "c" a namestring lead character? |
*/ |
u8 acpi_ps_is_leading_char(u32 c) |
{ |
return ((u8) (c == '_' || (c >= 'A' && c <= 'Z'))); |
} |
/* |
* Get op's name (4-byte name segment) or 0 if unnamed |
*/ |
u32 acpi_ps_get_name(union acpi_parse_object * op) |
{ |
/* The "generic" object has no name associated with it */ |
if (op->common.flags & ACPI_PARSEOP_GENERIC) { |
return (0); |
} |
/* Only the "Extended" parse objects have a name */ |
return (op->named.name); |
} |
/* |
* Set op's name |
*/ |
void acpi_ps_set_name(union acpi_parse_object *op, u32 name) |
{ |
/* The "generic" object has no name associated with it */ |
if (op->common.flags & ACPI_PARSEOP_GENERIC) { |
return; |
} |
op->named.name = name; |
} |
/drivers/acpi/acpica/pswalk.c |
---|
0,0 → 1,110 |
/****************************************************************************** |
* |
* Module Name: pswalk - Parser routines to walk parsed op tree(s) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("pswalk") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_delete_parse_tree |
* |
* PARAMETERS: subtree_root - Root of tree (or subtree) to delete |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete a portion of or an entire parse tree. |
* |
******************************************************************************/ |
void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) |
{ |
union acpi_parse_object *op = subtree_root; |
union acpi_parse_object *next = NULL; |
union acpi_parse_object *parent = NULL; |
ACPI_FUNCTION_TRACE_PTR(ps_delete_parse_tree, subtree_root); |
/* Visit all nodes in the subtree */ |
while (op) { |
/* Check if we are not ascending */ |
if (op != parent) { |
/* Look for an argument or child of the current op */ |
next = acpi_ps_get_arg(op, 0); |
if (next) { |
/* Still going downward in tree (Op is not completed yet) */ |
op = next; |
continue; |
} |
} |
/* No more children, this Op is complete. */ |
next = op->common.next; |
parent = op->common.parent; |
acpi_ps_free_op(op); |
/* If we are back to the starting point, the walk is complete. */ |
if (op == subtree_root) { |
return_VOID; |
} |
if (next) { |
op = next; |
} else { |
op = parent; |
} |
} |
return_VOID; |
} |
/drivers/acpi/acpica/psxface.c |
---|
0,0 → 1,285 |
/****************************************************************************** |
* |
* Module Name: psxface - Parser external interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acparser.h" |
#include "acdispat.h" |
#include "acinterp.h" |
#include "actables.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME("psxface") |
/* Local Prototypes */ |
static void |
acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); |
/******************************************************************************* |
* |
* FUNCTION: acpi_debug_trace |
* |
* PARAMETERS: method_name - Valid ACPI name string |
* debug_level - Optional level mask. 0 to use default |
* debug_layer - Optional layer mask. 0 to use default |
* flags - bit 1: one shot(1) or persistent(0) |
* |
* RETURN: Status |
* |
* DESCRIPTION: External interface to enable debug tracing during control |
* method execution |
* |
******************************************************************************/ |
acpi_status |
acpi_debug_trace(const char *name, u32 debug_level, u32 debug_layer, u32 flags) |
{ |
acpi_status status; |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
acpi_gbl_trace_method_name = name; |
acpi_gbl_trace_flags = flags; |
acpi_gbl_trace_dbg_level = debug_level; |
acpi_gbl_trace_dbg_layer = debug_layer; |
status = AE_OK; |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_execute_method |
* |
* PARAMETERS: info - Method info block, contains: |
* node - Method Node to execute |
* obj_desc - Method object |
* parameters - List of parameters to pass to the method, |
* terminated by NULL. Params itself may be |
* NULL if no parameters are being passed. |
* return_object - Where to put method's return value (if |
* any). If NULL, no value is returned. |
* parameter_type - Type of Parameter list |
* return_object - Where to put method's return value (if |
* any). If NULL, no value is returned. |
* pass_number - Parse or execute pass |
* |
* RETURN: Status |
* |
* DESCRIPTION: Execute a control method |
* |
******************************************************************************/ |
acpi_status acpi_ps_execute_method(struct acpi_evaluate_info * info) |
{ |
acpi_status status; |
union acpi_parse_object *op; |
struct acpi_walk_state *walk_state; |
ACPI_FUNCTION_TRACE(ps_execute_method); |
/* Quick validation of DSDT header */ |
acpi_tb_check_dsdt_header(); |
/* Validate the Info and method Node */ |
if (!info || !info->node) { |
return_ACPI_STATUS(AE_NULL_ENTRY); |
} |
/* Init for new method, wait on concurrency semaphore */ |
status = |
acpi_ds_begin_method_execution(info->node, info->obj_desc, NULL); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* The caller "owns" the parameters, so give each one an extra reference |
*/ |
acpi_ps_update_parameter_list(info, REF_INCREMENT); |
/* |
* Execute the method. Performs parse simultaneously |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
"**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n", |
info->node->name.ascii, info->node, info->obj_desc)); |
/* Create and init a Root Node */ |
op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); |
if (!op) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Create and initialize a new walk state */ |
info->pass_number = ACPI_IMODE_EXECUTE; |
walk_state = |
acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, |
NULL, NULL); |
if (!walk_state) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
status = acpi_ds_init_aml_walk(walk_state, op, info->node, |
info->obj_desc->method.aml_start, |
info->obj_desc->method.aml_length, info, |
info->pass_number); |
if (ACPI_FAILURE(status)) { |
acpi_ds_delete_walk_state(walk_state); |
goto cleanup; |
} |
if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { |
walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; |
} |
/* Invoke an internal method if necessary */ |
if (info->obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { |
status = |
info->obj_desc->method.dispatch.implementation(walk_state); |
info->return_object = walk_state->return_desc; |
/* Cleanup states */ |
acpi_ds_scope_stack_clear(walk_state); |
acpi_ps_cleanup_scope(&walk_state->parser_state); |
acpi_ds_terminate_control_method(walk_state->method_desc, |
walk_state); |
acpi_ds_delete_walk_state(walk_state); |
goto cleanup; |
} |
/* |
* Start method evaluation with an implicit return of zero. |
* This is done for Windows compatibility. |
*/ |
if (acpi_gbl_enable_interpreter_slack) { |
walk_state->implicit_return_obj = |
acpi_ut_create_integer_object((u64) 0); |
if (!walk_state->implicit_return_obj) { |
status = AE_NO_MEMORY; |
acpi_ds_delete_walk_state(walk_state); |
goto cleanup; |
} |
} |
/* Parse the AML */ |
status = acpi_ps_parse_aml(walk_state); |
/* walk_state was deleted by parse_aml */ |
cleanup: |
acpi_ps_delete_parse_tree(op); |
/* Take away the extra reference that we gave the parameters above */ |
acpi_ps_update_parameter_list(info, REF_DECREMENT); |
/* Exit now if error above */ |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* If the method has returned an object, signal this to the caller with |
* a control exception code |
*/ |
if (info->return_object) { |
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Method returned ObjDesc=%p\n", |
info->return_object)); |
ACPI_DUMP_STACK_ENTRY(info->return_object); |
status = AE_CTRL_RETURN_VALUE; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ps_update_parameter_list |
* |
* PARAMETERS: info - See struct acpi_evaluate_info |
* (Used: parameter_type and Parameters) |
* action - Add or Remove reference |
* |
* RETURN: Status |
* |
* DESCRIPTION: Update reference count on all method parameter objects |
* |
******************************************************************************/ |
static void |
acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action) |
{ |
u32 i; |
if (info->parameters) { |
/* Update reference count for each parameter */ |
for (i = 0; info->parameters[i]; i++) { |
/* Ignore errors, just do them all */ |
(void)acpi_ut_update_object_reference(info-> |
parameters[i], |
action); |
} |
} |
} |
/drivers/acpi/acpica/rsaddr.c |
---|
0,0 → 1,382 |
/******************************************************************************* |
* |
* Module Name: rsaddr - Address resource descriptors (16/32/64) |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsaddr") |
/******************************************************************************* |
* |
* acpi_rs_convert_address16 - All WORD (16-bit) address resources |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_address16[5] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_ADDRESS16, |
ACPI_RS_SIZE(struct acpi_resource_address16), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_address16)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_ADDRESS16, |
sizeof(struct aml_resource_address16), |
0}, |
/* Resource Type, General Flags, and Type-Specific Flags */ |
{ACPI_RSC_ADDRESS, 0, 0, 0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Address Granularity |
* Address Range Minimum |
* Address Range Maximum |
* Address Translation Offset |
* Address Length |
*/ |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.address16.address.granularity), |
AML_OFFSET(address16.granularity), |
5}, |
/* Optional resource_source (Index and String) */ |
{ACPI_RSC_SOURCE, ACPI_RS_OFFSET(data.address16.resource_source), |
0, |
sizeof(struct aml_resource_address16)} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_address32 - All DWORD (32-bit) address resources |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_address32[5] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_ADDRESS32, |
ACPI_RS_SIZE(struct acpi_resource_address32), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_address32)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_ADDRESS32, |
sizeof(struct aml_resource_address32), |
0}, |
/* Resource Type, General Flags, and Type-Specific Flags */ |
{ACPI_RSC_ADDRESS, 0, 0, 0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Address Granularity |
* Address Range Minimum |
* Address Range Maximum |
* Address Translation Offset |
* Address Length |
*/ |
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.address32.address.granularity), |
AML_OFFSET(address32.granularity), |
5}, |
/* Optional resource_source (Index and String) */ |
{ACPI_RSC_SOURCE, ACPI_RS_OFFSET(data.address32.resource_source), |
0, |
sizeof(struct aml_resource_address32)} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_address64 - All QWORD (64-bit) address resources |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_address64[5] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_ADDRESS64, |
ACPI_RS_SIZE(struct acpi_resource_address64), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_address64)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_ADDRESS64, |
sizeof(struct aml_resource_address64), |
0}, |
/* Resource Type, General Flags, and Type-Specific Flags */ |
{ACPI_RSC_ADDRESS, 0, 0, 0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Address Granularity |
* Address Range Minimum |
* Address Range Maximum |
* Address Translation Offset |
* Address Length |
*/ |
{ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.address64.address.granularity), |
AML_OFFSET(address64.granularity), |
5}, |
/* Optional resource_source (Index and String) */ |
{ACPI_RSC_SOURCE, ACPI_RS_OFFSET(data.address64.resource_source), |
0, |
sizeof(struct aml_resource_address64)} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_ext_address64 - All Extended (64-bit) address resources |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_ext_address64[5] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64, |
ACPI_RS_SIZE(struct acpi_resource_extended_address64), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_ext_address64)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64, |
sizeof(struct aml_resource_extended_address64), |
0}, |
/* Resource Type, General Flags, and Type-Specific Flags */ |
{ACPI_RSC_ADDRESS, 0, 0, 0}, |
/* Revision ID */ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.ext_address64.revision_ID), |
AML_OFFSET(ext_address64.revision_ID), |
1}, |
/* |
* These fields are contiguous in both the source and destination: |
* Address Granularity |
* Address Range Minimum |
* Address Range Maximum |
* Address Translation Offset |
* Address Length |
* Type-Specific Attribute |
*/ |
{ACPI_RSC_MOVE64, |
ACPI_RS_OFFSET(data.ext_address64.address.granularity), |
AML_OFFSET(ext_address64.granularity), |
6} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_general_flags - Flags common to all address descriptors |
* |
******************************************************************************/ |
static struct acpi_rsconvert_info acpi_rs_convert_general_flags[6] = { |
{ACPI_RSC_FLAGINIT, 0, AML_OFFSET(address.flags), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_general_flags)}, |
/* Resource Type (Memory, Io, bus_number, etc.) */ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.address.resource_type), |
AML_OFFSET(address.resource_type), |
1}, |
/* General flags - Consume, Decode, min_fixed, max_fixed */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.address.producer_consumer), |
AML_OFFSET(address.flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.address.decode), |
AML_OFFSET(address.flags), |
1}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.address.min_address_fixed), |
AML_OFFSET(address.flags), |
2}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.address.max_address_fixed), |
AML_OFFSET(address.flags), |
3} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_mem_flags - Flags common to Memory address descriptors |
* |
******************************************************************************/ |
static struct acpi_rsconvert_info acpi_rs_convert_mem_flags[5] = { |
{ACPI_RSC_FLAGINIT, 0, AML_OFFSET(address.specific_flags), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_mem_flags)}, |
/* Memory-specific flags */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.address.info.mem.write_protect), |
AML_OFFSET(address.specific_flags), |
0}, |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.address.info.mem.caching), |
AML_OFFSET(address.specific_flags), |
1}, |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.address.info.mem.range_type), |
AML_OFFSET(address.specific_flags), |
3}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.address.info.mem.translation), |
AML_OFFSET(address.specific_flags), |
5} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_io_flags - Flags common to I/O address descriptors |
* |
******************************************************************************/ |
static struct acpi_rsconvert_info acpi_rs_convert_io_flags[4] = { |
{ACPI_RSC_FLAGINIT, 0, AML_OFFSET(address.specific_flags), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_io_flags)}, |
/* I/O-specific flags */ |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.address.info.io.range_type), |
AML_OFFSET(address.specific_flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.address.info.io.translation), |
AML_OFFSET(address.specific_flags), |
4}, |
{ACPI_RSC_1BITFLAG, |
ACPI_RS_OFFSET(data.address.info.io.translation_type), |
AML_OFFSET(address.specific_flags), |
5} |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_address_common |
* |
* PARAMETERS: resource - Pointer to the internal resource struct |
* aml - Pointer to the AML resource descriptor |
* |
* RETURN: TRUE if the resource_type field is OK, FALSE otherwise |
* |
* DESCRIPTION: Convert common flag fields from a raw AML resource descriptor |
* to an internal resource descriptor |
* |
******************************************************************************/ |
u8 |
acpi_rs_get_address_common(struct acpi_resource *resource, |
union aml_resource *aml) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Validate the Resource Type */ |
if ((aml->address.resource_type > 2) |
&& (aml->address.resource_type < 0xC0)) { |
return (FALSE); |
} |
/* Get the Resource Type and General Flags */ |
(void)acpi_rs_convert_aml_to_resource(resource, aml, |
acpi_rs_convert_general_flags); |
/* Get the Type-Specific Flags (Memory and I/O descriptors only) */ |
if (resource->data.address.resource_type == ACPI_MEMORY_RANGE) { |
(void)acpi_rs_convert_aml_to_resource(resource, aml, |
acpi_rs_convert_mem_flags); |
} else if (resource->data.address.resource_type == ACPI_IO_RANGE) { |
(void)acpi_rs_convert_aml_to_resource(resource, aml, |
acpi_rs_convert_io_flags); |
} else { |
/* Generic resource type, just grab the type_specific byte */ |
resource->data.address.info.type_specific = |
aml->address.specific_flags; |
} |
return (TRUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_set_address_common |
* |
* PARAMETERS: aml - Pointer to the AML resource descriptor |
* resource - Pointer to the internal resource struct |
* |
* RETURN: None |
* |
* DESCRIPTION: Convert common flag fields from a resource descriptor to an |
* AML descriptor |
* |
******************************************************************************/ |
void |
acpi_rs_set_address_common(union aml_resource *aml, |
struct acpi_resource *resource) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Set the Resource Type and General Flags */ |
(void)acpi_rs_convert_resource_to_aml(resource, aml, |
acpi_rs_convert_general_flags); |
/* Set the Type-Specific Flags (Memory and I/O descriptors only) */ |
if (resource->data.address.resource_type == ACPI_MEMORY_RANGE) { |
(void)acpi_rs_convert_resource_to_aml(resource, aml, |
acpi_rs_convert_mem_flags); |
} else if (resource->data.address.resource_type == ACPI_IO_RANGE) { |
(void)acpi_rs_convert_resource_to_aml(resource, aml, |
acpi_rs_convert_io_flags); |
} else { |
/* Generic resource type, just copy the type_specific byte */ |
aml->address.specific_flags = |
resource->data.address.info.type_specific; |
} |
} |
/drivers/acpi/acpica/rscalc.c |
---|
0,0 → 1,718 |
/******************************************************************************* |
* |
* Module Name: rscalc - Calculate stream and list lengths |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rscalc") |
/* Local prototypes */ |
static u8 acpi_rs_count_set_bits(u16 bit_field); |
static acpi_rs_length |
acpi_rs_struct_option_length(struct acpi_resource_source *resource_source); |
static u32 |
acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length); |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_count_set_bits |
* |
* PARAMETERS: bit_field - Field in which to count bits |
* |
* RETURN: Number of bits set within the field |
* |
* DESCRIPTION: Count the number of bits set in a resource field. Used for |
* (Short descriptor) interrupt and DMA lists. |
* |
******************************************************************************/ |
static u8 acpi_rs_count_set_bits(u16 bit_field) |
{ |
u8 bits_set; |
ACPI_FUNCTION_ENTRY(); |
for (bits_set = 0; bit_field; bits_set++) { |
/* Zero the least significant bit that is set */ |
bit_field &= (u16) (bit_field - 1); |
} |
return (bits_set); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_struct_option_length |
* |
* PARAMETERS: resource_source - Pointer to optional descriptor field |
* |
* RETURN: Status |
* |
* DESCRIPTION: Common code to handle optional resource_source_index and |
* resource_source fields in some Large descriptors. Used during |
* list-to-stream conversion |
* |
******************************************************************************/ |
static acpi_rs_length |
acpi_rs_struct_option_length(struct acpi_resource_source *resource_source) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* |
* If the resource_source string is valid, return the size of the string |
* (string_length includes the NULL terminator) plus the size of the |
* resource_source_index (1). |
*/ |
if (resource_source->string_ptr) { |
return ((acpi_rs_length) (resource_source->string_length + 1)); |
} |
return (0); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_stream_option_length |
* |
* PARAMETERS: resource_length - Length from the resource header |
* minimum_total_length - Minimum length of this resource, before |
* any optional fields. Includes header size |
* |
* RETURN: Length of optional string (0 if no string present) |
* |
* DESCRIPTION: Common code to handle optional resource_source_index and |
* resource_source fields in some Large descriptors. Used during |
* stream-to-list conversion |
* |
******************************************************************************/ |
static u32 |
acpi_rs_stream_option_length(u32 resource_length, |
u32 minimum_aml_resource_length) |
{ |
u32 string_length = 0; |
ACPI_FUNCTION_ENTRY(); |
/* |
* The resource_source_index and resource_source are optional elements of some |
* Large-type resource descriptors. |
*/ |
/* |
* If the length of the actual resource descriptor is greater than the ACPI |
* spec-defined minimum length, it means that a resource_source_index exists |
* and is followed by a (required) null terminated string. The string length |
* (including the null terminator) is the resource length minus the minimum |
* length, minus one byte for the resource_source_index itself. |
*/ |
if (resource_length > minimum_aml_resource_length) { |
/* Compute the length of the optional string */ |
string_length = |
resource_length - minimum_aml_resource_length - 1; |
} |
/* |
* Round the length up to a multiple of the native word in order to |
* guarantee that the entire resource descriptor is native word aligned |
*/ |
return ((u32) ACPI_ROUND_UP_TO_NATIVE_WORD(string_length)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_aml_length |
* |
* PARAMETERS: resource - Pointer to the resource linked list |
* resource_list_size - Size of the resource linked list |
* size_needed - Where the required size is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Takes a linked list of internal resource descriptors and |
* calculates the size buffer needed to hold the corresponding |
* external resource byte stream. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_aml_length(struct acpi_resource *resource, |
acpi_size resource_list_size, acpi_size * size_needed) |
{ |
acpi_size aml_size_needed = 0; |
struct acpi_resource *resource_end; |
acpi_rs_length total_size; |
ACPI_FUNCTION_TRACE(rs_get_aml_length); |
/* Traverse entire list of internal resource descriptors */ |
resource_end = |
ACPI_ADD_PTR(struct acpi_resource, resource, resource_list_size); |
while (resource < resource_end) { |
/* Validate the descriptor type */ |
if (resource->type > ACPI_RESOURCE_TYPE_MAX) { |
return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); |
} |
/* Sanity check the length. It must not be zero, or we loop forever */ |
if (!resource->length) { |
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); |
} |
/* Get the base size of the (external stream) resource descriptor */ |
total_size = acpi_gbl_aml_resource_sizes[resource->type]; |
/* |
* Augment the base size for descriptors with optional and/or |
* variable-length fields |
*/ |
switch (resource->type) { |
case ACPI_RESOURCE_TYPE_IRQ: |
/* Length can be 3 or 2 */ |
if (resource->data.irq.descriptor_length == 2) { |
total_size--; |
} |
break; |
case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
/* Length can be 1 or 0 */ |
if (resource->data.irq.descriptor_length == 0) { |
total_size--; |
} |
break; |
case ACPI_RESOURCE_TYPE_VENDOR: |
/* |
* Vendor Defined Resource: |
* For a Vendor Specific resource, if the Length is between 1 and 7 |
* it will be created as a Small Resource data type, otherwise it |
* is a Large Resource data type. |
*/ |
if (resource->data.vendor.byte_length > 7) { |
/* Base size of a Large resource descriptor */ |
total_size = |
sizeof(struct aml_resource_large_header); |
} |
/* Add the size of the vendor-specific data */ |
total_size = (acpi_rs_length) |
(total_size + resource->data.vendor.byte_length); |
break; |
case ACPI_RESOURCE_TYPE_END_TAG: |
/* |
* End Tag: |
* We are done -- return the accumulated total size. |
*/ |
*size_needed = aml_size_needed + total_size; |
/* Normal exit */ |
return_ACPI_STATUS(AE_OK); |
case ACPI_RESOURCE_TYPE_ADDRESS16: |
/* |
* 16-Bit Address Resource: |
* Add the size of the optional resource_source info |
*/ |
total_size = (acpi_rs_length) |
(total_size + |
acpi_rs_struct_option_length(&resource->data. |
address16. |
resource_source)); |
break; |
case ACPI_RESOURCE_TYPE_ADDRESS32: |
/* |
* 32-Bit Address Resource: |
* Add the size of the optional resource_source info |
*/ |
total_size = (acpi_rs_length) |
(total_size + |
acpi_rs_struct_option_length(&resource->data. |
address32. |
resource_source)); |
break; |
case ACPI_RESOURCE_TYPE_ADDRESS64: |
/* |
* 64-Bit Address Resource: |
* Add the size of the optional resource_source info |
*/ |
total_size = (acpi_rs_length) |
(total_size + |
acpi_rs_struct_option_length(&resource->data. |
address64. |
resource_source)); |
break; |
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
/* |
* Extended IRQ Resource: |
* Add the size of each additional optional interrupt beyond the |
* required 1 (4 bytes for each u32 interrupt number) |
*/ |
total_size = (acpi_rs_length) |
(total_size + |
((resource->data.extended_irq.interrupt_count - |
1) * 4) + |
/* Add the size of the optional resource_source info */ |
acpi_rs_struct_option_length(&resource->data. |
extended_irq. |
resource_source)); |
break; |
case ACPI_RESOURCE_TYPE_GPIO: |
total_size = |
(acpi_rs_length) (total_size + |
(resource->data.gpio. |
pin_table_length * 2) + |
resource->data.gpio. |
resource_source.string_length + |
resource->data.gpio. |
vendor_length); |
break; |
case ACPI_RESOURCE_TYPE_SERIAL_BUS: |
total_size = |
acpi_gbl_aml_resource_serial_bus_sizes[resource-> |
data. |
common_serial_bus. |
type]; |
total_size = (acpi_rs_length) (total_size + |
resource->data. |
i2c_serial_bus. |
resource_source. |
string_length + |
resource->data. |
i2c_serial_bus. |
vendor_length); |
break; |
default: |
break; |
} |
/* Update the total */ |
aml_size_needed += total_size; |
/* Point to the next object */ |
resource = |
ACPI_ADD_PTR(struct acpi_resource, resource, |
resource->length); |
} |
/* Did not find an end_tag resource descriptor */ |
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_list_length |
* |
* PARAMETERS: aml_buffer - Pointer to the resource byte stream |
* aml_buffer_length - Size of aml_buffer |
* size_needed - Where the size needed is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Takes an external resource byte stream and calculates the size |
* buffer needed to hold the corresponding internal resource |
* descriptor linked list. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_list_length(u8 * aml_buffer, |
u32 aml_buffer_length, acpi_size * size_needed) |
{ |
acpi_status status; |
u8 *end_aml; |
u8 *buffer; |
u32 buffer_size; |
u16 temp16; |
u16 resource_length; |
u32 extra_struct_bytes; |
u8 resource_index; |
u8 minimum_aml_resource_length; |
union aml_resource *aml_resource; |
ACPI_FUNCTION_TRACE(rs_get_list_length); |
*size_needed = ACPI_RS_SIZE_MIN; /* Minimum size is one end_tag */ |
end_aml = aml_buffer + aml_buffer_length; |
/* Walk the list of AML resource descriptors */ |
while (aml_buffer < end_aml) { |
/* Validate the Resource Type and Resource Length */ |
status = |
acpi_ut_validate_resource(NULL, aml_buffer, |
&resource_index); |
if (ACPI_FAILURE(status)) { |
/* |
* Exit on failure. Cannot continue because the descriptor length |
* may be bogus also. |
*/ |
return_ACPI_STATUS(status); |
} |
aml_resource = (void *)aml_buffer; |
/* Get the resource length and base (minimum) AML size */ |
resource_length = acpi_ut_get_resource_length(aml_buffer); |
minimum_aml_resource_length = |
acpi_gbl_resource_aml_sizes[resource_index]; |
/* |
* Augment the size for descriptors with optional |
* and/or variable length fields |
*/ |
extra_struct_bytes = 0; |
buffer = |
aml_buffer + acpi_ut_get_resource_header_length(aml_buffer); |
switch (acpi_ut_get_resource_type(aml_buffer)) { |
case ACPI_RESOURCE_NAME_IRQ: |
/* |
* IRQ Resource: |
* Get the number of bits set in the 16-bit IRQ mask |
*/ |
ACPI_MOVE_16_TO_16(&temp16, buffer); |
extra_struct_bytes = acpi_rs_count_set_bits(temp16); |
break; |
case ACPI_RESOURCE_NAME_DMA: |
/* |
* DMA Resource: |
* Get the number of bits set in the 8-bit DMA mask |
*/ |
extra_struct_bytes = acpi_rs_count_set_bits(*buffer); |
break; |
case ACPI_RESOURCE_NAME_VENDOR_SMALL: |
case ACPI_RESOURCE_NAME_VENDOR_LARGE: |
/* |
* Vendor Resource: |
* Get the number of vendor data bytes |
*/ |
extra_struct_bytes = resource_length; |
/* |
* There is already one byte included in the minimum |
* descriptor size. If there are extra struct bytes, |
* subtract one from the count. |
*/ |
if (extra_struct_bytes) { |
extra_struct_bytes--; |
} |
break; |
case ACPI_RESOURCE_NAME_END_TAG: |
/* |
* End Tag: This is the normal exit |
*/ |
return_ACPI_STATUS(AE_OK); |
case ACPI_RESOURCE_NAME_ADDRESS32: |
case ACPI_RESOURCE_NAME_ADDRESS16: |
case ACPI_RESOURCE_NAME_ADDRESS64: |
/* |
* Address Resource: |
* Add the size of the optional resource_source |
*/ |
extra_struct_bytes = |
acpi_rs_stream_option_length(resource_length, |
minimum_aml_resource_length); |
break; |
case ACPI_RESOURCE_NAME_EXTENDED_IRQ: |
/* |
* Extended IRQ Resource: |
* Using the interrupt_table_length, add 4 bytes for each additional |
* interrupt. Note: at least one interrupt is required and is |
* included in the minimum descriptor size (reason for the -1) |
*/ |
extra_struct_bytes = (buffer[1] - 1) * sizeof(u32); |
/* Add the size of the optional resource_source */ |
extra_struct_bytes += |
acpi_rs_stream_option_length(resource_length - |
extra_struct_bytes, |
minimum_aml_resource_length); |
break; |
case ACPI_RESOURCE_NAME_GPIO: |
/* Vendor data is optional */ |
if (aml_resource->gpio.vendor_length) { |
extra_struct_bytes += |
aml_resource->gpio.vendor_offset - |
aml_resource->gpio.pin_table_offset + |
aml_resource->gpio.vendor_length; |
} else { |
extra_struct_bytes += |
aml_resource->large_header.resource_length + |
sizeof(struct aml_resource_large_header) - |
aml_resource->gpio.pin_table_offset; |
} |
break; |
case ACPI_RESOURCE_NAME_SERIAL_BUS: |
minimum_aml_resource_length = |
acpi_gbl_resource_aml_serial_bus_sizes |
[aml_resource->common_serial_bus.type]; |
extra_struct_bytes += |
aml_resource->common_serial_bus.resource_length - |
minimum_aml_resource_length; |
break; |
default: |
break; |
} |
/* |
* Update the required buffer size for the internal descriptor structs |
* |
* Important: Round the size up for the appropriate alignment. This |
* is a requirement on IA64. |
*/ |
if (acpi_ut_get_resource_type(aml_buffer) == |
ACPI_RESOURCE_NAME_SERIAL_BUS) { |
buffer_size = |
acpi_gbl_resource_struct_serial_bus_sizes |
[aml_resource->common_serial_bus.type] + |
extra_struct_bytes; |
} else { |
buffer_size = |
acpi_gbl_resource_struct_sizes[resource_index] + |
extra_struct_bytes; |
} |
buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); |
*size_needed += buffer_size; |
ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
"Type %.2X, AmlLength %.2X InternalLength %.2X\n", |
acpi_ut_get_resource_type(aml_buffer), |
acpi_ut_get_descriptor_length(aml_buffer), |
buffer_size)); |
/* |
* Point to the next resource within the AML stream using the length |
* contained in the resource descriptor header |
*/ |
aml_buffer += acpi_ut_get_descriptor_length(aml_buffer); |
} |
/* Did not find an end_tag resource descriptor */ |
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_pci_routing_table_length |
* |
* PARAMETERS: package_object - Pointer to the package object |
* buffer_size_needed - u32 pointer of the size buffer |
* needed to properly return the |
* parsed data |
* |
* RETURN: Status |
* |
* DESCRIPTION: Given a package representing a PCI routing table, this |
* calculates the size of the corresponding linked list of |
* descriptions. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, |
acpi_size * buffer_size_needed) |
{ |
u32 number_of_elements; |
acpi_size temp_size_needed = 0; |
union acpi_operand_object **top_object_list; |
u32 index; |
union acpi_operand_object *package_element; |
union acpi_operand_object **sub_object_list; |
u8 name_found; |
u32 table_index; |
ACPI_FUNCTION_TRACE(rs_get_pci_routing_table_length); |
number_of_elements = package_object->package.count; |
/* |
* Calculate the size of the return buffer. |
* The base size is the number of elements * the sizes of the |
* structures. Additional space for the strings is added below. |
* The minus one is to subtract the size of the u8 Source[1] |
* member because it is added below. |
* |
* But each PRT_ENTRY structure has a pointer to a string and |
* the size of that string must be found. |
*/ |
top_object_list = package_object->package.elements; |
for (index = 0; index < number_of_elements; index++) { |
/* Dereference the subpackage */ |
package_element = *top_object_list; |
/* We must have a valid Package object */ |
if (!package_element || |
(package_element->common.type != ACPI_TYPE_PACKAGE)) { |
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
} |
/* |
* The sub_object_list will now point to an array of the |
* four IRQ elements: Address, Pin, Source and source_index |
*/ |
sub_object_list = package_element->package.elements; |
/* Scan the irq_table_elements for the Source Name String */ |
name_found = FALSE; |
for (table_index = 0; |
table_index < package_element->package.count |
&& !name_found; table_index++) { |
if (*sub_object_list && /* Null object allowed */ |
((ACPI_TYPE_STRING == |
(*sub_object_list)->common.type) || |
((ACPI_TYPE_LOCAL_REFERENCE == |
(*sub_object_list)->common.type) && |
((*sub_object_list)->reference.class == |
ACPI_REFCLASS_NAME)))) { |
name_found = TRUE; |
} else { |
/* Look at the next element */ |
sub_object_list++; |
} |
} |
temp_size_needed += (sizeof(struct acpi_pci_routing_table) - 4); |
/* Was a String type found? */ |
if (name_found) { |
if ((*sub_object_list)->common.type == ACPI_TYPE_STRING) { |
/* |
* The length String.Length field does not include the |
* terminating NULL, add 1 |
*/ |
temp_size_needed += ((acpi_size) |
(*sub_object_list)->string. |
length + 1); |
} else { |
temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); |
} |
} else { |
/* |
* If no name was found, then this is a NULL, which is |
* translated as a u32 zero. |
*/ |
temp_size_needed += sizeof(u32); |
} |
/* Round up the size since each element must be aligned */ |
temp_size_needed = ACPI_ROUND_UP_TO_64BIT(temp_size_needed); |
/* Point to the next union acpi_operand_object */ |
top_object_list++; |
} |
/* |
* Add an extra element to the end of the list, essentially a |
* NULL terminator |
*/ |
*buffer_size_needed = |
temp_size_needed + sizeof(struct acpi_pci_routing_table); |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/rscreate.c |
---|
0,0 → 1,483 |
/******************************************************************************* |
* |
* Module Name: rscreate - Create resource lists/tables |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rscreate") |
/******************************************************************************* |
* |
* FUNCTION: acpi_buffer_to_resource |
* |
* PARAMETERS: aml_buffer - Pointer to the resource byte stream |
* aml_buffer_length - Length of the aml_buffer |
* resource_ptr - Where the converted resource is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert a raw AML buffer to a resource list |
* |
******************************************************************************/ |
acpi_status |
acpi_buffer_to_resource(u8 *aml_buffer, |
u16 aml_buffer_length, |
struct acpi_resource **resource_ptr) |
{ |
acpi_status status; |
acpi_size list_size_needed; |
void *resource; |
void *current_resource_ptr; |
ACPI_FUNCTION_TRACE(acpi_buffer_to_resource); |
/* |
* Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag |
* is not required here. |
*/ |
/* Get the required length for the converted resource */ |
status = acpi_rs_get_list_length(aml_buffer, aml_buffer_length, |
&list_size_needed); |
if (status == AE_AML_NO_RESOURCE_END_TAG) { |
status = AE_OK; |
} |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Allocate a buffer for the converted resource */ |
resource = ACPI_ALLOCATE_ZEROED(list_size_needed); |
current_resource_ptr = resource; |
if (!resource) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Perform the AML-to-Resource conversion */ |
status = acpi_ut_walk_aml_resources(NULL, aml_buffer, aml_buffer_length, |
acpi_rs_convert_aml_to_resources, |
¤t_resource_ptr); |
if (status == AE_AML_NO_RESOURCE_END_TAG) { |
status = AE_OK; |
} |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(resource); |
} else { |
*resource_ptr = resource; |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_buffer_to_resource) |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_create_resource_list |
* |
* PARAMETERS: aml_buffer - Pointer to the resource byte stream |
* output_buffer - Pointer to the user's buffer |
* |
* RETURN: Status: AE_OK if okay, else a valid acpi_status code |
* If output_buffer is not large enough, output_buffer_length |
* indicates how large output_buffer should be, else it |
* indicates how may u8 elements of output_buffer are valid. |
* |
* DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method |
* execution and parses the stream to create a linked list |
* of device resources. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, |
struct acpi_buffer *output_buffer) |
{ |
acpi_status status; |
u8 *aml_start; |
acpi_size list_size_needed = 0; |
u32 aml_buffer_length; |
void *resource; |
ACPI_FUNCTION_TRACE(rs_create_resource_list); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlBuffer = %p\n", aml_buffer)); |
/* Params already validated, so we don't re-validate here */ |
aml_buffer_length = aml_buffer->buffer.length; |
aml_start = aml_buffer->buffer.pointer; |
/* |
* Pass the aml_buffer into a module that can calculate |
* the buffer size needed for the linked list |
*/ |
status = acpi_rs_get_list_length(aml_start, aml_buffer_length, |
&list_size_needed); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Status=%X ListSizeNeeded=%X\n", |
status, (u32) list_size_needed)); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Validate/Allocate/Clear caller buffer */ |
status = acpi_ut_initialize_buffer(output_buffer, list_size_needed); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Do the conversion */ |
resource = output_buffer->pointer; |
status = acpi_ut_walk_aml_resources(NULL, aml_start, aml_buffer_length, |
acpi_rs_convert_aml_to_resources, |
&resource); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", |
output_buffer->pointer, (u32) output_buffer->length)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_create_pci_routing_table |
* |
* PARAMETERS: package_object - Pointer to a package containing one |
* of more ACPI_OPERAND_OBJECTs |
* output_buffer - Pointer to the user's buffer |
* |
* RETURN: Status AE_OK if okay, else a valid acpi_status code. |
* If the output_buffer is too small, the error will be |
* AE_BUFFER_OVERFLOW and output_buffer->Length will point |
* to the size buffer needed. |
* |
* DESCRIPTION: Takes the union acpi_operand_object package and creates a |
* linked list of PCI interrupt descriptions |
* |
* NOTE: It is the caller's responsibility to ensure that the start of the |
* output buffer is aligned properly (if necessary). |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, |
struct acpi_buffer *output_buffer) |
{ |
u8 *buffer; |
union acpi_operand_object **top_object_list; |
union acpi_operand_object **sub_object_list; |
union acpi_operand_object *obj_desc; |
acpi_size buffer_size_needed = 0; |
u32 number_of_elements; |
u32 index; |
struct acpi_pci_routing_table *user_prt; |
struct acpi_namespace_node *node; |
acpi_status status; |
struct acpi_buffer path_buffer; |
ACPI_FUNCTION_TRACE(rs_create_pci_routing_table); |
/* Params already validated, so we don't re-validate here */ |
/* Get the required buffer length */ |
status = acpi_rs_get_pci_routing_table_length(package_object, |
&buffer_size_needed); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "BufferSizeNeeded = %X\n", |
(u32) buffer_size_needed)); |
/* Validate/Allocate/Clear caller buffer */ |
status = acpi_ut_initialize_buffer(output_buffer, buffer_size_needed); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a |
* package that in turn contains an u64 Address, a u8 Pin, |
* a Name, and a u8 source_index. |
*/ |
top_object_list = package_object->package.elements; |
number_of_elements = package_object->package.count; |
buffer = output_buffer->pointer; |
user_prt = ACPI_CAST_PTR(struct acpi_pci_routing_table, buffer); |
for (index = 0; index < number_of_elements; index++) { |
/* |
* Point user_prt past this current structure |
* |
* NOTE: On the first iteration, user_prt->Length will |
* be zero because we cleared the return buffer earlier |
*/ |
buffer += user_prt->length; |
user_prt = ACPI_CAST_PTR(struct acpi_pci_routing_table, buffer); |
/* |
* Fill in the Length field with the information we have at this point. |
* The minus four is to subtract the size of the u8 Source[4] member |
* because it is added below. |
*/ |
user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4); |
/* Each subpackage must be of length 4 */ |
if ((*top_object_list)->package.count != 4) { |
ACPI_ERROR((AE_INFO, |
"(PRT[%u]) Need package of length 4, found length %u", |
index, (*top_object_list)->package.count)); |
return_ACPI_STATUS(AE_AML_PACKAGE_LIMIT); |
} |
/* |
* Dereference the subpackage. |
* The sub_object_list will now point to an array of the four IRQ |
* elements: [Address, Pin, Source, source_index] |
*/ |
sub_object_list = (*top_object_list)->package.elements; |
/* 1) First subobject: Dereference the PRT.Address */ |
obj_desc = sub_object_list[0]; |
if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) { |
ACPI_ERROR((AE_INFO, |
"(PRT[%u].Address) Need Integer, found %s", |
index, |
acpi_ut_get_object_type_name(obj_desc))); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
user_prt->address = obj_desc->integer.value; |
/* 2) Second subobject: Dereference the PRT.Pin */ |
obj_desc = sub_object_list[1]; |
if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) { |
ACPI_ERROR((AE_INFO, |
"(PRT[%u].Pin) Need Integer, found %s", |
index, |
acpi_ut_get_object_type_name(obj_desc))); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
user_prt->pin = (u32) obj_desc->integer.value; |
/* |
* 3) Third subobject: Dereference the PRT.source_name |
* The name may be unresolved (slack mode), so allow a null object |
*/ |
obj_desc = sub_object_list[2]; |
if (obj_desc) { |
switch (obj_desc->common.type) { |
case ACPI_TYPE_LOCAL_REFERENCE: |
if (obj_desc->reference.class != |
ACPI_REFCLASS_NAME) { |
ACPI_ERROR((AE_INFO, |
"(PRT[%u].Source) Need name, found Reference Class 0x%X", |
index, |
obj_desc->reference.class)); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
node = obj_desc->reference.node; |
/* Use *remaining* length of the buffer as max for pathname */ |
path_buffer.length = output_buffer->length - |
(u32) ((u8 *) user_prt->source - |
(u8 *) output_buffer->pointer); |
path_buffer.pointer = user_prt->source; |
status = |
acpi_ns_handle_to_pathname((acpi_handle) |
node, |
&path_buffer, |
FALSE); |
/* +1 to include null terminator */ |
user_prt->length += |
(u32)strlen(user_prt->source) + 1; |
break; |
case ACPI_TYPE_STRING: |
strcpy(user_prt->source, |
obj_desc->string.pointer); |
/* |
* Add to the Length field the length of the string |
* (add 1 for terminator) |
*/ |
user_prt->length += obj_desc->string.length + 1; |
break; |
case ACPI_TYPE_INTEGER: |
/* |
* If this is a number, then the Source Name is NULL, since the |
* entire buffer was zeroed out, we can leave this alone. |
* |
* Add to the Length field the length of the u32 NULL |
*/ |
user_prt->length += sizeof(u32); |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"(PRT[%u].Source) Need Ref/String/Integer, found %s", |
index, |
acpi_ut_get_object_type_name |
(obj_desc))); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
} |
/* Now align the current length */ |
user_prt->length = |
(u32) ACPI_ROUND_UP_TO_64BIT(user_prt->length); |
/* 4) Fourth subobject: Dereference the PRT.source_index */ |
obj_desc = sub_object_list[3]; |
if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) { |
ACPI_ERROR((AE_INFO, |
"(PRT[%u].SourceIndex) Need Integer, found %s", |
index, |
acpi_ut_get_object_type_name(obj_desc))); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
user_prt->source_index = (u32) obj_desc->integer.value; |
/* Point to the next union acpi_operand_object in the top level package */ |
top_object_list++; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", |
output_buffer->pointer, (u32) output_buffer->length)); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_create_aml_resources |
* |
* PARAMETERS: resource_list - Pointer to the resource list buffer |
* output_buffer - Where the AML buffer is returned |
* |
* RETURN: Status AE_OK if okay, else a valid acpi_status code. |
* If the output_buffer is too small, the error will be |
* AE_BUFFER_OVERFLOW and output_buffer->Length will point |
* to the size buffer needed. |
* |
* DESCRIPTION: Converts a list of device resources to an AML bytestream |
* to be used as input for the _SRS control method. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_create_aml_resources(struct acpi_buffer *resource_list, |
struct acpi_buffer *output_buffer) |
{ |
acpi_status status; |
acpi_size aml_size_needed = 0; |
ACPI_FUNCTION_TRACE(rs_create_aml_resources); |
/* Params already validated, no need to re-validate here */ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ResourceList Buffer = %p\n", |
resource_list->pointer)); |
/* Get the buffer size needed for the AML byte stream */ |
status = acpi_rs_get_aml_length(resource_list->pointer, |
resource_list->length, |
&aml_size_needed); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n", |
(u32)aml_size_needed, acpi_format_exception(status))); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Validate/Allocate/Clear caller buffer */ |
status = acpi_ut_initialize_buffer(output_buffer, aml_size_needed); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Do the conversion */ |
status = acpi_rs_convert_resources_to_aml(resource_list->pointer, |
aml_size_needed, |
output_buffer->pointer); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", |
output_buffer->pointer, (u32) output_buffer->length)); |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/rsdump.c |
---|
0,0 → 1,566 |
/******************************************************************************* |
* |
* Module Name: rsdump - AML debugger support for resource structures. |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsdump") |
/* |
* All functions in this module are used by the AML Debugger only |
*/ |
/* Local prototypes */ |
static void acpi_rs_out_string(char *title, char *value); |
static void acpi_rs_out_integer8(char *title, u8 value); |
static void acpi_rs_out_integer16(char *title, u16 value); |
static void acpi_rs_out_integer32(char *title, u32 value); |
static void acpi_rs_out_integer64(char *title, u64 value); |
static void acpi_rs_out_title(char *title); |
static void acpi_rs_dump_byte_list(u16 length, u8 *data); |
static void acpi_rs_dump_word_list(u16 length, u16 *data); |
static void acpi_rs_dump_dword_list(u8 length, u32 *data); |
static void acpi_rs_dump_short_byte_list(u8 length, u8 *data); |
static void |
acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source); |
static void acpi_rs_dump_address_common(union acpi_resource_data *resource); |
static void |
acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table); |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_dump_resource_list |
* |
* PARAMETERS: resource_list - Pointer to a resource descriptor list |
* |
* RETURN: None |
* |
* DESCRIPTION: Dispatches the structure to the correct dump routine. |
* |
******************************************************************************/ |
void acpi_rs_dump_resource_list(struct acpi_resource *resource_list) |
{ |
u32 count = 0; |
u32 type; |
ACPI_FUNCTION_ENTRY(); |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) { |
return; |
} |
/* Walk list and dump all resource descriptors (END_TAG terminates) */ |
do { |
acpi_os_printf("\n[%02X] ", count); |
count++; |
/* Validate Type before dispatch */ |
type = resource_list->type; |
if (type > ACPI_RESOURCE_TYPE_MAX) { |
acpi_os_printf |
("Invalid descriptor type (%X) in resource list\n", |
resource_list->type); |
return; |
} |
/* Sanity check the length. It must not be zero, or we loop forever */ |
if (!resource_list->length) { |
acpi_os_printf |
("Invalid zero length descriptor in resource list\n"); |
return; |
} |
/* Dump the resource descriptor */ |
if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { |
acpi_rs_dump_descriptor(&resource_list->data, |
acpi_gbl_dump_serial_bus_dispatch |
[resource_list->data. |
common_serial_bus.type]); |
} else { |
acpi_rs_dump_descriptor(&resource_list->data, |
acpi_gbl_dump_resource_dispatch |
[type]); |
} |
/* Point to the next resource structure */ |
resource_list = ACPI_NEXT_RESOURCE(resource_list); |
/* Exit when END_TAG descriptor is reached */ |
} while (type != ACPI_RESOURCE_TYPE_END_TAG); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_dump_irq_list |
* |
* PARAMETERS: route_table - Pointer to the routing table to dump. |
* |
* RETURN: None |
* |
* DESCRIPTION: Print IRQ routing table |
* |
******************************************************************************/ |
void acpi_rs_dump_irq_list(u8 *route_table) |
{ |
struct acpi_pci_routing_table *prt_element; |
u8 count; |
ACPI_FUNCTION_ENTRY(); |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) { |
return; |
} |
prt_element = ACPI_CAST_PTR(struct acpi_pci_routing_table, route_table); |
/* Dump all table elements, Exit on zero length element */ |
for (count = 0; prt_element->length; count++) { |
acpi_os_printf("\n[%02X] PCI IRQ Routing Table Package\n", |
count); |
acpi_rs_dump_descriptor(prt_element, acpi_rs_dump_prt); |
prt_element = ACPI_ADD_PTR(struct acpi_pci_routing_table, |
prt_element, prt_element->length); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_dump_descriptor |
* |
* PARAMETERS: resource - Buffer containing the resource |
* table - Table entry to decode the resource |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump a resource descriptor based on a dump table entry. |
* |
******************************************************************************/ |
static void |
acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) |
{ |
u8 *target = NULL; |
u8 *previous_target; |
char *name; |
u8 count; |
/* First table entry must contain the table length (# of table entries) */ |
count = table->offset; |
while (count) { |
previous_target = target; |
target = ACPI_ADD_PTR(u8, resource, table->offset); |
name = table->name; |
switch (table->opcode) { |
case ACPI_RSD_TITLE: |
/* |
* Optional resource title |
*/ |
if (table->name) { |
acpi_os_printf("%s Resource\n", name); |
} |
break; |
/* Strings */ |
case ACPI_RSD_LITERAL: |
acpi_rs_out_string(name, |
ACPI_CAST_PTR(char, table->pointer)); |
break; |
case ACPI_RSD_STRING: |
acpi_rs_out_string(name, ACPI_CAST_PTR(char, target)); |
break; |
/* Data items, 8/16/32/64 bit */ |
case ACPI_RSD_UINT8: |
if (table->pointer) { |
acpi_rs_out_string(name, ACPI_CAST_PTR(char, |
table-> |
pointer |
[*target])); |
} else { |
acpi_rs_out_integer8(name, ACPI_GET8(target)); |
} |
break; |
case ACPI_RSD_UINT16: |
acpi_rs_out_integer16(name, ACPI_GET16(target)); |
break; |
case ACPI_RSD_UINT32: |
acpi_rs_out_integer32(name, ACPI_GET32(target)); |
break; |
case ACPI_RSD_UINT64: |
acpi_rs_out_integer64(name, ACPI_GET64(target)); |
break; |
/* Flags: 1-bit and 2-bit flags supported */ |
case ACPI_RSD_1BITFLAG: |
acpi_rs_out_string(name, ACPI_CAST_PTR(char, |
table-> |
pointer[*target & |
0x01])); |
break; |
case ACPI_RSD_2BITFLAG: |
acpi_rs_out_string(name, ACPI_CAST_PTR(char, |
table-> |
pointer[*target & |
0x03])); |
break; |
case ACPI_RSD_3BITFLAG: |
acpi_rs_out_string(name, ACPI_CAST_PTR(char, |
table-> |
pointer[*target & |
0x07])); |
break; |
case ACPI_RSD_SHORTLIST: |
/* |
* Short byte list (single line output) for DMA and IRQ resources |
* Note: The list length is obtained from the previous table entry |
*/ |
if (previous_target) { |
acpi_rs_out_title(name); |
acpi_rs_dump_short_byte_list(*previous_target, |
target); |
} |
break; |
case ACPI_RSD_SHORTLISTX: |
/* |
* Short byte list (single line output) for GPIO vendor data |
* Note: The list length is obtained from the previous table entry |
*/ |
if (previous_target) { |
acpi_rs_out_title(name); |
acpi_rs_dump_short_byte_list(*previous_target, |
* |
(ACPI_CAST_INDIRECT_PTR |
(u8, target))); |
} |
break; |
case ACPI_RSD_LONGLIST: |
/* |
* Long byte list for Vendor resource data |
* Note: The list length is obtained from the previous table entry |
*/ |
if (previous_target) { |
acpi_rs_dump_byte_list(ACPI_GET16 |
(previous_target), |
target); |
} |
break; |
case ACPI_RSD_DWORDLIST: |
/* |
* Dword list for Extended Interrupt resources |
* Note: The list length is obtained from the previous table entry |
*/ |
if (previous_target) { |
acpi_rs_dump_dword_list(*previous_target, |
ACPI_CAST_PTR(u32, |
target)); |
} |
break; |
case ACPI_RSD_WORDLIST: |
/* |
* Word list for GPIO Pin Table |
* Note: The list length is obtained from the previous table entry |
*/ |
if (previous_target) { |
acpi_rs_dump_word_list(*previous_target, |
*(ACPI_CAST_INDIRECT_PTR |
(u16, target))); |
} |
break; |
case ACPI_RSD_ADDRESS: |
/* |
* Common flags for all Address resources |
*/ |
acpi_rs_dump_address_common(ACPI_CAST_PTR |
(union acpi_resource_data, |
target)); |
break; |
case ACPI_RSD_SOURCE: |
/* |
* Optional resource_source for Address resources |
*/ |
acpi_rs_dump_resource_source(ACPI_CAST_PTR |
(struct |
acpi_resource_source, |
target)); |
break; |
default: |
acpi_os_printf("**** Invalid table opcode [%X] ****\n", |
table->opcode); |
return; |
} |
table++; |
count--; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_dump_resource_source |
* |
* PARAMETERS: resource_source - Pointer to a Resource Source struct |
* |
* RETURN: None |
* |
* DESCRIPTION: Common routine for dumping the optional resource_source and the |
* corresponding resource_source_index. |
* |
******************************************************************************/ |
static void |
acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source) |
{ |
ACPI_FUNCTION_ENTRY(); |
if (resource_source->index == 0xFF) { |
return; |
} |
acpi_rs_out_integer8("Resource Source Index", resource_source->index); |
acpi_rs_out_string("Resource Source", |
resource_source->string_ptr ? |
resource_source->string_ptr : "[Not Specified]"); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_dump_address_common |
* |
* PARAMETERS: resource - Pointer to an internal resource descriptor |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump the fields that are common to all Address resource |
* descriptors |
* |
******************************************************************************/ |
static void acpi_rs_dump_address_common(union acpi_resource_data *resource) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Decode the type-specific flags */ |
switch (resource->address.resource_type) { |
case ACPI_MEMORY_RANGE: |
acpi_rs_dump_descriptor(resource, acpi_rs_dump_memory_flags); |
break; |
case ACPI_IO_RANGE: |
acpi_rs_dump_descriptor(resource, acpi_rs_dump_io_flags); |
break; |
case ACPI_BUS_NUMBER_RANGE: |
acpi_rs_out_string("Resource Type", "Bus Number Range"); |
break; |
default: |
acpi_rs_out_integer8("Resource Type", |
(u8) resource->address.resource_type); |
break; |
} |
/* Decode the general flags */ |
acpi_rs_dump_descriptor(resource, acpi_rs_dump_general_flags); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_out* |
* |
* PARAMETERS: title - Name of the resource field |
* value - Value of the resource field |
* |
* RETURN: None |
* |
* DESCRIPTION: Miscellaneous helper functions to consistently format the |
* output of the resource dump routines |
* |
******************************************************************************/ |
static void acpi_rs_out_string(char *title, char *value) |
{ |
acpi_os_printf("%27s : %s", title, value); |
if (!*value) { |
acpi_os_printf("[NULL NAMESTRING]"); |
} |
acpi_os_printf("\n"); |
} |
static void acpi_rs_out_integer8(char *title, u8 value) |
{ |
acpi_os_printf("%27s : %2.2X\n", title, value); |
} |
static void acpi_rs_out_integer16(char *title, u16 value) |
{ |
acpi_os_printf("%27s : %4.4X\n", title, value); |
} |
static void acpi_rs_out_integer32(char *title, u32 value) |
{ |
acpi_os_printf("%27s : %8.8X\n", title, value); |
} |
static void acpi_rs_out_integer64(char *title, u64 value) |
{ |
acpi_os_printf("%27s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value)); |
} |
static void acpi_rs_out_title(char *title) |
{ |
acpi_os_printf("%27s : ", title); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_dump*List |
* |
* PARAMETERS: length - Number of elements in the list |
* data - Start of the list |
* |
* RETURN: None |
* |
* DESCRIPTION: Miscellaneous functions to dump lists of raw data |
* |
******************************************************************************/ |
static void acpi_rs_dump_byte_list(u16 length, u8 * data) |
{ |
u8 i; |
for (i = 0; i < length; i++) { |
acpi_os_printf("%25s%2.2X : %2.2X\n", "Byte", i, data[i]); |
} |
} |
static void acpi_rs_dump_short_byte_list(u8 length, u8 * data) |
{ |
u8 i; |
for (i = 0; i < length; i++) { |
acpi_os_printf("%X ", data[i]); |
} |
acpi_os_printf("\n"); |
} |
static void acpi_rs_dump_dword_list(u8 length, u32 * data) |
{ |
u8 i; |
for (i = 0; i < length; i++) { |
acpi_os_printf("%25s%2.2X : %8.8X\n", "Dword", i, data[i]); |
} |
} |
static void acpi_rs_dump_word_list(u16 length, u16 *data) |
{ |
u16 i; |
for (i = 0; i < length; i++) { |
acpi_os_printf("%25s%2.2X : %4.4X\n", "Word", i, data[i]); |
} |
} |
/drivers/acpi/acpica/rsdumpinfo.c |
---|
0,0 → 1,455 |
/******************************************************************************* |
* |
* Module Name: rsdumpinfo - Tables used to display resource descriptors. |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsdumpinfo") |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER) |
#define ACPI_RSD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_resource_data,f) |
#define ACPI_PRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f) |
#define ACPI_RSD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_rsdump_info)) |
/******************************************************************************* |
* |
* Resource Descriptor info tables |
* |
* Note: The first table entry must be a Title or Literal and must contain |
* the table length (number of table entries) |
* |
******************************************************************************/ |
struct acpi_rsdump_info acpi_rs_dump_irq[7] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length), |
"Descriptor Length", NULL}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering", |
acpi_gbl_he_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity", |
acpi_gbl_ll_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(irq.sharable), "Sharing", |
acpi_gbl_shr_decode}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.interrupt_count), |
"Interrupt Count", NULL}, |
{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(irq.interrupts[0]), |
"Interrupt List", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_dma[6] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_dma), "DMA", NULL}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.type), "Speed", |
acpi_gbl_typ_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(dma.bus_master), "Mastering", |
acpi_gbl_bm_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.transfer), "Transfer Type", |
acpi_gbl_siz_decode}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(dma.channel_count), "Channel Count", |
NULL}, |
{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(dma.channels[0]), "Channel List", |
NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf), |
"Start-Dependent-Functions", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length), |
"Descriptor Length", NULL}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority), |
"Compatibility Priority", acpi_gbl_config_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness), |
"Performance/Robustness", acpi_gbl_config_decode} |
}; |
struct acpi_rsdump_info acpi_rs_dump_end_dpf[1] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_dpf), |
"End-Dependent-Functions", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_io[6] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io), "I/O", NULL}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(io.io_decode), "Address Decoding", |
acpi_gbl_io_decode}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.minimum), "Address Minimum", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.maximum), "Address Maximum", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.alignment), "Alignment", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.address_length), "Address Length", |
NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_fixed_io[3] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_io), |
"Fixed I/O", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_io.address), "Address", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_io.address_length), |
"Address Length", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_vendor[3] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_vendor), |
"Vendor Specific", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(vendor.byte_length), "Length", NULL}, |
{ACPI_RSD_LONGLIST, ACPI_RSD_OFFSET(vendor.byte_data[0]), "Vendor Data", |
NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_end_tag[1] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "EndTag", |
NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_memory24[6] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory24), |
"24-Bit Memory Range", NULL}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory24.write_protect), |
"Write Protect", acpi_gbl_rw_decode}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.minimum), "Address Minimum", |
NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.maximum), "Address Maximum", |
NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.alignment), "Alignment", |
NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.address_length), |
"Address Length", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_memory32[6] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory32), |
"32-Bit Memory Range", NULL}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory32.write_protect), |
"Write Protect", acpi_gbl_rw_decode}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.minimum), "Address Minimum", |
NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.maximum), "Address Maximum", |
NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.alignment), "Alignment", |
NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.address_length), |
"Address Length", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[4] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_memory32), |
"32-Bit Fixed Memory Range", NULL}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(fixed_memory32.write_protect), |
"Write Protect", acpi_gbl_rw_decode}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address), "Address", |
NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address_length), |
"Address Length", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_address16[8] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16), |
"16-Bit WORD Address Space", NULL}, |
{ACPI_RSD_ADDRESS, 0, NULL, NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.granularity), |
"Granularity", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.minimum), |
"Address Minimum", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.maximum), |
"Address Maximum", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.translation_offset), |
"Translation Offset", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.address_length), |
"Address Length", NULL}, |
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_address32[8] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32), |
"32-Bit DWORD Address Space", NULL}, |
{ACPI_RSD_ADDRESS, 0, NULL, NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.granularity), |
"Granularity", NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.minimum), |
"Address Minimum", NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.maximum), |
"Address Maximum", NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.translation_offset), |
"Translation Offset", NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.address_length), |
"Address Length", NULL}, |
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_address64[8] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64), |
"64-Bit QWORD Address Space", NULL}, |
{ACPI_RSD_ADDRESS, 0, NULL, NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.granularity), |
"Granularity", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.minimum), |
"Address Minimum", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.maximum), |
"Address Maximum", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.translation_offset), |
"Translation Offset", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.address_length), |
"Address Length", NULL}, |
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64), |
"64-Bit Extended Address Space", NULL}, |
{ACPI_RSD_ADDRESS, 0, NULL, NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.granularity), |
"Granularity", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.minimum), |
"Address Minimum", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.maximum), |
"Address Maximum", NULL}, |
{ACPI_RSD_UINT64, |
ACPI_RSD_OFFSET(ext_address64.address.translation_offset), |
"Translation Offset", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.address_length), |
"Address Length", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific), |
"Type-Specific Attribute", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_ext_irq[8] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_irq), |
"Extended IRQ", NULL}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.producer_consumer), |
"Type", acpi_gbl_consume_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.triggering), |
"Triggering", acpi_gbl_he_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.polarity), "Polarity", |
acpi_gbl_ll_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(extended_irq.sharable), "Sharing", |
acpi_gbl_shr_decode}, |
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(extended_irq.resource_source), NULL, |
NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(extended_irq.interrupt_count), |
"Interrupt Count", NULL}, |
{ACPI_RSD_DWORDLIST, ACPI_RSD_OFFSET(extended_irq.interrupts[0]), |
"Interrupt List", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_generic_reg), |
"Generic Register", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.space_id), "Space ID", |
NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_width), "Bit Width", |
NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_offset), "Bit Offset", |
NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.access_size), |
"Access Size", NULL}, |
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL} |
}; |
struct acpi_rsdump_info acpi_rs_dump_gpio[16] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type), |
"ConnectionType", acpi_gbl_ct_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer), |
"ProducerConsumer", acpi_gbl_consume_decode}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig", |
acpi_gbl_ppc_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharing", |
acpi_gbl_shr_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction), |
"IoRestriction", acpi_gbl_ior_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering", |
acpi_gbl_he_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity", |
acpi_gbl_ll_decode}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength", |
NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout), |
"DebounceTimeout", NULL}, |
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source), |
"ResourceSource", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length), |
"PinTableLength", NULL}, |
{ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength", |
NULL}, |
{ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData", |
NULL}, |
}; |
struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma), |
"FixedDma", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines), |
"RequestLines", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels", |
NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth", |
acpi_gbl_dts_decode}, |
}; |
#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \ |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.revision_id), "RevisionId", NULL}, \ |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type), "Type", acpi_gbl_sbt_decode}, \ |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer", acpi_gbl_consume_decode}, \ |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode), "SlaveMode", acpi_gbl_sm_decode}, \ |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId", NULL}, \ |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength", NULL}, \ |
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource", NULL}, \ |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.vendor_length), "VendorLength", NULL}, \ |
{ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data), "VendorData", NULL}, |
struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus), |
"Common Serial Bus", NULL}, |
ACPI_RS_DUMP_COMMON_SERIAL_BUS |
}; |
struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus), |
"I2C Serial Bus", NULL}, |
ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG, |
ACPI_RSD_OFFSET(i2c_serial_bus. |
access_mode), |
"AccessMode", acpi_gbl_am_decode}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed), |
"ConnectionSpeed", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address), |
"SlaveAddress", NULL}, |
}; |
struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus), |
"Spi Serial Bus", NULL}, |
ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG, |
ACPI_RSD_OFFSET(spi_serial_bus. |
wire_mode), "WireMode", |
acpi_gbl_wm_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity), |
"DevicePolarity", acpi_gbl_dp_decode}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length), |
"DataBitLength", NULL}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase), |
"ClockPhase", acpi_gbl_cph_decode}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity), |
"ClockPolarity", acpi_gbl_cpo_decode}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection), |
"DeviceSelection", NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed), |
"ConnectionSpeed", NULL}, |
}; |
struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus), |
"Uart Serial Bus", NULL}, |
ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG, |
ACPI_RSD_OFFSET(uart_serial_bus. |
flow_control), |
"FlowControl", acpi_gbl_fc_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits), |
"StopBits", acpi_gbl_sb_decode}, |
{ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits), |
"DataBits", acpi_gbl_bpb_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian", |
acpi_gbl_ed_decode}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity", |
acpi_gbl_pt_decode}, |
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled), |
"LinesEnabled", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size), |
"RxFifoSize", NULL}, |
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size), |
"TxFifoSize", NULL}, |
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate), |
"ConnectionSpeed", NULL}, |
}; |
/* |
* Tables used for common address descriptor flag fields |
*/ |
struct acpi_rsdump_info acpi_rs_dump_general_flags[5] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_general_flags), NULL, |
NULL}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.producer_consumer), |
"Consumer/Producer", acpi_gbl_consume_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.decode), "Address Decode", |
acpi_gbl_dec_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.min_address_fixed), |
"Min Relocatability", acpi_gbl_min_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.max_address_fixed), |
"Max Relocatability", acpi_gbl_max_decode} |
}; |
struct acpi_rsdump_info acpi_rs_dump_memory_flags[5] = { |
{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory_flags), |
"Resource Type", (void *)"Memory Range"}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.write_protect), |
"Write Protect", acpi_gbl_rw_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.caching), |
"Caching", acpi_gbl_mem_decode}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.range_type), |
"Range Type", acpi_gbl_mtp_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.translation), |
"Translation", acpi_gbl_ttp_decode} |
}; |
struct acpi_rsdump_info acpi_rs_dump_io_flags[4] = { |
{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io_flags), |
"Resource Type", (void *)"I/O Range"}, |
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.io.range_type), |
"Range Type", acpi_gbl_rng_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation), |
"Translation", acpi_gbl_ttp_decode}, |
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation_type), |
"Translation Type", acpi_gbl_trs_decode} |
}; |
/* |
* Table used to dump _PRT contents |
*/ |
struct acpi_rsdump_info acpi_rs_dump_prt[5] = { |
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_prt), NULL, NULL}, |
{ACPI_RSD_UINT64, ACPI_PRT_OFFSET(address), "Address", NULL}, |
{ACPI_RSD_UINT32, ACPI_PRT_OFFSET(pin), "Pin", NULL}, |
{ACPI_RSD_STRING, ACPI_PRT_OFFSET(source[0]), "Source", NULL}, |
{ACPI_RSD_UINT32, ACPI_PRT_OFFSET(source_index), "Source Index", NULL} |
}; |
#endif |
/drivers/acpi/acpica/rsinfo.c |
---|
0,0 → 1,248 |
/******************************************************************************* |
* |
* Module Name: rsinfo - Dispatch and Info tables |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsinfo") |
/* |
* Resource dispatch and information tables. Any new resource types (either |
* Large or Small) must be reflected in each of these tables, so they are here |
* in one place. |
* |
* The tables for Large descriptors are indexed by bits 6:0 of the AML |
* descriptor type byte. The tables for Small descriptors are indexed by |
* bits 6:3 of the descriptor byte. The tables for internal resource |
* descriptors are indexed by the acpi_resource_type field. |
*/ |
/* Dispatch table for resource-to-AML (Set Resource) conversion functions */ |
struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[] = { |
acpi_rs_set_irq, /* 0x00, ACPI_RESOURCE_TYPE_IRQ */ |
acpi_rs_convert_dma, /* 0x01, ACPI_RESOURCE_TYPE_DMA */ |
acpi_rs_set_start_dpf, /* 0x02, ACPI_RESOURCE_TYPE_START_DEPENDENT */ |
acpi_rs_convert_end_dpf, /* 0x03, ACPI_RESOURCE_TYPE_END_DEPENDENT */ |
acpi_rs_convert_io, /* 0x04, ACPI_RESOURCE_TYPE_IO */ |
acpi_rs_convert_fixed_io, /* 0x05, ACPI_RESOURCE_TYPE_FIXED_IO */ |
acpi_rs_set_vendor, /* 0x06, ACPI_RESOURCE_TYPE_VENDOR */ |
acpi_rs_convert_end_tag, /* 0x07, ACPI_RESOURCE_TYPE_END_TAG */ |
acpi_rs_convert_memory24, /* 0x08, ACPI_RESOURCE_TYPE_MEMORY24 */ |
acpi_rs_convert_memory32, /* 0x09, ACPI_RESOURCE_TYPE_MEMORY32 */ |
acpi_rs_convert_fixed_memory32, /* 0x0A, ACPI_RESOURCE_TYPE_FIXED_MEMORY32 */ |
acpi_rs_convert_address16, /* 0x0B, ACPI_RESOURCE_TYPE_ADDRESS16 */ |
acpi_rs_convert_address32, /* 0x0C, ACPI_RESOURCE_TYPE_ADDRESS32 */ |
acpi_rs_convert_address64, /* 0x0D, ACPI_RESOURCE_TYPE_ADDRESS64 */ |
acpi_rs_convert_ext_address64, /* 0x0E, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ |
acpi_rs_convert_ext_irq, /* 0x0F, ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ |
acpi_rs_convert_generic_reg, /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ |
acpi_rs_convert_gpio, /* 0x11, ACPI_RESOURCE_TYPE_GPIO */ |
acpi_rs_convert_fixed_dma, /* 0x12, ACPI_RESOURCE_TYPE_FIXED_DMA */ |
NULL, /* 0x13, ACPI_RESOURCE_TYPE_SERIAL_BUS - Use subtype table below */ |
}; |
/* Dispatch tables for AML-to-resource (Get Resource) conversion functions */ |
struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { |
/* Small descriptors */ |
NULL, /* 0x00, Reserved */ |
NULL, /* 0x01, Reserved */ |
NULL, /* 0x02, Reserved */ |
NULL, /* 0x03, Reserved */ |
acpi_rs_get_irq, /* 0x04, ACPI_RESOURCE_NAME_IRQ */ |
acpi_rs_convert_dma, /* 0x05, ACPI_RESOURCE_NAME_DMA */ |
acpi_rs_get_start_dpf, /* 0x06, ACPI_RESOURCE_NAME_START_DEPENDENT */ |
acpi_rs_convert_end_dpf, /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */ |
acpi_rs_convert_io, /* 0x08, ACPI_RESOURCE_NAME_IO */ |
acpi_rs_convert_fixed_io, /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO */ |
acpi_rs_convert_fixed_dma, /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */ |
NULL, /* 0x0B, Reserved */ |
NULL, /* 0x0C, Reserved */ |
NULL, /* 0x0D, Reserved */ |
acpi_rs_get_vendor_small, /* 0x0E, ACPI_RESOURCE_NAME_VENDOR_SMALL */ |
acpi_rs_convert_end_tag, /* 0x0F, ACPI_RESOURCE_NAME_END_TAG */ |
/* Large descriptors */ |
NULL, /* 0x00, Reserved */ |
acpi_rs_convert_memory24, /* 0x01, ACPI_RESOURCE_NAME_MEMORY24 */ |
acpi_rs_convert_generic_reg, /* 0x02, ACPI_RESOURCE_NAME_GENERIC_REGISTER */ |
NULL, /* 0x03, Reserved */ |
acpi_rs_get_vendor_large, /* 0x04, ACPI_RESOURCE_NAME_VENDOR_LARGE */ |
acpi_rs_convert_memory32, /* 0x05, ACPI_RESOURCE_NAME_MEMORY32 */ |
acpi_rs_convert_fixed_memory32, /* 0x06, ACPI_RESOURCE_NAME_FIXED_MEMORY32 */ |
acpi_rs_convert_address32, /* 0x07, ACPI_RESOURCE_NAME_ADDRESS32 */ |
acpi_rs_convert_address16, /* 0x08, ACPI_RESOURCE_NAME_ADDRESS16 */ |
acpi_rs_convert_ext_irq, /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_IRQ */ |
acpi_rs_convert_address64, /* 0x0A, ACPI_RESOURCE_NAME_ADDRESS64 */ |
acpi_rs_convert_ext_address64, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ |
acpi_rs_convert_gpio, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */ |
NULL, /* 0x0D, Reserved */ |
NULL, /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use subtype table below */ |
}; |
/* Subtype table for serial_bus -- I2C, SPI, and UART */ |
struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = { |
NULL, |
acpi_rs_convert_i2c_serial_bus, |
acpi_rs_convert_spi_serial_bus, |
acpi_rs_convert_uart_serial_bus, |
}; |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER) |
/* Dispatch table for resource dump functions */ |
struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = { |
acpi_rs_dump_irq, /* ACPI_RESOURCE_TYPE_IRQ */ |
acpi_rs_dump_dma, /* ACPI_RESOURCE_TYPE_DMA */ |
acpi_rs_dump_start_dpf, /* ACPI_RESOURCE_TYPE_START_DEPENDENT */ |
acpi_rs_dump_end_dpf, /* ACPI_RESOURCE_TYPE_END_DEPENDENT */ |
acpi_rs_dump_io, /* ACPI_RESOURCE_TYPE_IO */ |
acpi_rs_dump_fixed_io, /* ACPI_RESOURCE_TYPE_FIXED_IO */ |
acpi_rs_dump_vendor, /* ACPI_RESOURCE_TYPE_VENDOR */ |
acpi_rs_dump_end_tag, /* ACPI_RESOURCE_TYPE_END_TAG */ |
acpi_rs_dump_memory24, /* ACPI_RESOURCE_TYPE_MEMORY24 */ |
acpi_rs_dump_memory32, /* ACPI_RESOURCE_TYPE_MEMORY32 */ |
acpi_rs_dump_fixed_memory32, /* ACPI_RESOURCE_TYPE_FIXED_MEMORY32 */ |
acpi_rs_dump_address16, /* ACPI_RESOURCE_TYPE_ADDRESS16 */ |
acpi_rs_dump_address32, /* ACPI_RESOURCE_TYPE_ADDRESS32 */ |
acpi_rs_dump_address64, /* ACPI_RESOURCE_TYPE_ADDRESS64 */ |
acpi_rs_dump_ext_address64, /* ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ |
acpi_rs_dump_ext_irq, /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ |
acpi_rs_dump_generic_reg, /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ |
acpi_rs_dump_gpio, /* ACPI_RESOURCE_TYPE_GPIO */ |
acpi_rs_dump_fixed_dma, /* ACPI_RESOURCE_TYPE_FIXED_DMA */ |
NULL, /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ |
}; |
struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = { |
NULL, |
acpi_rs_dump_i2c_serial_bus, /* AML_RESOURCE_I2C_BUS_TYPE */ |
acpi_rs_dump_spi_serial_bus, /* AML_RESOURCE_SPI_BUS_TYPE */ |
acpi_rs_dump_uart_serial_bus, /* AML_RESOURCE_UART_BUS_TYPE */ |
}; |
#endif |
/* |
* Base sizes for external AML resource descriptors, indexed by internal type. |
* Includes size of the descriptor header (1 byte for small descriptors, |
* 3 bytes for large descriptors) |
*/ |
const u8 acpi_gbl_aml_resource_sizes[] = { |
sizeof(struct aml_resource_irq), /* ACPI_RESOURCE_TYPE_IRQ (optional Byte 3 always created) */ |
sizeof(struct aml_resource_dma), /* ACPI_RESOURCE_TYPE_DMA */ |
sizeof(struct aml_resource_start_dependent), /* ACPI_RESOURCE_TYPE_START_DEPENDENT (optional Byte 1 always created) */ |
sizeof(struct aml_resource_end_dependent), /* ACPI_RESOURCE_TYPE_END_DEPENDENT */ |
sizeof(struct aml_resource_io), /* ACPI_RESOURCE_TYPE_IO */ |
sizeof(struct aml_resource_fixed_io), /* ACPI_RESOURCE_TYPE_FIXED_IO */ |
sizeof(struct aml_resource_vendor_small), /* ACPI_RESOURCE_TYPE_VENDOR */ |
sizeof(struct aml_resource_end_tag), /* ACPI_RESOURCE_TYPE_END_TAG */ |
sizeof(struct aml_resource_memory24), /* ACPI_RESOURCE_TYPE_MEMORY24 */ |
sizeof(struct aml_resource_memory32), /* ACPI_RESOURCE_TYPE_MEMORY32 */ |
sizeof(struct aml_resource_fixed_memory32), /* ACPI_RESOURCE_TYPE_FIXED_MEMORY32 */ |
sizeof(struct aml_resource_address16), /* ACPI_RESOURCE_TYPE_ADDRESS16 */ |
sizeof(struct aml_resource_address32), /* ACPI_RESOURCE_TYPE_ADDRESS32 */ |
sizeof(struct aml_resource_address64), /* ACPI_RESOURCE_TYPE_ADDRESS64 */ |
sizeof(struct aml_resource_extended_address64), /*ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ |
sizeof(struct aml_resource_extended_irq), /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ |
sizeof(struct aml_resource_generic_register), /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ |
sizeof(struct aml_resource_gpio), /* ACPI_RESOURCE_TYPE_GPIO */ |
sizeof(struct aml_resource_fixed_dma), /* ACPI_RESOURCE_TYPE_FIXED_DMA */ |
sizeof(struct aml_resource_common_serialbus), /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ |
}; |
const u8 acpi_gbl_resource_struct_sizes[] = { |
/* Small descriptors */ |
0, |
0, |
0, |
0, |
ACPI_RS_SIZE(struct acpi_resource_irq), |
ACPI_RS_SIZE(struct acpi_resource_dma), |
ACPI_RS_SIZE(struct acpi_resource_start_dependent), |
ACPI_RS_SIZE_MIN, |
ACPI_RS_SIZE(struct acpi_resource_io), |
ACPI_RS_SIZE(struct acpi_resource_fixed_io), |
ACPI_RS_SIZE(struct acpi_resource_fixed_dma), |
0, |
0, |
0, |
ACPI_RS_SIZE(struct acpi_resource_vendor), |
ACPI_RS_SIZE_MIN, |
/* Large descriptors */ |
0, |
ACPI_RS_SIZE(struct acpi_resource_memory24), |
ACPI_RS_SIZE(struct acpi_resource_generic_register), |
0, |
ACPI_RS_SIZE(struct acpi_resource_vendor), |
ACPI_RS_SIZE(struct acpi_resource_memory32), |
ACPI_RS_SIZE(struct acpi_resource_fixed_memory32), |
ACPI_RS_SIZE(struct acpi_resource_address32), |
ACPI_RS_SIZE(struct acpi_resource_address16), |
ACPI_RS_SIZE(struct acpi_resource_extended_irq), |
ACPI_RS_SIZE(struct acpi_resource_address64), |
ACPI_RS_SIZE(struct acpi_resource_extended_address64), |
ACPI_RS_SIZE(struct acpi_resource_gpio), |
ACPI_RS_SIZE(struct acpi_resource_common_serialbus) |
}; |
const u8 acpi_gbl_aml_resource_serial_bus_sizes[] = { |
0, |
sizeof(struct aml_resource_i2c_serialbus), |
sizeof(struct aml_resource_spi_serialbus), |
sizeof(struct aml_resource_uart_serialbus), |
}; |
const u8 acpi_gbl_resource_struct_serial_bus_sizes[] = { |
0, |
ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus), |
ACPI_RS_SIZE(struct acpi_resource_spi_serialbus), |
ACPI_RS_SIZE(struct acpi_resource_uart_serialbus), |
}; |
/drivers/acpi/acpica/rsio.c |
---|
0,0 → 1,290 |
/******************************************************************************* |
* |
* Module Name: rsio - IO and DMA resource descriptors |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsio") |
/******************************************************************************* |
* |
* acpi_rs_convert_io |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_io[5] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IO, |
ACPI_RS_SIZE(struct acpi_resource_io), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_io)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IO, |
sizeof(struct aml_resource_io), |
0}, |
/* Decode flag */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.io.io_decode), |
AML_OFFSET(io.flags), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Address Alignment |
* Length |
* Minimum Base Address |
* Maximum Base Address |
*/ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.io.alignment), |
AML_OFFSET(io.alignment), |
2}, |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.io.minimum), |
AML_OFFSET(io.minimum), |
2} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_fixed_io |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_fixed_io[4] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_IO, |
ACPI_RS_SIZE(struct acpi_resource_fixed_io), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_fixed_io)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_IO, |
sizeof(struct aml_resource_fixed_io), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Base Address |
* Length |
*/ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.fixed_io.address_length), |
AML_OFFSET(fixed_io.address_length), |
1}, |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.fixed_io.address), |
AML_OFFSET(fixed_io.address), |
1} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_generic_reg |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_generic_reg[4] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GENERIC_REGISTER, |
ACPI_RS_SIZE(struct acpi_resource_generic_register), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_generic_reg)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_GENERIC_REGISTER, |
sizeof(struct aml_resource_generic_register), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Address Space ID |
* Register Bit Width |
* Register Bit Offset |
* Access Size |
*/ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.generic_reg.space_id), |
AML_OFFSET(generic_reg.address_space_id), |
4}, |
/* Get the Register Address */ |
{ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.generic_reg.address), |
AML_OFFSET(generic_reg.address), |
1} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_end_dpf |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_end_dpf[2] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_END_DEPENDENT, |
ACPI_RS_SIZE_MIN, |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_end_dpf)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_END_DEPENDENT, |
sizeof(struct aml_resource_end_dependent), |
0} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_end_tag |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_end_tag[2] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_END_TAG, |
ACPI_RS_SIZE_MIN, |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_end_tag)}, |
/* |
* Note: The checksum field is set to zero, meaning that the resource |
* data is treated as if the checksum operation succeeded. |
* (ACPI Spec 1.0b Section 6.4.2.8) |
*/ |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_END_TAG, |
sizeof(struct aml_resource_end_tag), |
0} |
}; |
/******************************************************************************* |
* |
* acpi_rs_get_start_dpf |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_get_start_dpf[6] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_START_DEPENDENT, |
ACPI_RS_SIZE(struct acpi_resource_start_dependent), |
ACPI_RSC_TABLE_SIZE(acpi_rs_get_start_dpf)}, |
/* Defaults for Compatibility and Performance priorities */ |
{ACPI_RSC_SET8, ACPI_RS_OFFSET(data.start_dpf.compatibility_priority), |
ACPI_ACCEPTABLE_CONFIGURATION, |
2}, |
/* Get the descriptor length (0 or 1 for Start Dpf descriptor) */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.start_dpf.descriptor_length), |
AML_OFFSET(start_dpf.descriptor_type), |
0}, |
/* All done if there is no flag byte present in the descriptor */ |
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 1}, |
/* Flag byte is present, get the flags */ |
{ACPI_RSC_2BITFLAG, |
ACPI_RS_OFFSET(data.start_dpf.compatibility_priority), |
AML_OFFSET(start_dpf.flags), |
0}, |
{ACPI_RSC_2BITFLAG, |
ACPI_RS_OFFSET(data.start_dpf.performance_robustness), |
AML_OFFSET(start_dpf.flags), |
2} |
}; |
/******************************************************************************* |
* |
* acpi_rs_set_start_dpf |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_set_start_dpf[10] = { |
/* Start with a default descriptor of length 1 */ |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_START_DEPENDENT, |
sizeof(struct aml_resource_start_dependent), |
ACPI_RSC_TABLE_SIZE(acpi_rs_set_start_dpf)}, |
/* Set the default flag values */ |
{ACPI_RSC_2BITFLAG, |
ACPI_RS_OFFSET(data.start_dpf.compatibility_priority), |
AML_OFFSET(start_dpf.flags), |
0}, |
{ACPI_RSC_2BITFLAG, |
ACPI_RS_OFFSET(data.start_dpf.performance_robustness), |
AML_OFFSET(start_dpf.flags), |
2}, |
/* |
* All done if the output descriptor length is required to be 1 |
* (i.e., optimization to 0 bytes cannot be attempted) |
*/ |
{ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.start_dpf.descriptor_length), |
1}, |
/* Set length to 0 bytes (no flags byte) */ |
{ACPI_RSC_LENGTH, 0, 0, |
sizeof(struct aml_resource_start_dependent_noprio)}, |
/* |
* All done if the output descriptor length is required to be 0. |
* |
* TBD: Perhaps we should check for error if input flags are not |
* compatible with a 0-byte descriptor. |
*/ |
{ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.start_dpf.descriptor_length), |
0}, |
/* Reset length to 1 byte (descriptor with flags byte) */ |
{ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_start_dependent)}, |
/* |
* All done if flags byte is necessary -- if either priority value |
* is not ACPI_ACCEPTABLE_CONFIGURATION |
*/ |
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.start_dpf.compatibility_priority), |
ACPI_ACCEPTABLE_CONFIGURATION}, |
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.start_dpf.performance_robustness), |
ACPI_ACCEPTABLE_CONFIGURATION}, |
/* Flag byte is not necessary */ |
{ACPI_RSC_LENGTH, 0, 0, |
sizeof(struct aml_resource_start_dependent_noprio)} |
}; |
/drivers/acpi/acpica/rsirq.c |
---|
0,0 → 1,307 |
/******************************************************************************* |
* |
* Module Name: rsirq - IRQ resource descriptors |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsirq") |
/******************************************************************************* |
* |
* acpi_rs_get_irq |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_get_irq[9] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ, |
ACPI_RS_SIZE(struct acpi_resource_irq), |
ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)}, |
/* Get the IRQ mask (bytes 1:2) */ |
{ACPI_RSC_BITMASK16, ACPI_RS_OFFSET(data.irq.interrupts[0]), |
AML_OFFSET(irq.irq_mask), |
ACPI_RS_OFFSET(data.irq.interrupt_count)}, |
/* Set default flags (others are zero) */ |
{ACPI_RSC_SET8, ACPI_RS_OFFSET(data.irq.triggering), |
ACPI_EDGE_SENSITIVE, |
1}, |
/* Get the descriptor length (2 or 3 for IRQ descriptor) */ |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.irq.descriptor_length), |
AML_OFFSET(irq.descriptor_type), |
0}, |
/* All done if no flag byte present in descriptor */ |
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3}, |
/* Get flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering), |
AML_OFFSET(irq.flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.polarity), |
AML_OFFSET(irq.flags), |
3}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable), |
AML_OFFSET(irq.flags), |
4}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.wake_capable), |
AML_OFFSET(irq.flags), |
5} |
}; |
/******************************************************************************* |
* |
* acpi_rs_set_irq |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_set_irq[14] = { |
/* Start with a default descriptor of length 3 */ |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ, |
sizeof(struct aml_resource_irq), |
ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)}, |
/* Convert interrupt list to 16-bit IRQ bitmask */ |
{ACPI_RSC_BITMASK16, ACPI_RS_OFFSET(data.irq.interrupts[0]), |
AML_OFFSET(irq.irq_mask), |
ACPI_RS_OFFSET(data.irq.interrupt_count)}, |
/* Set flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering), |
AML_OFFSET(irq.flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.polarity), |
AML_OFFSET(irq.flags), |
3}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable), |
AML_OFFSET(irq.flags), |
4}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.wake_capable), |
AML_OFFSET(irq.flags), |
5}, |
/* |
* All done if the output descriptor length is required to be 3 |
* (i.e., optimization to 2 bytes cannot be attempted) |
*/ |
{ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.irq.descriptor_length), |
3}, |
/* Set length to 2 bytes (no flags byte) */ |
{ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)}, |
/* |
* All done if the output descriptor length is required to be 2. |
* |
* TBD: Perhaps we should check for error if input flags are not |
* compatible with a 2-byte descriptor. |
*/ |
{ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.irq.descriptor_length), |
2}, |
/* Reset length to 3 bytes (descriptor with flags byte) */ |
{ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq)}, |
/* |
* Check if the flags byte is necessary. Not needed if the flags are: |
* ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH, ACPI_EXCLUSIVE |
*/ |
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.irq.triggering), |
ACPI_EDGE_SENSITIVE}, |
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.irq.polarity), |
ACPI_ACTIVE_HIGH}, |
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, |
ACPI_RS_OFFSET(data.irq.sharable), |
ACPI_EXCLUSIVE}, |
/* We can optimize to a 2-byte irq_no_flags() descriptor */ |
{ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_ext_irq |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_ext_irq[10] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_EXTENDED_IRQ, |
ACPI_RS_SIZE(struct acpi_resource_extended_irq), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_ext_irq)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_EXTENDED_IRQ, |
sizeof(struct aml_resource_extended_irq), |
0}, |
/* |
* Flags: Producer/Consumer[0], Triggering[1], Polarity[2], |
* Sharing[3], Wake[4] |
*/ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.producer_consumer), |
AML_OFFSET(extended_irq.flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.triggering), |
AML_OFFSET(extended_irq.flags), |
1}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.polarity), |
AML_OFFSET(extended_irq.flags), |
2}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.sharable), |
AML_OFFSET(extended_irq.flags), |
3}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.wake_capable), |
AML_OFFSET(extended_irq.flags), |
4}, |
/* IRQ Table length (Byte4) */ |
{ACPI_RSC_COUNT, ACPI_RS_OFFSET(data.extended_irq.interrupt_count), |
AML_OFFSET(extended_irq.interrupt_count), |
sizeof(u32)}, |
/* Copy every IRQ in the table, each is 32 bits */ |
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.extended_irq.interrupts[0]), |
AML_OFFSET(extended_irq.interrupts[0]), |
0}, |
/* Optional resource_source (Index and String) */ |
{ACPI_RSC_SOURCEX, ACPI_RS_OFFSET(data.extended_irq.resource_source), |
ACPI_RS_OFFSET(data.extended_irq.interrupts[0]), |
sizeof(struct aml_resource_extended_irq)} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_dma |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_dma[6] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_DMA, |
ACPI_RS_SIZE(struct acpi_resource_dma), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_dma)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_DMA, |
sizeof(struct aml_resource_dma), |
0}, |
/* Flags: transfer preference, bus mastering, channel speed */ |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.dma.transfer), |
AML_OFFSET(dma.flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.dma.bus_master), |
AML_OFFSET(dma.flags), |
2}, |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.dma.type), |
AML_OFFSET(dma.flags), |
5}, |
/* DMA channel mask bits */ |
{ACPI_RSC_BITMASK, ACPI_RS_OFFSET(data.dma.channels[0]), |
AML_OFFSET(dma.dma_channel_mask), |
ACPI_RS_OFFSET(data.dma.channel_count)} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_fixed_dma |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[4] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_DMA, |
ACPI_RS_SIZE(struct acpi_resource_fixed_dma), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_fixed_dma)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_DMA, |
sizeof(struct aml_resource_fixed_dma), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* request_lines |
* Channels |
*/ |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.fixed_dma.request_lines), |
AML_OFFSET(fixed_dma.request_lines), |
2}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.fixed_dma.width), |
AML_OFFSET(fixed_dma.width), |
1}, |
}; |
/drivers/acpi/acpica/rslist.c |
---|
0,0 → 1,259 |
/******************************************************************************* |
* |
* Module Name: rslist - Linked list utilities |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rslist") |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_convert_aml_to_resources |
* |
* PARAMETERS: acpi_walk_aml_callback |
* resource_ptr - Pointer to the buffer that will |
* contain the output structures |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an AML resource to an internal representation of the |
* resource that is aligned and easier to access. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_convert_aml_to_resources(u8 * aml, |
u32 length, |
u32 offset, u8 resource_index, void **context) |
{ |
struct acpi_resource **resource_ptr = |
ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context); |
struct acpi_resource *resource; |
union aml_resource *aml_resource; |
struct acpi_rsconvert_info *conversion_table; |
acpi_status status; |
ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources); |
/* |
* Check that the input buffer and all subsequent pointers into it |
* are aligned on a native word boundary. Most important on IA64 |
*/ |
resource = *resource_ptr; |
if (ACPI_IS_MISALIGNED(resource)) { |
ACPI_WARNING((AE_INFO, |
"Misaligned resource pointer %p", resource)); |
} |
/* Get the appropriate conversion info table */ |
aml_resource = ACPI_CAST_PTR(union aml_resource, aml); |
if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { |
if (aml_resource->common_serial_bus.type > |
AML_RESOURCE_MAX_SERIALBUSTYPE) { |
conversion_table = NULL; |
} else { |
/* This is an I2C, SPI, or UART serial_bus descriptor */ |
conversion_table = |
acpi_gbl_convert_resource_serial_bus_dispatch |
[aml_resource->common_serial_bus.type]; |
} |
} else { |
conversion_table = |
acpi_gbl_get_resource_dispatch[resource_index]; |
} |
if (!conversion_table) { |
ACPI_ERROR((AE_INFO, |
"Invalid/unsupported resource descriptor: Type 0x%2.2X", |
resource_index)); |
return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); |
} |
/* Convert the AML byte stream resource to a local resource struct */ |
status = |
acpi_rs_convert_aml_to_resource(resource, aml_resource, |
conversion_table); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not convert AML resource (Type 0x%X)", |
*aml)); |
return_ACPI_STATUS(status); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
"Type %.2X, AmlLength %.2X InternalLength %.2X\n", |
acpi_ut_get_resource_type(aml), length, |
resource->length)); |
/* Point to the next structure in the output buffer */ |
*resource_ptr = ACPI_NEXT_RESOURCE(resource); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_convert_resources_to_aml |
* |
* PARAMETERS: resource - Pointer to the resource linked list |
* aml_size_needed - Calculated size of the byte stream |
* needed from calling acpi_rs_get_aml_length() |
* The size of the output_buffer is |
* guaranteed to be >= aml_size_needed |
* output_buffer - Pointer to the buffer that will |
* contain the byte stream |
* |
* RETURN: Status |
* |
* DESCRIPTION: Takes the resource linked list and parses it, creating a |
* byte stream of resources in the caller's output buffer |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, |
acpi_size aml_size_needed, u8 * output_buffer) |
{ |
u8 *aml = output_buffer; |
u8 *end_aml = output_buffer + aml_size_needed; |
struct acpi_rsconvert_info *conversion_table; |
acpi_status status; |
ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml); |
/* Walk the resource descriptor list, convert each descriptor */ |
while (aml < end_aml) { |
/* Validate the (internal) Resource Type */ |
if (resource->type > ACPI_RESOURCE_TYPE_MAX) { |
ACPI_ERROR((AE_INFO, |
"Invalid descriptor type (0x%X) in resource list", |
resource->type)); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
/* Sanity check the length. It must not be zero, or we loop forever */ |
if (!resource->length) { |
ACPI_ERROR((AE_INFO, |
"Invalid zero length descriptor in resource list\n")); |
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); |
} |
/* Perform the conversion */ |
if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { |
if (resource->data.common_serial_bus.type > |
AML_RESOURCE_MAX_SERIALBUSTYPE) { |
conversion_table = NULL; |
} else { |
/* This is an I2C, SPI, or UART serial_bus descriptor */ |
conversion_table = |
acpi_gbl_convert_resource_serial_bus_dispatch |
[resource->data.common_serial_bus.type]; |
} |
} else { |
conversion_table = |
acpi_gbl_set_resource_dispatch[resource->type]; |
} |
if (!conversion_table) { |
ACPI_ERROR((AE_INFO, |
"Invalid/unsupported resource descriptor: Type 0x%2.2X", |
resource->type)); |
return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); |
} |
status = acpi_rs_convert_resource_to_aml(resource, |
ACPI_CAST_PTR(union |
aml_resource, |
aml), |
conversion_table); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not convert resource (type 0x%X) to AML", |
resource->type)); |
return_ACPI_STATUS(status); |
} |
/* Perform final sanity check on the new AML resource descriptor */ |
status = acpi_ut_validate_resource(NULL, |
ACPI_CAST_PTR(union |
aml_resource, |
aml), NULL); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Check for end-of-list, normal exit */ |
if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { |
/* An End Tag indicates the end of the input Resource Template */ |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Extract the total length of the new descriptor and set the |
* Aml to point to the next (output) resource descriptor |
*/ |
aml += acpi_ut_get_descriptor_length(aml); |
/* Point to the next input resource descriptor */ |
resource = ACPI_NEXT_RESOURCE(resource); |
} |
/* Completed buffer, but did not find an end_tag resource descriptor */ |
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); |
} |
/drivers/acpi/acpica/rsmemory.c |
---|
0,0 → 1,234 |
/******************************************************************************* |
* |
* Module Name: rsmem24 - Memory resource descriptors |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsmemory") |
/******************************************************************************* |
* |
* acpi_rs_convert_memory24 |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_memory24[4] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_MEMORY24, |
ACPI_RS_SIZE(struct acpi_resource_memory24), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_memory24)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_MEMORY24, |
sizeof(struct aml_resource_memory24), |
0}, |
/* Read/Write bit */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.memory24.write_protect), |
AML_OFFSET(memory24.flags), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Minimum Base Address |
* Maximum Base Address |
* Address Base Alignment |
* Range Length |
*/ |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.memory24.minimum), |
AML_OFFSET(memory24.minimum), |
4} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_memory32 |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_memory32[4] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_MEMORY32, |
ACPI_RS_SIZE(struct acpi_resource_memory32), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_memory32)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_MEMORY32, |
sizeof(struct aml_resource_memory32), |
0}, |
/* Read/Write bit */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.memory32.write_protect), |
AML_OFFSET(memory32.flags), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Minimum Base Address |
* Maximum Base Address |
* Address Base Alignment |
* Range Length |
*/ |
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.memory32.minimum), |
AML_OFFSET(memory32.minimum), |
4} |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_fixed_memory32 |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_fixed_memory32[4] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_MEMORY32, |
ACPI_RS_SIZE(struct acpi_resource_fixed_memory32), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_fixed_memory32)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_MEMORY32, |
sizeof(struct aml_resource_fixed_memory32), |
0}, |
/* Read/Write bit */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.fixed_memory32.write_protect), |
AML_OFFSET(fixed_memory32.flags), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* Base Address |
* Range Length |
*/ |
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.fixed_memory32.address), |
AML_OFFSET(fixed_memory32.address), |
2} |
}; |
/******************************************************************************* |
* |
* acpi_rs_get_vendor_small |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_get_vendor_small[3] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_VENDOR, |
ACPI_RS_SIZE(struct acpi_resource_vendor), |
ACPI_RSC_TABLE_SIZE(acpi_rs_get_vendor_small)}, |
/* Length of the vendor data (byte count) */ |
{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length), |
0, |
sizeof(u8)}, |
/* Vendor data */ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.vendor.byte_data[0]), |
sizeof(struct aml_resource_small_header), |
0} |
}; |
/******************************************************************************* |
* |
* acpi_rs_get_vendor_large |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_get_vendor_large[3] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_VENDOR, |
ACPI_RS_SIZE(struct acpi_resource_vendor), |
ACPI_RSC_TABLE_SIZE(acpi_rs_get_vendor_large)}, |
/* Length of the vendor data (byte count) */ |
{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length), |
0, |
sizeof(u8)}, |
/* Vendor data */ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.vendor.byte_data[0]), |
sizeof(struct aml_resource_large_header), |
0} |
}; |
/******************************************************************************* |
* |
* acpi_rs_set_vendor |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_set_vendor[7] = { |
/* Default is a small vendor descriptor */ |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_VENDOR_SMALL, |
sizeof(struct aml_resource_small_header), |
ACPI_RSC_TABLE_SIZE(acpi_rs_set_vendor)}, |
/* Get the length and copy the data */ |
{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length), |
0, |
0}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.vendor.byte_data[0]), |
sizeof(struct aml_resource_small_header), |
0}, |
/* |
* All done if the Vendor byte length is 7 or less, meaning that it will |
* fit within a small descriptor |
*/ |
{ACPI_RSC_EXIT_LE, 0, 0, 7}, |
/* Must create a large vendor descriptor */ |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_VENDOR_LARGE, |
sizeof(struct aml_resource_large_header), |
0}, |
{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length), |
0, |
0}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.vendor.byte_data[0]), |
sizeof(struct aml_resource_large_header), |
0} |
}; |
/drivers/acpi/acpica/rsmisc.c |
---|
0,0 → 1,825 |
/******************************************************************************* |
* |
* Module Name: rsmisc - Miscellaneous resource descriptors |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsmisc") |
#define INIT_RESOURCE_TYPE(i) i->resource_offset |
#define INIT_RESOURCE_LENGTH(i) i->aml_offset |
#define INIT_TABLE_LENGTH(i) i->value |
#define COMPARE_OPCODE(i) i->resource_offset |
#define COMPARE_TARGET(i) i->aml_offset |
#define COMPARE_VALUE(i) i->value |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_convert_aml_to_resource |
* |
* PARAMETERS: resource - Pointer to the resource descriptor |
* aml - Where the AML descriptor is returned |
* info - Pointer to appropriate conversion table |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an external AML resource descriptor to the corresponding |
* internal resource descriptor |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, |
union aml_resource *aml, |
struct acpi_rsconvert_info *info) |
{ |
acpi_rs_length aml_resource_length; |
void *source; |
void *destination; |
char *target; |
u8 count; |
u8 flags_mode = FALSE; |
u16 item_count = 0; |
u16 temp16 = 0; |
ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); |
if (!info) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (((acpi_size) resource) & 0x3) { |
/* Each internal resource struct is expected to be 32-bit aligned */ |
ACPI_WARNING((AE_INFO, |
"Misaligned resource pointer (get): %p Type 0x%2.2X Length %u", |
resource, resource->type, resource->length)); |
} |
/* Extract the resource Length field (does not include header length) */ |
aml_resource_length = acpi_ut_get_resource_length(aml); |
/* |
* First table entry must be ACPI_RSC_INITxxx and must contain the |
* table length (# of table entries) |
*/ |
count = INIT_TABLE_LENGTH(info); |
while (count) { |
/* |
* Source is the external AML byte stream buffer, |
* destination is the internal resource descriptor |
*/ |
source = ACPI_ADD_PTR(void, aml, info->aml_offset); |
destination = |
ACPI_ADD_PTR(void, resource, info->resource_offset); |
switch (info->opcode) { |
case ACPI_RSC_INITGET: |
/* |
* Get the resource type and the initial (minimum) length |
*/ |
memset(resource, 0, INIT_RESOURCE_LENGTH(info)); |
resource->type = INIT_RESOURCE_TYPE(info); |
resource->length = INIT_RESOURCE_LENGTH(info); |
break; |
case ACPI_RSC_INITSET: |
break; |
case ACPI_RSC_FLAGINIT: |
flags_mode = TRUE; |
break; |
case ACPI_RSC_1BITFLAG: |
/* |
* Mask and shift the flag bit |
*/ |
ACPI_SET8(destination, |
((ACPI_GET8(source) >> info->value) & 0x01)); |
break; |
case ACPI_RSC_2BITFLAG: |
/* |
* Mask and shift the flag bits |
*/ |
ACPI_SET8(destination, |
((ACPI_GET8(source) >> info->value) & 0x03)); |
break; |
case ACPI_RSC_3BITFLAG: |
/* |
* Mask and shift the flag bits |
*/ |
ACPI_SET8(destination, |
((ACPI_GET8(source) >> info->value) & 0x07)); |
break; |
case ACPI_RSC_COUNT: |
item_count = ACPI_GET8(source); |
ACPI_SET8(destination, item_count); |
resource->length = resource->length + |
(info->value * (item_count - 1)); |
break; |
case ACPI_RSC_COUNT16: |
item_count = aml_resource_length; |
ACPI_SET16(destination, item_count); |
resource->length = resource->length + |
(info->value * (item_count - 1)); |
break; |
case ACPI_RSC_COUNT_GPIO_PIN: |
target = ACPI_ADD_PTR(void, aml, info->value); |
item_count = ACPI_GET16(target) - ACPI_GET16(source); |
resource->length = resource->length + item_count; |
item_count = item_count / 2; |
ACPI_SET16(destination, item_count); |
break; |
case ACPI_RSC_COUNT_GPIO_VEN: |
item_count = ACPI_GET8(source); |
ACPI_SET8(destination, item_count); |
resource->length = resource->length + |
(info->value * item_count); |
break; |
case ACPI_RSC_COUNT_GPIO_RES: |
/* |
* Vendor data is optional (length/offset may both be zero) |
* Examine vendor data length field first |
*/ |
target = ACPI_ADD_PTR(void, aml, (info->value + 2)); |
if (ACPI_GET16(target)) { |
/* Use vendor offset to get resource source length */ |
target = ACPI_ADD_PTR(void, aml, info->value); |
item_count = |
ACPI_GET16(target) - ACPI_GET16(source); |
} else { |
/* No vendor data to worry about */ |
item_count = aml->large_header.resource_length + |
sizeof(struct aml_resource_large_header) - |
ACPI_GET16(source); |
} |
resource->length = resource->length + item_count; |
ACPI_SET16(destination, item_count); |
break; |
case ACPI_RSC_COUNT_SERIAL_VEN: |
item_count = ACPI_GET16(source) - info->value; |
resource->length = resource->length + item_count; |
ACPI_SET16(destination, item_count); |
break; |
case ACPI_RSC_COUNT_SERIAL_RES: |
item_count = (aml_resource_length + |
sizeof(struct aml_resource_large_header)) |
- ACPI_GET16(source) - info->value; |
resource->length = resource->length + item_count; |
ACPI_SET16(destination, item_count); |
break; |
case ACPI_RSC_LENGTH: |
resource->length = resource->length + info->value; |
break; |
case ACPI_RSC_MOVE8: |
case ACPI_RSC_MOVE16: |
case ACPI_RSC_MOVE32: |
case ACPI_RSC_MOVE64: |
/* |
* Raw data move. Use the Info value field unless item_count has |
* been previously initialized via a COUNT opcode |
*/ |
if (info->value) { |
item_count = info->value; |
} |
acpi_rs_move_data(destination, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_GPIO_PIN: |
/* Generate and set the PIN data pointer */ |
target = (char *)ACPI_ADD_PTR(void, resource, |
(resource->length - |
item_count * 2)); |
*(u16 **)destination = ACPI_CAST_PTR(u16, target); |
/* Copy the PIN data */ |
source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); |
acpi_rs_move_data(target, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_GPIO_RES: |
/* Generate and set the resource_source string pointer */ |
target = (char *)ACPI_ADD_PTR(void, resource, |
(resource->length - |
item_count)); |
*(u8 **)destination = ACPI_CAST_PTR(u8, target); |
/* Copy the resource_source string */ |
source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); |
acpi_rs_move_data(target, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_SERIAL_VEN: |
/* Generate and set the Vendor Data pointer */ |
target = (char *)ACPI_ADD_PTR(void, resource, |
(resource->length - |
item_count)); |
*(u8 **)destination = ACPI_CAST_PTR(u8, target); |
/* Copy the Vendor Data */ |
source = ACPI_ADD_PTR(void, aml, info->value); |
acpi_rs_move_data(target, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_SERIAL_RES: |
/* Generate and set the resource_source string pointer */ |
target = (char *)ACPI_ADD_PTR(void, resource, |
(resource->length - |
item_count)); |
*(u8 **)destination = ACPI_CAST_PTR(u8, target); |
/* Copy the resource_source string */ |
source = |
ACPI_ADD_PTR(void, aml, |
(ACPI_GET16(source) + info->value)); |
acpi_rs_move_data(target, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_SET8: |
memset(destination, info->aml_offset, info->value); |
break; |
case ACPI_RSC_DATA8: |
target = ACPI_ADD_PTR(char, resource, info->value); |
memcpy(destination, source, ACPI_GET16(target)); |
break; |
case ACPI_RSC_ADDRESS: |
/* |
* Common handler for address descriptor flags |
*/ |
if (!acpi_rs_get_address_common(resource, aml)) { |
return_ACPI_STATUS |
(AE_AML_INVALID_RESOURCE_TYPE); |
} |
break; |
case ACPI_RSC_SOURCE: |
/* |
* Optional resource_source (Index and String) |
*/ |
resource->length += |
acpi_rs_get_resource_source(aml_resource_length, |
info->value, |
destination, aml, NULL); |
break; |
case ACPI_RSC_SOURCEX: |
/* |
* Optional resource_source (Index and String). This is the more |
* complicated case used by the Interrupt() macro |
*/ |
target = ACPI_ADD_PTR(char, resource, |
info->aml_offset + |
(item_count * 4)); |
resource->length += |
acpi_rs_get_resource_source(aml_resource_length, |
(acpi_rs_length) |
(((item_count - |
1) * sizeof(u32)) + |
info->value), |
destination, aml, |
target); |
break; |
case ACPI_RSC_BITMASK: |
/* |
* 8-bit encoded bitmask (DMA macro) |
*/ |
item_count = |
acpi_rs_decode_bitmask(ACPI_GET8(source), |
destination); |
if (item_count) { |
resource->length += (item_count - 1); |
} |
target = ACPI_ADD_PTR(char, resource, info->value); |
ACPI_SET8(target, item_count); |
break; |
case ACPI_RSC_BITMASK16: |
/* |
* 16-bit encoded bitmask (IRQ macro) |
*/ |
ACPI_MOVE_16_TO_16(&temp16, source); |
item_count = |
acpi_rs_decode_bitmask(temp16, destination); |
if (item_count) { |
resource->length += (item_count - 1); |
} |
target = ACPI_ADD_PTR(char, resource, info->value); |
ACPI_SET8(target, item_count); |
break; |
case ACPI_RSC_EXIT_NE: |
/* |
* control - Exit conversion if not equal |
*/ |
switch (info->resource_offset) { |
case ACPI_RSC_COMPARE_AML_LENGTH: |
if (aml_resource_length != info->value) { |
goto exit; |
} |
break; |
case ACPI_RSC_COMPARE_VALUE: |
if (ACPI_GET8(source) != info->value) { |
goto exit; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Invalid conversion sub-opcode")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
count--; |
info++; |
} |
exit: |
if (!flags_mode) { |
/* Round the resource struct length up to the next boundary (32 or 64) */ |
resource->length = |
(u32) ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_convert_resource_to_aml |
* |
* PARAMETERS: resource - Pointer to the resource descriptor |
* aml - Where the AML descriptor is returned |
* info - Pointer to appropriate conversion table |
* |
* RETURN: Status |
* |
* DESCRIPTION: Convert an internal resource descriptor to the corresponding |
* external AML resource descriptor. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, |
union aml_resource *aml, |
struct acpi_rsconvert_info *info) |
{ |
void *source = NULL; |
void *destination; |
char *target; |
acpi_rsdesc_size aml_length = 0; |
u8 count; |
u16 temp16 = 0; |
u16 item_count = 0; |
ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); |
if (!info) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* First table entry must be ACPI_RSC_INITxxx and must contain the |
* table length (# of table entries) |
*/ |
count = INIT_TABLE_LENGTH(info); |
while (count) { |
/* |
* Source is the internal resource descriptor, |
* destination is the external AML byte stream buffer |
*/ |
source = ACPI_ADD_PTR(void, resource, info->resource_offset); |
destination = ACPI_ADD_PTR(void, aml, info->aml_offset); |
switch (info->opcode) { |
case ACPI_RSC_INITSET: |
memset(aml, 0, INIT_RESOURCE_LENGTH(info)); |
aml_length = INIT_RESOURCE_LENGTH(info); |
acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info), |
aml_length, aml); |
break; |
case ACPI_RSC_INITGET: |
break; |
case ACPI_RSC_FLAGINIT: |
/* |
* Clear the flag byte |
*/ |
ACPI_SET8(destination, 0); |
break; |
case ACPI_RSC_1BITFLAG: |
/* |
* Mask and shift the flag bit |
*/ |
ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) |
((ACPI_GET8(source) & 0x01) << info-> |
value)); |
break; |
case ACPI_RSC_2BITFLAG: |
/* |
* Mask and shift the flag bits |
*/ |
ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) |
((ACPI_GET8(source) & 0x03) << info-> |
value)); |
break; |
case ACPI_RSC_3BITFLAG: |
/* |
* Mask and shift the flag bits |
*/ |
ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) |
((ACPI_GET8(source) & 0x07) << info-> |
value)); |
break; |
case ACPI_RSC_COUNT: |
item_count = ACPI_GET8(source); |
ACPI_SET8(destination, item_count); |
aml_length = |
(u16) (aml_length + |
(info->value * (item_count - 1))); |
break; |
case ACPI_RSC_COUNT16: |
item_count = ACPI_GET16(source); |
aml_length = (u16) (aml_length + item_count); |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_COUNT_GPIO_PIN: |
item_count = ACPI_GET16(source); |
ACPI_SET16(destination, aml_length); |
aml_length = (u16)(aml_length + item_count * 2); |
target = ACPI_ADD_PTR(void, aml, info->value); |
ACPI_SET16(target, aml_length); |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_COUNT_GPIO_VEN: |
item_count = ACPI_GET16(source); |
ACPI_SET16(destination, item_count); |
aml_length = |
(u16)(aml_length + (info->value * item_count)); |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_COUNT_GPIO_RES: |
/* Set resource source string length */ |
item_count = ACPI_GET16(source); |
ACPI_SET16(destination, aml_length); |
/* Compute offset for the Vendor Data */ |
aml_length = (u16)(aml_length + item_count); |
target = ACPI_ADD_PTR(void, aml, info->value); |
/* Set vendor offset only if there is vendor data */ |
if (resource->data.gpio.vendor_length) { |
ACPI_SET16(target, aml_length); |
} |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_COUNT_SERIAL_VEN: |
item_count = ACPI_GET16(source); |
ACPI_SET16(destination, item_count + info->value); |
aml_length = (u16)(aml_length + item_count); |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_COUNT_SERIAL_RES: |
item_count = ACPI_GET16(source); |
aml_length = (u16)(aml_length + item_count); |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_LENGTH: |
acpi_rs_set_resource_length(info->value, aml); |
break; |
case ACPI_RSC_MOVE8: |
case ACPI_RSC_MOVE16: |
case ACPI_RSC_MOVE32: |
case ACPI_RSC_MOVE64: |
if (info->value) { |
item_count = info->value; |
} |
acpi_rs_move_data(destination, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_GPIO_PIN: |
destination = (char *)ACPI_ADD_PTR(void, aml, |
ACPI_GET16 |
(destination)); |
source = *(u16 **)source; |
acpi_rs_move_data(destination, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_GPIO_RES: |
/* Used for both resource_source string and vendor_data */ |
destination = (char *)ACPI_ADD_PTR(void, aml, |
ACPI_GET16 |
(destination)); |
source = *(u8 **)source; |
acpi_rs_move_data(destination, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_SERIAL_VEN: |
destination = (char *)ACPI_ADD_PTR(void, aml, |
(aml_length - |
item_count)); |
source = *(u8 **)source; |
acpi_rs_move_data(destination, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_MOVE_SERIAL_RES: |
destination = (char *)ACPI_ADD_PTR(void, aml, |
(aml_length - |
item_count)); |
source = *(u8 **)source; |
acpi_rs_move_data(destination, source, item_count, |
info->opcode); |
break; |
case ACPI_RSC_ADDRESS: |
/* Set the Resource Type, General Flags, and Type-Specific Flags */ |
acpi_rs_set_address_common(aml, resource); |
break; |
case ACPI_RSC_SOURCEX: |
/* |
* Optional resource_source (Index and String) |
*/ |
aml_length = |
acpi_rs_set_resource_source(aml, |
(acpi_rs_length) |
aml_length, source); |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_SOURCE: |
/* |
* Optional resource_source (Index and String). This is the more |
* complicated case used by the Interrupt() macro |
*/ |
aml_length = |
acpi_rs_set_resource_source(aml, info->value, |
source); |
acpi_rs_set_resource_length(aml_length, aml); |
break; |
case ACPI_RSC_BITMASK: |
/* |
* 8-bit encoded bitmask (DMA macro) |
*/ |
ACPI_SET8(destination, |
acpi_rs_encode_bitmask(source, |
*ACPI_ADD_PTR(u8, |
resource, |
info-> |
value))); |
break; |
case ACPI_RSC_BITMASK16: |
/* |
* 16-bit encoded bitmask (IRQ macro) |
*/ |
temp16 = acpi_rs_encode_bitmask(source, |
*ACPI_ADD_PTR(u8, |
resource, |
info-> |
value)); |
ACPI_MOVE_16_TO_16(destination, &temp16); |
break; |
case ACPI_RSC_EXIT_LE: |
/* |
* control - Exit conversion if less than or equal |
*/ |
if (item_count <= info->value) { |
goto exit; |
} |
break; |
case ACPI_RSC_EXIT_NE: |
/* |
* control - Exit conversion if not equal |
*/ |
switch (COMPARE_OPCODE(info)) { |
case ACPI_RSC_COMPARE_VALUE: |
if (*ACPI_ADD_PTR(u8, resource, |
COMPARE_TARGET(info)) != |
COMPARE_VALUE(info)) { |
goto exit; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, |
"Invalid conversion sub-opcode")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
break; |
case ACPI_RSC_EXIT_EQ: |
/* |
* control - Exit conversion if equal |
*/ |
if (*ACPI_ADD_PTR(u8, resource, |
COMPARE_TARGET(info)) == |
COMPARE_VALUE(info)) { |
goto exit; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
count--; |
info++; |
} |
exit: |
return_ACPI_STATUS(AE_OK); |
} |
#if 0 |
/* Previous resource validations */ |
if (aml->ext_address64.revision_ID != AML_RESOURCE_EXTENDED_ADDRESS_REVISION) { |
return_ACPI_STATUS(AE_SUPPORT); |
} |
if (resource->data.start_dpf.performance_robustness >= 3) { |
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_VALUE); |
} |
if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) { |
/* |
* Only [active_high, edge_sensitive] or [active_low, level_sensitive] |
* polarity/trigger interrupts are allowed (ACPI spec, section |
* "IRQ Format"), so 0x00 and 0x09 are illegal. |
*/ |
ACPI_ERROR((AE_INFO, |
"Invalid interrupt polarity/trigger in resource list, 0x%X", |
aml->irq.flags)); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
resource->data.extended_irq.interrupt_count = temp8; |
if (temp8 < 1) { |
/* Must have at least one IRQ */ |
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); |
} |
if (resource->data.dma.transfer == 0x03) { |
ACPI_ERROR((AE_INFO, "Invalid DMA.Transfer preference (3)")); |
return_ACPI_STATUS(AE_BAD_DATA); |
} |
#endif |
/drivers/acpi/acpica/rsserial.c |
---|
0,0 → 1,445 |
/******************************************************************************* |
* |
* Module Name: rsserial - GPIO/serial_bus resource descriptors |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsserial") |
/******************************************************************************* |
* |
* acpi_rs_convert_gpio |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_gpio[18] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GPIO, |
ACPI_RS_SIZE(struct acpi_resource_gpio), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_gpio)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_GPIO, |
sizeof(struct aml_resource_gpio), |
0}, |
/* |
* These fields are contiguous in both the source and destination: |
* revision_id |
* connection_type |
*/ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.revision_id), |
AML_OFFSET(gpio.revision_id), |
2}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.producer_consumer), |
AML_OFFSET(gpio.flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable), |
AML_OFFSET(gpio.int_flags), |
3}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.wake_capable), |
AML_OFFSET(gpio.int_flags), |
4}, |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.io_restriction), |
AML_OFFSET(gpio.int_flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.triggering), |
AML_OFFSET(gpio.int_flags), |
0}, |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.polarity), |
AML_OFFSET(gpio.int_flags), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.pin_config), |
AML_OFFSET(gpio.pin_config), |
1}, |
/* |
* These fields are contiguous in both the source and destination: |
* drive_strength |
* debounce_timeout |
*/ |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.gpio.drive_strength), |
AML_OFFSET(gpio.drive_strength), |
2}, |
/* Pin Table */ |
{ACPI_RSC_COUNT_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table_length), |
AML_OFFSET(gpio.pin_table_offset), |
AML_OFFSET(gpio.res_source_offset)}, |
{ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table), |
AML_OFFSET(gpio.pin_table_offset), |
0}, |
/* Resource Source */ |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.resource_source.index), |
AML_OFFSET(gpio.res_source_index), |
1}, |
{ACPI_RSC_COUNT_GPIO_RES, |
ACPI_RS_OFFSET(data.gpio.resource_source.string_length), |
AML_OFFSET(gpio.res_source_offset), |
AML_OFFSET(gpio.vendor_offset)}, |
{ACPI_RSC_MOVE_GPIO_RES, |
ACPI_RS_OFFSET(data.gpio.resource_source.string_ptr), |
AML_OFFSET(gpio.res_source_offset), |
0}, |
/* Vendor Data */ |
{ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.gpio.vendor_length), |
AML_OFFSET(gpio.vendor_length), |
1}, |
{ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.gpio.vendor_data), |
AML_OFFSET(gpio.vendor_offset), |
0}, |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_i2c_serial_bus |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[16] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, |
ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_i2c_serial_bus)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, |
sizeof(struct aml_resource_i2c_serialbus), |
0}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), |
AML_OFFSET(common_serial_bus.revision_id), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), |
AML_OFFSET(common_serial_bus.type), |
1}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), |
AML_OFFSET(common_serial_bus.flags), |
0}, |
{ACPI_RSC_1BITFLAG, |
ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), |
AML_OFFSET(common_serial_bus.flags), |
1}, |
{ACPI_RSC_MOVE8, |
ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), |
AML_OFFSET(common_serial_bus.type_revision_id), |
1}, |
{ACPI_RSC_MOVE16, |
ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
1}, |
/* Vendor data */ |
{ACPI_RSC_COUNT_SERIAL_VEN, |
ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
AML_RESOURCE_I2C_MIN_DATA_LEN}, |
{ACPI_RSC_MOVE_SERIAL_VEN, |
ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), |
0, |
sizeof(struct aml_resource_i2c_serialbus)}, |
/* Resource Source */ |
{ACPI_RSC_MOVE8, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), |
AML_OFFSET(common_serial_bus.res_source_index), |
1}, |
{ACPI_RSC_COUNT_SERIAL_RES, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
sizeof(struct aml_resource_common_serialbus)}, |
{ACPI_RSC_MOVE_SERIAL_RES, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), |
AML_OFFSET(common_serial_bus.type_data_length), |
sizeof(struct aml_resource_common_serialbus)}, |
/* I2C bus type specific */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.i2c_serial_bus.access_mode), |
AML_OFFSET(i2c_serial_bus.type_specific_flags), |
0}, |
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.i2c_serial_bus.connection_speed), |
AML_OFFSET(i2c_serial_bus.connection_speed), |
1}, |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.i2c_serial_bus.slave_address), |
AML_OFFSET(i2c_serial_bus.slave_address), |
1}, |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_spi_serial_bus |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[20] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, |
ACPI_RS_SIZE(struct acpi_resource_spi_serialbus), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_spi_serial_bus)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, |
sizeof(struct aml_resource_spi_serialbus), |
0}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), |
AML_OFFSET(common_serial_bus.revision_id), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), |
AML_OFFSET(common_serial_bus.type), |
1}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), |
AML_OFFSET(common_serial_bus.flags), |
0}, |
{ACPI_RSC_1BITFLAG, |
ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), |
AML_OFFSET(common_serial_bus.flags), |
1}, |
{ACPI_RSC_MOVE8, |
ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), |
AML_OFFSET(common_serial_bus.type_revision_id), |
1}, |
{ACPI_RSC_MOVE16, |
ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
1}, |
/* Vendor data */ |
{ACPI_RSC_COUNT_SERIAL_VEN, |
ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
AML_RESOURCE_SPI_MIN_DATA_LEN}, |
{ACPI_RSC_MOVE_SERIAL_VEN, |
ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), |
0, |
sizeof(struct aml_resource_spi_serialbus)}, |
/* Resource Source */ |
{ACPI_RSC_MOVE8, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), |
AML_OFFSET(common_serial_bus.res_source_index), |
1}, |
{ACPI_RSC_COUNT_SERIAL_RES, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
sizeof(struct aml_resource_common_serialbus)}, |
{ACPI_RSC_MOVE_SERIAL_RES, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), |
AML_OFFSET(common_serial_bus.type_data_length), |
sizeof(struct aml_resource_common_serialbus)}, |
/* Spi bus type specific */ |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.wire_mode), |
AML_OFFSET(spi_serial_bus.type_specific_flags), |
0}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.device_polarity), |
AML_OFFSET(spi_serial_bus.type_specific_flags), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.data_bit_length), |
AML_OFFSET(spi_serial_bus.data_bit_length), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_phase), |
AML_OFFSET(spi_serial_bus.clock_phase), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_polarity), |
AML_OFFSET(spi_serial_bus.clock_polarity), |
1}, |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.spi_serial_bus.device_selection), |
AML_OFFSET(spi_serial_bus.device_selection), |
1}, |
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.spi_serial_bus.connection_speed), |
AML_OFFSET(spi_serial_bus.connection_speed), |
1}, |
}; |
/******************************************************************************* |
* |
* acpi_rs_convert_uart_serial_bus |
* |
******************************************************************************/ |
struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[22] = { |
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, |
ACPI_RS_SIZE(struct acpi_resource_uart_serialbus), |
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_uart_serial_bus)}, |
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, |
sizeof(struct aml_resource_uart_serialbus), |
0}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), |
AML_OFFSET(common_serial_bus.revision_id), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), |
AML_OFFSET(common_serial_bus.type), |
1}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), |
AML_OFFSET(common_serial_bus.flags), |
0}, |
{ACPI_RSC_1BITFLAG, |
ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), |
AML_OFFSET(common_serial_bus.flags), |
1}, |
{ACPI_RSC_MOVE8, |
ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), |
AML_OFFSET(common_serial_bus.type_revision_id), |
1}, |
{ACPI_RSC_MOVE16, |
ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
1}, |
/* Vendor data */ |
{ACPI_RSC_COUNT_SERIAL_VEN, |
ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
AML_RESOURCE_UART_MIN_DATA_LEN}, |
{ACPI_RSC_MOVE_SERIAL_VEN, |
ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), |
0, |
sizeof(struct aml_resource_uart_serialbus)}, |
/* Resource Source */ |
{ACPI_RSC_MOVE8, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), |
AML_OFFSET(common_serial_bus.res_source_index), |
1}, |
{ACPI_RSC_COUNT_SERIAL_RES, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), |
AML_OFFSET(common_serial_bus.type_data_length), |
sizeof(struct aml_resource_common_serialbus)}, |
{ACPI_RSC_MOVE_SERIAL_RES, |
ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), |
AML_OFFSET(common_serial_bus.type_data_length), |
sizeof(struct aml_resource_common_serialbus)}, |
/* Uart bus type specific */ |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.flow_control), |
AML_OFFSET(uart_serial_bus.type_specific_flags), |
0}, |
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.stop_bits), |
AML_OFFSET(uart_serial_bus.type_specific_flags), |
2}, |
{ACPI_RSC_3BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.data_bits), |
AML_OFFSET(uart_serial_bus.type_specific_flags), |
4}, |
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.endian), |
AML_OFFSET(uart_serial_bus.type_specific_flags), |
7}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.parity), |
AML_OFFSET(uart_serial_bus.parity), |
1}, |
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.lines_enabled), |
AML_OFFSET(uart_serial_bus.lines_enabled), |
1}, |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.rx_fifo_size), |
AML_OFFSET(uart_serial_bus.rx_fifo_size), |
1}, |
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.tx_fifo_size), |
AML_OFFSET(uart_serial_bus.tx_fifo_size), |
1}, |
{ACPI_RSC_MOVE32, |
ACPI_RS_OFFSET(data.uart_serial_bus.default_baud_rate), |
AML_OFFSET(uart_serial_bus.default_baud_rate), |
1}, |
}; |
/drivers/acpi/acpica/rsutils.c |
---|
0,0 → 1,787 |
/******************************************************************************* |
* |
* Module Name: rsutils - Utilities for the resource manager |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsutils") |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_decode_bitmask |
* |
* PARAMETERS: mask - Bitmask to decode |
* list - Where the converted list is returned |
* |
* RETURN: Count of bits set (length of list) |
* |
* DESCRIPTION: Convert a bit mask into a list of values |
* |
******************************************************************************/ |
u8 acpi_rs_decode_bitmask(u16 mask, u8 * list) |
{ |
u8 i; |
u8 bit_count; |
ACPI_FUNCTION_ENTRY(); |
/* Decode the mask bits */ |
for (i = 0, bit_count = 0; mask; i++) { |
if (mask & 0x0001) { |
list[bit_count] = i; |
bit_count++; |
} |
mask >>= 1; |
} |
return (bit_count); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_encode_bitmask |
* |
* PARAMETERS: list - List of values to encode |
* count - Length of list |
* |
* RETURN: Encoded bitmask |
* |
* DESCRIPTION: Convert a list of values to an encoded bitmask |
* |
******************************************************************************/ |
u16 acpi_rs_encode_bitmask(u8 * list, u8 count) |
{ |
u32 i; |
u16 mask; |
ACPI_FUNCTION_ENTRY(); |
/* Encode the list into a single bitmask */ |
for (i = 0, mask = 0; i < count; i++) { |
mask |= (0x1 << list[i]); |
} |
return (mask); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_move_data |
* |
* PARAMETERS: destination - Pointer to the destination descriptor |
* source - Pointer to the source descriptor |
* item_count - How many items to move |
* move_type - Byte width |
* |
* RETURN: None |
* |
* DESCRIPTION: Move multiple data items from one descriptor to another. Handles |
* alignment issues and endian issues if necessary, as configured |
* via the ACPI_MOVE_* macros. (This is why a memcpy is not used) |
* |
******************************************************************************/ |
void |
acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type) |
{ |
u32 i; |
ACPI_FUNCTION_ENTRY(); |
/* One move per item */ |
for (i = 0; i < item_count; i++) { |
switch (move_type) { |
/* |
* For the 8-bit case, we can perform the move all at once |
* since there are no alignment or endian issues |
*/ |
case ACPI_RSC_MOVE8: |
case ACPI_RSC_MOVE_GPIO_RES: |
case ACPI_RSC_MOVE_SERIAL_VEN: |
case ACPI_RSC_MOVE_SERIAL_RES: |
memcpy(destination, source, item_count); |
return; |
/* |
* 16-, 32-, and 64-bit cases must use the move macros that perform |
* endian conversion and/or accommodate hardware that cannot perform |
* misaligned memory transfers |
*/ |
case ACPI_RSC_MOVE16: |
case ACPI_RSC_MOVE_GPIO_PIN: |
ACPI_MOVE_16_TO_16(&ACPI_CAST_PTR(u16, destination)[i], |
&ACPI_CAST_PTR(u16, source)[i]); |
break; |
case ACPI_RSC_MOVE32: |
ACPI_MOVE_32_TO_32(&ACPI_CAST_PTR(u32, destination)[i], |
&ACPI_CAST_PTR(u32, source)[i]); |
break; |
case ACPI_RSC_MOVE64: |
ACPI_MOVE_64_TO_64(&ACPI_CAST_PTR(u64, destination)[i], |
&ACPI_CAST_PTR(u64, source)[i]); |
break; |
default: |
return; |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_set_resource_length |
* |
* PARAMETERS: total_length - Length of the AML descriptor, including |
* the header and length fields. |
* aml - Pointer to the raw AML descriptor |
* |
* RETURN: None |
* |
* DESCRIPTION: Set the resource_length field of an AML |
* resource descriptor, both Large and Small descriptors are |
* supported automatically. Note: Descriptor Type field must |
* be valid. |
* |
******************************************************************************/ |
void |
acpi_rs_set_resource_length(acpi_rsdesc_size total_length, |
union aml_resource *aml) |
{ |
acpi_rs_length resource_length; |
ACPI_FUNCTION_ENTRY(); |
/* Length is the total descriptor length minus the header length */ |
resource_length = (acpi_rs_length) |
(total_length - acpi_ut_get_resource_header_length(aml)); |
/* Length is stored differently for large and small descriptors */ |
if (aml->small_header.descriptor_type & ACPI_RESOURCE_NAME_LARGE) { |
/* Large descriptor -- bytes 1-2 contain the 16-bit length */ |
ACPI_MOVE_16_TO_16(&aml->large_header.resource_length, |
&resource_length); |
} else { |
/* Small descriptor -- bits 2:0 of byte 0 contain the length */ |
aml->small_header.descriptor_type = (u8) |
/* Clear any existing length, preserving descriptor type bits */ |
((aml->small_header. |
descriptor_type & ~ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK) |
| resource_length); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_set_resource_header |
* |
* PARAMETERS: descriptor_type - Byte to be inserted as the type |
* total_length - Length of the AML descriptor, including |
* the header and length fields. |
* aml - Pointer to the raw AML descriptor |
* |
* RETURN: None |
* |
* DESCRIPTION: Set the descriptor_type and resource_length fields of an AML |
* resource descriptor, both Large and Small descriptors are |
* supported automatically |
* |
******************************************************************************/ |
void |
acpi_rs_set_resource_header(u8 descriptor_type, |
acpi_rsdesc_size total_length, |
union aml_resource *aml) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Set the Resource Type */ |
aml->small_header.descriptor_type = descriptor_type; |
/* Set the Resource Length */ |
acpi_rs_set_resource_length(total_length, aml); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_strcpy |
* |
* PARAMETERS: destination - Pointer to the destination string |
* source - Pointer to the source string |
* |
* RETURN: String length, including NULL terminator |
* |
* DESCRIPTION: Local string copy that returns the string length, saving a |
* strcpy followed by a strlen. |
* |
******************************************************************************/ |
static u16 acpi_rs_strcpy(char *destination, char *source) |
{ |
u16 i; |
ACPI_FUNCTION_ENTRY(); |
for (i = 0; source[i]; i++) { |
destination[i] = source[i]; |
} |
destination[i] = 0; |
/* Return string length including the NULL terminator */ |
return ((u16) (i + 1)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_resource_source |
* |
* PARAMETERS: resource_length - Length field of the descriptor |
* minimum_length - Minimum length of the descriptor (minus |
* any optional fields) |
* resource_source - Where the resource_source is returned |
* aml - Pointer to the raw AML descriptor |
* string_ptr - (optional) where to store the actual |
* resource_source string |
* |
* RETURN: Length of the string plus NULL terminator, rounded up to native |
* word boundary |
* |
* DESCRIPTION: Copy the optional resource_source data from a raw AML descriptor |
* to an internal resource descriptor |
* |
******************************************************************************/ |
acpi_rs_length |
acpi_rs_get_resource_source(acpi_rs_length resource_length, |
acpi_rs_length minimum_length, |
struct acpi_resource_source * resource_source, |
union aml_resource * aml, char *string_ptr) |
{ |
acpi_rsdesc_size total_length; |
u8 *aml_resource_source; |
ACPI_FUNCTION_ENTRY(); |
total_length = |
resource_length + sizeof(struct aml_resource_large_header); |
aml_resource_source = ACPI_ADD_PTR(u8, aml, minimum_length); |
/* |
* resource_source is present if the length of the descriptor is longer than |
* the minimum length. |
* |
* Note: Some resource descriptors will have an additional null, so |
* we add 1 to the minimum length. |
*/ |
if (total_length > (acpi_rsdesc_size) (minimum_length + 1)) { |
/* Get the resource_source_index */ |
resource_source->index = aml_resource_source[0]; |
resource_source->string_ptr = string_ptr; |
if (!string_ptr) { |
/* |
* String destination pointer is not specified; Set the String |
* pointer to the end of the current resource_source structure. |
*/ |
resource_source->string_ptr = |
ACPI_ADD_PTR(char, resource_source, |
sizeof(struct acpi_resource_source)); |
} |
/* |
* In order for the Resource length to be a multiple of the native |
* word, calculate the length of the string (+1 for NULL terminator) |
* and expand to the next word multiple. |
* |
* Zero the entire area of the buffer. |
*/ |
total_length = |
(u32)strlen(ACPI_CAST_PTR(char, &aml_resource_source[1])) + |
1; |
total_length = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); |
memset(resource_source->string_ptr, 0, total_length); |
/* Copy the resource_source string to the destination */ |
resource_source->string_length = |
acpi_rs_strcpy(resource_source->string_ptr, |
ACPI_CAST_PTR(char, |
&aml_resource_source[1])); |
return ((acpi_rs_length) total_length); |
} |
/* resource_source is not present */ |
resource_source->index = 0; |
resource_source->string_length = 0; |
resource_source->string_ptr = NULL; |
return (0); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_set_resource_source |
* |
* PARAMETERS: aml - Pointer to the raw AML descriptor |
* minimum_length - Minimum length of the descriptor (minus |
* any optional fields) |
* resource_source - Internal resource_source |
* |
* RETURN: Total length of the AML descriptor |
* |
* DESCRIPTION: Convert an optional resource_source from internal format to a |
* raw AML resource descriptor |
* |
******************************************************************************/ |
acpi_rsdesc_size |
acpi_rs_set_resource_source(union aml_resource * aml, |
acpi_rs_length minimum_length, |
struct acpi_resource_source * resource_source) |
{ |
u8 *aml_resource_source; |
acpi_rsdesc_size descriptor_length; |
ACPI_FUNCTION_ENTRY(); |
descriptor_length = minimum_length; |
/* Non-zero string length indicates presence of a resource_source */ |
if (resource_source->string_length) { |
/* Point to the end of the AML descriptor */ |
aml_resource_source = ACPI_ADD_PTR(u8, aml, minimum_length); |
/* Copy the resource_source_index */ |
aml_resource_source[0] = (u8) resource_source->index; |
/* Copy the resource_source string */ |
strcpy(ACPI_CAST_PTR(char, &aml_resource_source[1]), |
resource_source->string_ptr); |
/* |
* Add the length of the string (+ 1 for null terminator) to the |
* final descriptor length |
*/ |
descriptor_length += |
((acpi_rsdesc_size) resource_source->string_length + 1); |
} |
/* Return the new total length of the AML descriptor */ |
return (descriptor_length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_prt_method_data |
* |
* PARAMETERS: node - Device node |
* ret_buffer - Pointer to a buffer structure for the |
* results |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the _PRT value of an object |
* contained in an object specified by the handle passed in |
* |
* If the function fails an appropriate status will be returned |
* and the contents of the callers buffer is undefined. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_prt_method_data(struct acpi_namespace_node * node, |
struct acpi_buffer * ret_buffer) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(rs_get_prt_method_data); |
/* Parameters guaranteed valid by caller */ |
/* Execute the method, no parameters */ |
status = acpi_ut_evaluate_object(node, METHOD_NAME__PRT, |
ACPI_BTYPE_PACKAGE, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Create a resource linked list from the byte stream buffer that comes |
* back from the _CRS method execution. |
*/ |
status = acpi_rs_create_pci_routing_table(obj_desc, ret_buffer); |
/* On exit, we must delete the object returned by evaluate_object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_crs_method_data |
* |
* PARAMETERS: node - Device node |
* ret_buffer - Pointer to a buffer structure for the |
* results |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the _CRS value of an object |
* contained in an object specified by the handle passed in |
* |
* If the function fails an appropriate status will be returned |
* and the contents of the callers buffer is undefined. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_crs_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(rs_get_crs_method_data); |
/* Parameters guaranteed valid by caller */ |
/* Execute the method, no parameters */ |
status = acpi_ut_evaluate_object(node, METHOD_NAME__CRS, |
ACPI_BTYPE_BUFFER, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Make the call to create a resource linked list from the |
* byte stream buffer that comes back from the _CRS method |
* execution. |
*/ |
status = acpi_rs_create_resource_list(obj_desc, ret_buffer); |
/* On exit, we must delete the object returned by evaluateObject */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_prs_method_data |
* |
* PARAMETERS: node - Device node |
* ret_buffer - Pointer to a buffer structure for the |
* results |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the _PRS value of an object |
* contained in an object specified by the handle passed in |
* |
* If the function fails an appropriate status will be returned |
* and the contents of the callers buffer is undefined. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(rs_get_prs_method_data); |
/* Parameters guaranteed valid by caller */ |
/* Execute the method, no parameters */ |
status = acpi_ut_evaluate_object(node, METHOD_NAME__PRS, |
ACPI_BTYPE_BUFFER, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Make the call to create a resource linked list from the |
* byte stream buffer that comes back from the _CRS method |
* execution. |
*/ |
status = acpi_rs_create_resource_list(obj_desc, ret_buffer); |
/* On exit, we must delete the object returned by evaluateObject */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_aei_method_data |
* |
* PARAMETERS: node - Device node |
* ret_buffer - Pointer to a buffer structure for the |
* results |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the _AEI value of an object |
* contained in an object specified by the handle passed in |
* |
* If the function fails an appropriate status will be returned |
* and the contents of the callers buffer is undefined. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_aei_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *ret_buffer) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(rs_get_aei_method_data); |
/* Parameters guaranteed valid by caller */ |
/* Execute the method, no parameters */ |
status = acpi_ut_evaluate_object(node, METHOD_NAME__AEI, |
ACPI_BTYPE_BUFFER, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Make the call to create a resource linked list from the |
* byte stream buffer that comes back from the _CRS method |
* execution. |
*/ |
status = acpi_rs_create_resource_list(obj_desc, ret_buffer); |
/* On exit, we must delete the object returned by evaluateObject */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_get_method_data |
* |
* PARAMETERS: handle - Handle to the containing object |
* path - Path to method, relative to Handle |
* ret_buffer - Pointer to a buffer structure for the |
* results |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the _CRS or _PRS value of an |
* object contained in an object specified by the handle passed in |
* |
* If the function fails an appropriate status will be returned |
* and the contents of the callers buffer is undefined. |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_get_method_data(acpi_handle handle, |
char *path, struct acpi_buffer *ret_buffer) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(rs_get_method_data); |
/* Parameters guaranteed valid by caller */ |
/* Execute the method, no parameters */ |
status = |
acpi_ut_evaluate_object(ACPI_CAST_PTR |
(struct acpi_namespace_node, handle), path, |
ACPI_BTYPE_BUFFER, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Make the call to create a resource linked list from the |
* byte stream buffer that comes back from the method |
* execution. |
*/ |
status = acpi_rs_create_resource_list(obj_desc, ret_buffer); |
/* On exit, we must delete the object returned by evaluate_object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_set_srs_method_data |
* |
* PARAMETERS: node - Device node |
* in_buffer - Pointer to a buffer structure of the |
* parameter |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to set the _SRS of an object contained |
* in an object specified by the handle passed in |
* |
* If the function fails an appropriate status will be returned |
* and the contents of the callers buffer is undefined. |
* |
* Note: Parameters guaranteed valid by caller |
* |
******************************************************************************/ |
acpi_status |
acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, |
struct acpi_buffer *in_buffer) |
{ |
struct acpi_evaluate_info *info; |
union acpi_operand_object *args[2]; |
acpi_status status; |
struct acpi_buffer buffer; |
ACPI_FUNCTION_TRACE(rs_set_srs_method_data); |
/* Allocate and initialize the evaluation information block */ |
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
info->prefix_node = node; |
info->relative_pathname = METHOD_NAME__SRS; |
info->parameters = args; |
info->flags = ACPI_IGNORE_RETURN_VALUE; |
/* |
* The in_buffer parameter will point to a linked list of |
* resource parameters. It needs to be formatted into a |
* byte stream to be sent in as an input parameter to _SRS |
* |
* Convert the linked list into a byte stream |
*/ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_rs_create_aml_resources(in_buffer, &buffer); |
if (ACPI_FAILURE(status)) { |
goto cleanup; |
} |
/* Create and initialize the method parameter object */ |
args[0] = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER); |
if (!args[0]) { |
/* |
* Must free the buffer allocated above (otherwise it is freed |
* later) |
*/ |
ACPI_FREE(buffer.pointer); |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
args[0]->buffer.length = (u32) buffer.length; |
args[0]->buffer.pointer = buffer.pointer; |
args[0]->common.flags = AOPOBJ_DATA_VALID; |
args[1] = NULL; |
/* Execute the method, no return value is expected */ |
status = acpi_ns_evaluate(info); |
/* Clean up and return the status from acpi_ns_evaluate */ |
acpi_ut_remove_reference(args[0]); |
cleanup: |
ACPI_FREE(info); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/rsxface.c |
---|
0,0 → 1,663 |
/******************************************************************************* |
* |
* Module Name: rsxface - Public interfaces to the resource manager |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_RESOURCES |
ACPI_MODULE_NAME("rsxface") |
/* Local macros for 16,32-bit to 64-bit conversion */ |
#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field) |
#define ACPI_COPY_ADDRESS(out, in) \ |
ACPI_COPY_FIELD(out, in, resource_type); \ |
ACPI_COPY_FIELD(out, in, producer_consumer); \ |
ACPI_COPY_FIELD(out, in, decode); \ |
ACPI_COPY_FIELD(out, in, min_address_fixed); \ |
ACPI_COPY_FIELD(out, in, max_address_fixed); \ |
ACPI_COPY_FIELD(out, in, info); \ |
ACPI_COPY_FIELD(out, in, address.granularity); \ |
ACPI_COPY_FIELD(out, in, address.minimum); \ |
ACPI_COPY_FIELD(out, in, address.maximum); \ |
ACPI_COPY_FIELD(out, in, address.translation_offset); \ |
ACPI_COPY_FIELD(out, in, address.address_length); \ |
ACPI_COPY_FIELD(out, in, resource_source); |
/* Local prototypes */ |
static acpi_status |
acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context); |
static acpi_status |
acpi_rs_validate_parameters(acpi_handle device_handle, |
struct acpi_buffer *buffer, |
struct acpi_namespace_node **return_node); |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_validate_parameters |
* |
* PARAMETERS: device_handle - Handle to a device |
* buffer - Pointer to a data buffer |
* return_node - Pointer to where the device node is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Common parameter validation for resource interfaces |
* |
******************************************************************************/ |
static acpi_status |
acpi_rs_validate_parameters(acpi_handle device_handle, |
struct acpi_buffer *buffer, |
struct acpi_namespace_node **return_node) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(rs_validate_parameters); |
/* |
* Must have a valid handle to an ACPI device |
*/ |
if (!device_handle) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
node = acpi_ns_validate_handle(device_handle); |
if (!node) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (node->type != ACPI_TYPE_DEVICE) { |
return_ACPI_STATUS(AE_TYPE); |
} |
/* |
* Validate the user buffer object |
* |
* if there is a non-zero buffer length we also need a valid pointer in |
* the buffer. If it's a zero buffer length, we'll be returning the |
* needed buffer size (later), so keep going. |
*/ |
status = acpi_ut_validate_buffer(buffer); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
*return_node = node; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_irq_routing_table |
* |
* PARAMETERS: device_handle - Handle to the Bus device we are querying |
* ret_buffer - Pointer to a buffer to receive the |
* current resources for the device |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the IRQ routing table for a |
* specific bus. The caller must first acquire a handle for the |
* desired bus. The routine table is placed in the buffer pointed |
* to by the ret_buffer variable parameter. |
* |
* If the function fails an appropriate status will be returned |
* and the value of ret_buffer is undefined. |
* |
* This function attempts to execute the _PRT method contained in |
* the object indicated by the passed device_handle. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_irq_routing_table(acpi_handle device_handle, |
struct acpi_buffer *ret_buffer) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(acpi_get_irq_routing_table); |
/* Validate parameters then dispatch to internal routine */ |
status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_rs_get_prt_method_data(node, ret_buffer); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_irq_routing_table) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_current_resources |
* |
* PARAMETERS: device_handle - Handle to the device object for the |
* device we are querying |
* ret_buffer - Pointer to a buffer to receive the |
* current resources for the device |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the current resources for a |
* specific device. The caller must first acquire a handle for |
* the desired device. The resource data is placed in the buffer |
* pointed to by the ret_buffer variable parameter. |
* |
* If the function fails an appropriate status will be returned |
* and the value of ret_buffer is undefined. |
* |
* This function attempts to execute the _CRS method contained in |
* the object indicated by the passed device_handle. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_current_resources(acpi_handle device_handle, |
struct acpi_buffer *ret_buffer) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(acpi_get_current_resources); |
/* Validate parameters then dispatch to internal routine */ |
status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_rs_get_crs_method_data(node, ret_buffer); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_current_resources) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_possible_resources |
* |
* PARAMETERS: device_handle - Handle to the device object for the |
* device we are querying |
* ret_buffer - Pointer to a buffer to receive the |
* resources for the device |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get a list of the possible resources |
* for a specific device. The caller must first acquire a handle |
* for the desired device. The resource data is placed in the |
* buffer pointed to by the ret_buffer variable. |
* |
* If the function fails an appropriate status will be returned |
* and the value of ret_buffer is undefined. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_possible_resources(acpi_handle device_handle, |
struct acpi_buffer *ret_buffer) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(acpi_get_possible_resources); |
/* Validate parameters then dispatch to internal routine */ |
status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_rs_get_prs_method_data(node, ret_buffer); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_possible_resources) |
/******************************************************************************* |
* |
* FUNCTION: acpi_set_current_resources |
* |
* PARAMETERS: device_handle - Handle to the device object for the |
* device we are setting resources |
* in_buffer - Pointer to a buffer containing the |
* resources to be set for the device |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to set the current resources for a |
* specific device. The caller must first acquire a handle for |
* the desired device. The resource data is passed to the routine |
* the buffer pointed to by the in_buffer variable. |
* |
******************************************************************************/ |
acpi_status |
acpi_set_current_resources(acpi_handle device_handle, |
struct acpi_buffer *in_buffer) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(acpi_set_current_resources); |
/* Validate the buffer, don't allow zero length */ |
if ((!in_buffer) || (!in_buffer->pointer) || (!in_buffer->length)) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Validate parameters then dispatch to internal routine */ |
status = acpi_rs_validate_parameters(device_handle, in_buffer, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_rs_set_srs_method_data(node, in_buffer); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_set_current_resources) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_event_resources |
* |
* PARAMETERS: device_handle - Handle to the device object for the |
* device we are getting resources |
* in_buffer - Pointer to a buffer containing the |
* resources to be set for the device |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to get the event resources for a |
* specific device. The caller must first acquire a handle for |
* the desired device. The resource data is passed to the routine |
* the buffer pointed to by the in_buffer variable. Uses the |
* _AEI method. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_event_resources(acpi_handle device_handle, |
struct acpi_buffer *ret_buffer) |
{ |
acpi_status status; |
struct acpi_namespace_node *node; |
ACPI_FUNCTION_TRACE(acpi_get_event_resources); |
/* Validate parameters then dispatch to internal routine */ |
status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_rs_get_aei_method_data(node, ret_buffer); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_event_resources) |
/****************************************************************************** |
* |
* FUNCTION: acpi_resource_to_address64 |
* |
* PARAMETERS: resource - Pointer to a resource |
* out - Pointer to the users's return buffer |
* (a struct acpi_resource_address64) |
* |
* RETURN: Status |
* |
* DESCRIPTION: If the resource is an address16, address32, or address64, |
* copy it to the address64 return buffer. This saves the |
* caller from having to duplicate code for different-sized |
* addresses. |
* |
******************************************************************************/ |
acpi_status |
acpi_resource_to_address64(struct acpi_resource *resource, |
struct acpi_resource_address64 *out) |
{ |
struct acpi_resource_address16 *address16; |
struct acpi_resource_address32 *address32; |
if (!resource || !out) { |
return (AE_BAD_PARAMETER); |
} |
/* Convert 16 or 32 address descriptor to 64 */ |
switch (resource->type) { |
case ACPI_RESOURCE_TYPE_ADDRESS16: |
address16 = |
ACPI_CAST_PTR(struct acpi_resource_address16, |
&resource->data); |
ACPI_COPY_ADDRESS(out, address16); |
break; |
case ACPI_RESOURCE_TYPE_ADDRESS32: |
address32 = |
ACPI_CAST_PTR(struct acpi_resource_address32, |
&resource->data); |
ACPI_COPY_ADDRESS(out, address32); |
break; |
case ACPI_RESOURCE_TYPE_ADDRESS64: |
/* Simple copy for 64 bit source */ |
memcpy(out, &resource->data, |
sizeof(struct acpi_resource_address64)); |
break; |
default: |
return (AE_BAD_PARAMETER); |
} |
return (AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_resource_to_address64) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_vendor_resource |
* |
* PARAMETERS: device_handle - Handle for the parent device object |
* name - Method name for the parent resource |
* (METHOD_NAME__CRS or METHOD_NAME__PRS) |
* uuid - Pointer to the UUID to be matched. |
* includes both subtype and 16-byte UUID |
* ret_buffer - Where the vendor resource is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walk a resource template for the specified device to find a |
* vendor-defined resource that matches the supplied UUID and |
* UUID subtype. Returns a struct acpi_resource of type Vendor. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_vendor_resource(acpi_handle device_handle, |
char *name, |
struct acpi_vendor_uuid * uuid, |
struct acpi_buffer * ret_buffer) |
{ |
struct acpi_vendor_walk_info info; |
acpi_status status; |
/* Other parameters are validated by acpi_walk_resources */ |
if (!uuid || !ret_buffer) { |
return (AE_BAD_PARAMETER); |
} |
info.uuid = uuid; |
info.buffer = ret_buffer; |
info.status = AE_NOT_EXIST; |
/* Walk the _CRS or _PRS resource list for this device */ |
status = |
acpi_walk_resources(device_handle, name, |
acpi_rs_match_vendor_resource, &info); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
return (info.status); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_vendor_resource) |
/******************************************************************************* |
* |
* FUNCTION: acpi_rs_match_vendor_resource |
* |
* PARAMETERS: acpi_walk_resource_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Match a vendor resource via the ACPI 3.0 UUID |
* |
******************************************************************************/ |
static acpi_status |
acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) |
{ |
struct acpi_vendor_walk_info *info = context; |
struct acpi_resource_vendor_typed *vendor; |
struct acpi_buffer *buffer; |
acpi_status status; |
/* Ignore all descriptors except Vendor */ |
if (resource->type != ACPI_RESOURCE_TYPE_VENDOR) { |
return (AE_OK); |
} |
vendor = &resource->data.vendor_typed; |
/* |
* For a valid match, these conditions must hold: |
* |
* 1) Length of descriptor data must be at least as long as a UUID struct |
* 2) The UUID subtypes must match |
* 3) The UUID data must match |
*/ |
if ((vendor->byte_length < (ACPI_UUID_LENGTH + 1)) || |
(vendor->uuid_subtype != info->uuid->subtype) || |
(memcmp(vendor->uuid, info->uuid->data, ACPI_UUID_LENGTH))) { |
return (AE_OK); |
} |
/* Validate/Allocate/Clear caller buffer */ |
buffer = info->buffer; |
status = acpi_ut_initialize_buffer(buffer, resource->length); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Found the correct resource, copy and return it */ |
memcpy(buffer->pointer, resource, resource->length); |
buffer->length = resource->length; |
/* Found the desired descriptor, terminate resource walk */ |
info->status = AE_OK; |
return (AE_CTRL_TERMINATE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_walk_resource_buffer |
* |
* PARAMETERS: buffer - Formatted buffer returned by one of the |
* various Get*Resource functions |
* user_function - Called for each resource |
* context - Passed to user_function |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walks the input resource template. The user_function is called |
* once for each resource in the list. |
* |
******************************************************************************/ |
acpi_status |
acpi_walk_resource_buffer(struct acpi_buffer * buffer, |
acpi_walk_resource_callback user_function, |
void *context) |
{ |
acpi_status status = AE_OK; |
struct acpi_resource *resource; |
struct acpi_resource *resource_end; |
ACPI_FUNCTION_TRACE(acpi_walk_resource_buffer); |
/* Parameter validation */ |
if (!buffer || !buffer->pointer || !user_function) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Buffer contains the resource list and length */ |
resource = ACPI_CAST_PTR(struct acpi_resource, buffer->pointer); |
resource_end = |
ACPI_ADD_PTR(struct acpi_resource, buffer->pointer, buffer->length); |
/* Walk the resource list until the end_tag is found (or buffer end) */ |
while (resource < resource_end) { |
/* Sanity check the resource type */ |
if (resource->type > ACPI_RESOURCE_TYPE_MAX) { |
status = AE_AML_INVALID_RESOURCE_TYPE; |
break; |
} |
/* Sanity check the length. It must not be zero, or we loop forever */ |
if (!resource->length) { |
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); |
} |
/* Invoke the user function, abort on any error returned */ |
status = user_function(resource, context); |
if (ACPI_FAILURE(status)) { |
if (status == AE_CTRL_TERMINATE) { |
/* This is an OK termination by the user function */ |
status = AE_OK; |
} |
break; |
} |
/* end_tag indicates end-of-list */ |
if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { |
break; |
} |
/* Get the next resource descriptor */ |
resource = ACPI_NEXT_RESOURCE(resource); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_walk_resource_buffer) |
/******************************************************************************* |
* |
* FUNCTION: acpi_walk_resources |
* |
* PARAMETERS: device_handle - Handle to the device object for the |
* device we are querying |
* name - Method name of the resources we want. |
* (METHOD_NAME__CRS, METHOD_NAME__PRS, or |
* METHOD_NAME__AEI) |
* user_function - Called for each resource |
* context - Passed to user_function |
* |
* RETURN: Status |
* |
* DESCRIPTION: Retrieves the current or possible resource list for the |
* specified device. The user_function is called once for |
* each resource in the list. |
* |
******************************************************************************/ |
acpi_status |
acpi_walk_resources(acpi_handle device_handle, |
char *name, |
acpi_walk_resource_callback user_function, void *context) |
{ |
acpi_status status; |
struct acpi_buffer buffer; |
ACPI_FUNCTION_TRACE(acpi_walk_resources); |
/* Parameter validation */ |
if (!device_handle || !user_function || !name || |
(!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) && |
!ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) && |
!ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Get the _CRS/_PRS/_AEI resource list */ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_rs_get_method_data(device_handle, name, &buffer); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Walk the resource list and cleanup */ |
status = acpi_walk_resource_buffer(&buffer, user_function, context); |
ACPI_FREE(buffer.pointer); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_walk_resources) |
/drivers/acpi/acpica/tbdata.c |
---|
0,0 → 1,773 |
/****************************************************************************** |
* |
* Module Name: tbdata - Table manager data structure functions |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbdata") |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_init_table_descriptor |
* |
* PARAMETERS: table_desc - Table descriptor |
* address - Physical address of the table |
* flags - Allocation flags of the table |
* table - Pointer to the table |
* |
* RETURN: None |
* |
* DESCRIPTION: Initialize a new table descriptor |
* |
******************************************************************************/ |
void |
acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, |
acpi_physical_address address, |
u8 flags, struct acpi_table_header *table) |
{ |
/* |
* Initialize the table descriptor. Set the pointer to NULL, since the |
* table is not fully mapped at this time. |
*/ |
memset(table_desc, 0, sizeof(struct acpi_table_desc)); |
table_desc->address = address; |
table_desc->length = table->length; |
table_desc->flags = flags; |
ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_acquire_table |
* |
* PARAMETERS: table_desc - Table descriptor |
* table_ptr - Where table is returned |
* table_length - Where table length is returned |
* table_flags - Where table allocation flags are returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Acquire an ACPI table. It can be used for tables not |
* maintained in the acpi_gbl_root_table_list. |
* |
******************************************************************************/ |
acpi_status |
acpi_tb_acquire_table(struct acpi_table_desc *table_desc, |
struct acpi_table_header **table_ptr, |
u32 *table_length, u8 *table_flags) |
{ |
struct acpi_table_header *table = NULL; |
switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { |
case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: |
table = |
acpi_os_map_memory(table_desc->address, table_desc->length); |
break; |
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: |
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: |
table = ACPI_CAST_PTR(struct acpi_table_header, |
ACPI_PHYSADDR_TO_PTR(table_desc-> |
address)); |
break; |
default: |
break; |
} |
/* Table is not valid yet */ |
if (!table) { |
return (AE_NO_MEMORY); |
} |
/* Fill the return values */ |
*table_ptr = table; |
*table_length = table_desc->length; |
*table_flags = table_desc->flags; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_release_table |
* |
* PARAMETERS: table - Pointer for the table |
* table_length - Length for the table |
* table_flags - Allocation flags for the table |
* |
* RETURN: None |
* |
* DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table(). |
* |
******************************************************************************/ |
void |
acpi_tb_release_table(struct acpi_table_header *table, |
u32 table_length, u8 table_flags) |
{ |
switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { |
case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: |
acpi_os_unmap_memory(table, table_length); |
break; |
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: |
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: |
default: |
break; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_acquire_temp_table |
* |
* PARAMETERS: table_desc - Table descriptor to be acquired |
* address - Address of the table |
* flags - Allocation flags of the table |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function validates the table header to obtain the length |
* of a table and fills the table descriptor to make its state as |
* "INSTALLED". Such a table descriptor is only used for verified |
* installation. |
* |
******************************************************************************/ |
acpi_status |
acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, |
acpi_physical_address address, u8 flags) |
{ |
struct acpi_table_header *table_header; |
switch (flags & ACPI_TABLE_ORIGIN_MASK) { |
case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: |
/* Get the length of the full table from the header */ |
table_header = |
acpi_os_map_memory(address, |
sizeof(struct acpi_table_header)); |
if (!table_header) { |
return (AE_NO_MEMORY); |
} |
acpi_tb_init_table_descriptor(table_desc, address, flags, |
table_header); |
acpi_os_unmap_memory(table_header, |
sizeof(struct acpi_table_header)); |
return (AE_OK); |
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: |
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: |
table_header = ACPI_CAST_PTR(struct acpi_table_header, |
ACPI_PHYSADDR_TO_PTR(address)); |
if (!table_header) { |
return (AE_NO_MEMORY); |
} |
acpi_tb_init_table_descriptor(table_desc, address, flags, |
table_header); |
return (AE_OK); |
default: |
break; |
} |
/* Table is not valid yet */ |
return (AE_NO_MEMORY); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_release_temp_table |
* |
* PARAMETERS: table_desc - Table descriptor to be released |
* |
* RETURN: Status |
* |
* DESCRIPTION: The inverse of acpi_tb_acquire_temp_table(). |
* |
*****************************************************************************/ |
void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc) |
{ |
/* |
* Note that the .Address is maintained by the callers of |
* acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table() |
* where .Address will be freed. |
*/ |
acpi_tb_invalidate_table(table_desc); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_tb_validate_table |
* |
* PARAMETERS: table_desc - Table descriptor |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to validate the table, the returned |
* table descriptor is in "VALIDATED" state. |
* |
*****************************************************************************/ |
acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(tb_validate_table); |
/* Validate the table if necessary */ |
if (!table_desc->pointer) { |
status = acpi_tb_acquire_table(table_desc, &table_desc->pointer, |
&table_desc->length, |
&table_desc->flags); |
if (!table_desc->pointer) { |
status = AE_NO_MEMORY; |
} |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_invalidate_table |
* |
* PARAMETERS: table_desc - Table descriptor |
* |
* RETURN: None |
* |
* DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of |
* acpi_tb_validate_table(). |
* |
******************************************************************************/ |
void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) |
{ |
ACPI_FUNCTION_TRACE(tb_invalidate_table); |
/* Table must be validated */ |
if (!table_desc->pointer) { |
return_VOID; |
} |
acpi_tb_release_table(table_desc->pointer, table_desc->length, |
table_desc->flags); |
table_desc->pointer = NULL; |
return_VOID; |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_tb_validate_temp_table |
* |
* PARAMETERS: table_desc - Table descriptor |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to validate the table, the returned |
* table descriptor is in "VALIDATED" state. |
* |
*****************************************************************************/ |
acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc) |
{ |
if (!table_desc->pointer && !acpi_gbl_verify_table_checksum) { |
/* |
* Only validates the header of the table. |
* Note that Length contains the size of the mapping after invoking |
* this work around, this value is required by |
* acpi_tb_release_temp_table(). |
* We can do this because in acpi_init_table_descriptor(), the Length |
* field of the installed descriptor is filled with the actual |
* table length obtaining from the table header. |
*/ |
table_desc->length = sizeof(struct acpi_table_header); |
} |
return (acpi_tb_validate_table(table_desc)); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_tb_verify_temp_table |
* |
* PARAMETERS: table_desc - Table descriptor |
* signature - Table signature to verify |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to validate and verify the table, the |
* returned table descriptor is in "VALIDATED" state. |
* |
*****************************************************************************/ |
acpi_status |
acpi_tb_verify_temp_table(struct acpi_table_desc * table_desc, char *signature) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(tb_verify_temp_table); |
/* Validate the table */ |
status = acpi_tb_validate_temp_table(table_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* If a particular signature is expected (DSDT/FACS), it must match */ |
if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) { |
ACPI_BIOS_ERROR((AE_INFO, |
"Invalid signature 0x%X for ACPI table, expected [%s]", |
table_desc->signature.integer, signature)); |
status = AE_BAD_SIGNATURE; |
goto invalidate_and_exit; |
} |
/* Verify the checksum */ |
if (acpi_gbl_verify_table_checksum) { |
status = |
acpi_tb_verify_checksum(table_desc->pointer, |
table_desc->length); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, |
"%4.4s 0x%8.8X%8.8X" |
" Attempted table install failed", |
acpi_ut_valid_acpi_name(table_desc-> |
signature. |
ascii) ? |
table_desc->signature.ascii : "????", |
ACPI_FORMAT_UINT64(table_desc-> |
address))); |
goto invalidate_and_exit; |
} |
} |
return_ACPI_STATUS(AE_OK); |
invalidate_and_exit: |
acpi_tb_invalidate_table(table_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_resize_root_table_list |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Expand the size of global table array |
* |
******************************************************************************/ |
acpi_status acpi_tb_resize_root_table_list(void) |
{ |
struct acpi_table_desc *tables; |
u32 table_count; |
ACPI_FUNCTION_TRACE(tb_resize_root_table_list); |
/* allow_resize flag is a parameter to acpi_initialize_tables */ |
if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { |
ACPI_ERROR((AE_INFO, |
"Resize of Root Table Array is not allowed")); |
return_ACPI_STATUS(AE_SUPPORT); |
} |
/* Increase the Table Array size */ |
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { |
table_count = acpi_gbl_root_table_list.max_table_count; |
} else { |
table_count = acpi_gbl_root_table_list.current_table_count; |
} |
tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count + |
ACPI_ROOT_TABLE_SIZE_INCREMENT) * |
sizeof(struct acpi_table_desc)); |
if (!tables) { |
ACPI_ERROR((AE_INFO, |
"Could not allocate new root table array")); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Copy and free the previous table array */ |
if (acpi_gbl_root_table_list.tables) { |
memcpy(tables, acpi_gbl_root_table_list.tables, |
(acpi_size) table_count * |
sizeof(struct acpi_table_desc)); |
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { |
ACPI_FREE(acpi_gbl_root_table_list.tables); |
} |
} |
acpi_gbl_root_table_list.tables = tables; |
acpi_gbl_root_table_list.max_table_count = |
table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; |
acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_get_next_table_descriptor |
* |
* PARAMETERS: table_index - Where table index is returned |
* table_desc - Where table descriptor is returned |
* |
* RETURN: Status and table index/descriptor. |
* |
* DESCRIPTION: Allocate a new ACPI table entry to the global table list |
* |
******************************************************************************/ |
acpi_status |
acpi_tb_get_next_table_descriptor(u32 *table_index, |
struct acpi_table_desc **table_desc) |
{ |
acpi_status status; |
u32 i; |
/* Ensure that there is room for the table in the Root Table List */ |
if (acpi_gbl_root_table_list.current_table_count >= |
acpi_gbl_root_table_list.max_table_count) { |
status = acpi_tb_resize_root_table_list(); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
i = acpi_gbl_root_table_list.current_table_count; |
acpi_gbl_root_table_list.current_table_count++; |
if (table_index) { |
*table_index = i; |
} |
if (table_desc) { |
*table_desc = &acpi_gbl_root_table_list.tables[i]; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_terminate |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete all internal ACPI tables |
* |
******************************************************************************/ |
void acpi_tb_terminate(void) |
{ |
u32 i; |
ACPI_FUNCTION_TRACE(tb_terminate); |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
/* Delete the individual tables */ |
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { |
acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]); |
} |
/* |
* Delete the root table array if allocated locally. Array cannot be |
* mapped, so we don't need to check for that flag. |
*/ |
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { |
ACPI_FREE(acpi_gbl_root_table_list.tables); |
} |
acpi_gbl_root_table_list.tables = NULL; |
acpi_gbl_root_table_list.flags = 0; |
acpi_gbl_root_table_list.current_table_count = 0; |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_delete_namespace_by_owner |
* |
* PARAMETERS: table_index - Table index |
* |
* RETURN: Status |
* |
* DESCRIPTION: Delete all namespace objects created when this table was loaded. |
* |
******************************************************************************/ |
acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) |
{ |
acpi_owner_id owner_id; |
acpi_status status; |
ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); |
status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (table_index >= acpi_gbl_root_table_list.current_table_count) { |
/* The table index does not exist */ |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(AE_NOT_EXIST); |
} |
/* Get the owner ID for this table, used to delete namespace nodes */ |
owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
/* |
* Need to acquire the namespace writer lock to prevent interference |
* with any concurrent namespace walks. The interpreter must be |
* released during the deletion since the acquisition of the deletion |
* lock may block, and also since the execution of a namespace walk |
* must be allowed to use the interpreter. |
*/ |
(void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); |
status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); |
acpi_ns_delete_namespace_by_owner(owner_id); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); |
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_allocate_owner_id |
* |
* PARAMETERS: table_index - Table index |
* |
* RETURN: Status |
* |
* DESCRIPTION: Allocates owner_id in table_desc |
* |
******************************************************************************/ |
acpi_status acpi_tb_allocate_owner_id(u32 table_index) |
{ |
acpi_status status = AE_BAD_PARAMETER; |
ACPI_FUNCTION_TRACE(tb_allocate_owner_id); |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
if (table_index < acpi_gbl_root_table_list.current_table_count) { |
status = |
acpi_ut_allocate_owner_id(& |
(acpi_gbl_root_table_list. |
tables[table_index].owner_id)); |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_release_owner_id |
* |
* PARAMETERS: table_index - Table index |
* |
* RETURN: Status |
* |
* DESCRIPTION: Releases owner_id in table_desc |
* |
******************************************************************************/ |
acpi_status acpi_tb_release_owner_id(u32 table_index) |
{ |
acpi_status status = AE_BAD_PARAMETER; |
ACPI_FUNCTION_TRACE(tb_release_owner_id); |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
if (table_index < acpi_gbl_root_table_list.current_table_count) { |
acpi_ut_release_owner_id(& |
(acpi_gbl_root_table_list. |
tables[table_index].owner_id)); |
status = AE_OK; |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_get_owner_id |
* |
* PARAMETERS: table_index - Table index |
* owner_id - Where the table owner_id is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: returns owner_id for the ACPI table |
* |
******************************************************************************/ |
acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id) |
{ |
acpi_status status = AE_BAD_PARAMETER; |
ACPI_FUNCTION_TRACE(tb_get_owner_id); |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
if (table_index < acpi_gbl_root_table_list.current_table_count) { |
*owner_id = |
acpi_gbl_root_table_list.tables[table_index].owner_id; |
status = AE_OK; |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_is_table_loaded |
* |
* PARAMETERS: table_index - Index into the root table |
* |
* RETURN: Table Loaded Flag |
* |
******************************************************************************/ |
u8 acpi_tb_is_table_loaded(u32 table_index) |
{ |
u8 is_loaded = FALSE; |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
if (table_index < acpi_gbl_root_table_list.current_table_count) { |
is_loaded = (u8) |
(acpi_gbl_root_table_list.tables[table_index].flags & |
ACPI_TABLE_IS_LOADED); |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return (is_loaded); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_set_table_loaded_flag |
* |
* PARAMETERS: table_index - Table index |
* is_loaded - TRUE if table is loaded, FALSE otherwise |
* |
* RETURN: None |
* |
* DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. |
* |
******************************************************************************/ |
void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) |
{ |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
if (table_index < acpi_gbl_root_table_list.current_table_count) { |
if (is_loaded) { |
acpi_gbl_root_table_list.tables[table_index].flags |= |
ACPI_TABLE_IS_LOADED; |
} else { |
acpi_gbl_root_table_list.tables[table_index].flags &= |
~ACPI_TABLE_IS_LOADED; |
} |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
} |
/drivers/acpi/acpica/tbfadt.c |
---|
0,0 → 1,752 |
/****************************************************************************** |
* |
* Module Name: tbfadt - FADT table utilities |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbfadt") |
/* Local prototypes */ |
static void |
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, |
u8 space_id, |
u8 byte_width, |
u64 address, char *register_name, u8 flags); |
static void acpi_tb_convert_fadt(void); |
static void acpi_tb_setup_fadt_registers(void); |
static u64 |
acpi_tb_select_address(char *register_name, u32 address32, u64 address64); |
/* Table for conversion of FADT to common internal format and FADT validation */ |
typedef struct acpi_fadt_info { |
char *name; |
u16 address64; |
u16 address32; |
u16 length; |
u8 default_length; |
u8 flags; |
} acpi_fadt_info; |
#define ACPI_FADT_OPTIONAL 0 |
#define ACPI_FADT_REQUIRED 1 |
#define ACPI_FADT_SEPARATE_LENGTH 2 |
#define ACPI_FADT_GPE_REGISTER 4 |
static struct acpi_fadt_info fadt_info_table[] = { |
{"Pm1aEventBlock", |
ACPI_FADT_OFFSET(xpm1a_event_block), |
ACPI_FADT_OFFSET(pm1a_event_block), |
ACPI_FADT_OFFSET(pm1_event_length), |
ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ |
ACPI_FADT_REQUIRED}, |
{"Pm1bEventBlock", |
ACPI_FADT_OFFSET(xpm1b_event_block), |
ACPI_FADT_OFFSET(pm1b_event_block), |
ACPI_FADT_OFFSET(pm1_event_length), |
ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ |
ACPI_FADT_OPTIONAL}, |
{"Pm1aControlBlock", |
ACPI_FADT_OFFSET(xpm1a_control_block), |
ACPI_FADT_OFFSET(pm1a_control_block), |
ACPI_FADT_OFFSET(pm1_control_length), |
ACPI_PM1_REGISTER_WIDTH, |
ACPI_FADT_REQUIRED}, |
{"Pm1bControlBlock", |
ACPI_FADT_OFFSET(xpm1b_control_block), |
ACPI_FADT_OFFSET(pm1b_control_block), |
ACPI_FADT_OFFSET(pm1_control_length), |
ACPI_PM1_REGISTER_WIDTH, |
ACPI_FADT_OPTIONAL}, |
{"Pm2ControlBlock", |
ACPI_FADT_OFFSET(xpm2_control_block), |
ACPI_FADT_OFFSET(pm2_control_block), |
ACPI_FADT_OFFSET(pm2_control_length), |
ACPI_PM2_REGISTER_WIDTH, |
ACPI_FADT_SEPARATE_LENGTH}, |
{"PmTimerBlock", |
ACPI_FADT_OFFSET(xpm_timer_block), |
ACPI_FADT_OFFSET(pm_timer_block), |
ACPI_FADT_OFFSET(pm_timer_length), |
ACPI_PM_TIMER_WIDTH, |
ACPI_FADT_SEPARATE_LENGTH}, /* ACPI 5.0A: Timer is optional */ |
{"Gpe0Block", |
ACPI_FADT_OFFSET(xgpe0_block), |
ACPI_FADT_OFFSET(gpe0_block), |
ACPI_FADT_OFFSET(gpe0_block_length), |
0, |
ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER}, |
{"Gpe1Block", |
ACPI_FADT_OFFSET(xgpe1_block), |
ACPI_FADT_OFFSET(gpe1_block), |
ACPI_FADT_OFFSET(gpe1_block_length), |
0, |
ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER} |
}; |
#define ACPI_FADT_INFO_ENTRIES \ |
(sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) |
/* Table used to split Event Blocks into separate status/enable registers */ |
typedef struct acpi_fadt_pm_info { |
struct acpi_generic_address *target; |
u16 source; |
u8 register_num; |
} acpi_fadt_pm_info; |
static struct acpi_fadt_pm_info fadt_pm_info_table[] = { |
{&acpi_gbl_xpm1a_status, |
ACPI_FADT_OFFSET(xpm1a_event_block), |
0}, |
{&acpi_gbl_xpm1a_enable, |
ACPI_FADT_OFFSET(xpm1a_event_block), |
1}, |
{&acpi_gbl_xpm1b_status, |
ACPI_FADT_OFFSET(xpm1b_event_block), |
0}, |
{&acpi_gbl_xpm1b_enable, |
ACPI_FADT_OFFSET(xpm1b_event_block), |
1} |
}; |
#define ACPI_FADT_PM_INFO_ENTRIES \ |
(sizeof (fadt_pm_info_table) / sizeof (struct acpi_fadt_pm_info)) |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_init_generic_address |
* |
* PARAMETERS: generic_address - GAS struct to be initialized |
* space_id - ACPI Space ID for this register |
* byte_width - Width of this register |
* address - Address of the register |
* register_name - ASCII name of the ACPI register |
* |
* RETURN: None |
* |
* DESCRIPTION: Initialize a Generic Address Structure (GAS) |
* See the ACPI specification for a full description and |
* definition of this structure. |
* |
******************************************************************************/ |
static void |
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, |
u8 space_id, |
u8 byte_width, |
u64 address, char *register_name, u8 flags) |
{ |
u8 bit_width; |
/* |
* Bit width field in the GAS is only one byte long, 255 max. |
* Check for bit_width overflow in GAS. |
*/ |
bit_width = (u8)(byte_width * 8); |
if (byte_width > 31) { /* (31*8)=248, (32*8)=256 */ |
/* |
* No error for GPE blocks, because we do not use the bit_width |
* for GPEs, the legacy length (byte_width) is used instead to |
* allow for a large number of GPEs. |
*/ |
if (!(flags & ACPI_FADT_GPE_REGISTER)) { |
ACPI_ERROR((AE_INFO, |
"%s - 32-bit FADT register is too long (%u bytes, %u bits) " |
"to convert to GAS struct - 255 bits max, truncating", |
register_name, byte_width, |
(byte_width * 8))); |
} |
bit_width = 255; |
} |
/* |
* The 64-bit Address field is non-aligned in the byte packed |
* GAS struct. |
*/ |
ACPI_MOVE_64_TO_64(&generic_address->address, &address); |
/* All other fields are byte-wide */ |
generic_address->space_id = space_id; |
generic_address->bit_width = bit_width; |
generic_address->bit_offset = 0; |
generic_address->access_width = 0; /* Access width ANY */ |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_select_address |
* |
* PARAMETERS: register_name - ASCII name of the ACPI register |
* address32 - 32-bit address of the register |
* address64 - 64-bit address of the register |
* |
* RETURN: The resolved 64-bit address |
* |
* DESCRIPTION: Select between 32-bit and 64-bit versions of addresses within |
* the FADT. Used for the FACS and DSDT addresses. |
* |
* NOTES: |
* |
* Check for FACS and DSDT address mismatches. An address mismatch between |
* the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and |
* DSDT/X_DSDT) could be a corrupted address field or it might indicate |
* the presence of two FACS or two DSDT tables. |
* |
* November 2013: |
* By default, as per the ACPICA specification, a valid 64-bit address is |
* used regardless of the value of the 32-bit address. However, this |
* behavior can be overridden via the acpi_gbl_use32_bit_fadt_addresses flag. |
* |
******************************************************************************/ |
static u64 |
acpi_tb_select_address(char *register_name, u32 address32, u64 address64) |
{ |
if (!address64) { |
/* 64-bit address is zero, use 32-bit address */ |
return ((u64)address32); |
} |
if (address32 && (address64 != (u64)address32)) { |
/* Address mismatch between 32-bit and 64-bit versions */ |
ACPI_BIOS_WARNING((AE_INFO, |
"32/64X %s address mismatch in FADT: " |
"0x%8.8X/0x%8.8X%8.8X, using %u-bit address", |
register_name, address32, |
ACPI_FORMAT_UINT64(address64), |
acpi_gbl_use32_bit_fadt_addresses ? 32 : |
64)); |
/* 32-bit address override */ |
if (acpi_gbl_use32_bit_fadt_addresses) { |
return ((u64)address32); |
} |
} |
/* Default is to use the 64-bit address */ |
return (address64); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_parse_fadt |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Initialize the FADT, DSDT and FACS tables |
* (FADT contains the addresses of the DSDT and FACS) |
* |
******************************************************************************/ |
void acpi_tb_parse_fadt(void) |
{ |
u32 length; |
struct acpi_table_header *table; |
/* |
* The FADT has multiple versions with different lengths, |
* and it contains pointers to both the DSDT and FACS tables. |
* |
* Get a local copy of the FADT and convert it to a common format |
* Map entire FADT, assumed to be smaller than one page. |
*/ |
length = acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index].length; |
table = |
acpi_os_map_memory(acpi_gbl_root_table_list. |
tables[acpi_gbl_fadt_index].address, length); |
if (!table) { |
return; |
} |
/* |
* Validate the FADT checksum before we copy the table. Ignore |
* checksum error as we want to try to get the DSDT and FACS. |
*/ |
(void)acpi_tb_verify_checksum(table, length); |
/* Create a local copy of the FADT in common ACPI 2.0+ format */ |
acpi_tb_create_local_fadt(table, length); |
/* All done with the real FADT, unmap it */ |
acpi_os_unmap_memory(table, length); |
/* Obtain the DSDT and FACS tables via their addresses within the FADT */ |
acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, |
ACPI_SIG_DSDT, &acpi_gbl_dsdt_index); |
/* If Hardware Reduced flag is set, there is no FACS */ |
if (!acpi_gbl_reduced_hardware) { |
if (acpi_gbl_FADT.facs) { |
acpi_tb_install_fixed_table((acpi_physical_address) |
acpi_gbl_FADT.facs, |
ACPI_SIG_FACS, |
&acpi_gbl_facs_index); |
} |
if (acpi_gbl_FADT.Xfacs) { |
acpi_tb_install_fixed_table((acpi_physical_address) |
acpi_gbl_FADT.Xfacs, |
ACPI_SIG_FACS, |
&acpi_gbl_xfacs_index); |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_create_local_fadt |
* |
* PARAMETERS: table - Pointer to BIOS FADT |
* length - Length of the table |
* |
* RETURN: None |
* |
* DESCRIPTION: Get a local copy of the FADT and convert it to a common format. |
* Performs validation on some important FADT fields. |
* |
* NOTE: We create a local copy of the FADT regardless of the version. |
* |
******************************************************************************/ |
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) |
{ |
/* |
* Check if the FADT is larger than the largest table that we expect |
* (the ACPI 5.0 version). If so, truncate the table, and issue |
* a warning. |
*/ |
if (length > sizeof(struct acpi_table_fadt)) { |
ACPI_BIOS_WARNING((AE_INFO, |
"FADT (revision %u) is longer than ACPI 5.0 version, " |
"truncating length %u to %u", |
table->revision, length, |
(u32)sizeof(struct acpi_table_fadt))); |
} |
/* Clear the entire local FADT */ |
memset(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); |
/* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */ |
memcpy(&acpi_gbl_FADT, table, |
ACPI_MIN(length, sizeof(struct acpi_table_fadt))); |
/* Take a copy of the Hardware Reduced flag */ |
acpi_gbl_reduced_hardware = FALSE; |
if (acpi_gbl_FADT.flags & ACPI_FADT_HW_REDUCED) { |
acpi_gbl_reduced_hardware = TRUE; |
} |
/* Convert the local copy of the FADT to the common internal format */ |
acpi_tb_convert_fadt(); |
/* Initialize the global ACPI register structures */ |
acpi_tb_setup_fadt_registers(); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_convert_fadt |
* |
* PARAMETERS: none - acpi_gbl_FADT is used. |
* |
* RETURN: None |
* |
* DESCRIPTION: Converts all versions of the FADT to a common internal format. |
* Expand 32-bit addresses to 64-bit as necessary. Also validate |
* important fields within the FADT. |
* |
* NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), and must |
* contain a copy of the actual BIOS-provided FADT. |
* |
* Notes on 64-bit register addresses: |
* |
* After this FADT conversion, later ACPICA code will only use the 64-bit "X" |
* fields of the FADT for all ACPI register addresses. |
* |
* The 64-bit X fields are optional extensions to the original 32-bit FADT |
* V1.0 fields. Even if they are present in the FADT, they are optional and |
* are unused if the BIOS sets them to zero. Therefore, we must copy/expand |
* 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is |
* originally zero. |
* |
* For ACPI 1.0 FADTs (that contain no 64-bit addresses), all 32-bit address |
* fields are expanded to the corresponding 64-bit X fields in the internal |
* common FADT. |
* |
* For ACPI 2.0+ FADTs, all valid (non-zero) 32-bit address fields are expanded |
* to the corresponding 64-bit X fields, if the 64-bit field is originally |
* zero. Adhering to the ACPI specification, we completely ignore the 32-bit |
* field if the 64-bit field is valid, regardless of whether the host OS is |
* 32-bit or 64-bit. |
* |
* Possible additional checks: |
* (acpi_gbl_FADT.pm1_event_length >= 4) |
* (acpi_gbl_FADT.pm1_control_length >= 2) |
* (acpi_gbl_FADT.pm_timer_length >= 4) |
* Gpe block lengths must be multiple of 2 |
* |
******************************************************************************/ |
static void acpi_tb_convert_fadt(void) |
{ |
char *name; |
struct acpi_generic_address *address64; |
u32 address32; |
u8 length; |
u8 flags; |
u32 i; |
/* |
* For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which |
* should be zero are indeed zero. This will workaround BIOSs that |
* inadvertently place values in these fields. |
* |
* The ACPI 1.0 reserved fields that will be zeroed are the bytes located |
* at offset 45, 55, 95, and the word located at offset 109, 110. |
* |
* Note: The FADT revision value is unreliable. Only the length can be |
* trusted. |
*/ |
if (acpi_gbl_FADT.header.length <= ACPI_FADT_V2_SIZE) { |
acpi_gbl_FADT.preferred_profile = 0; |
acpi_gbl_FADT.pstate_control = 0; |
acpi_gbl_FADT.cst_control = 0; |
acpi_gbl_FADT.boot_flags = 0; |
} |
/* |
* Now we can update the local FADT length to the length of the |
* current FADT version as defined by the ACPI specification. |
* Thus, we will have a common FADT internally. |
*/ |
acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); |
/* |
* Expand the 32-bit DSDT addresses to 64-bit as necessary. |
* Later ACPICA code will always use the X 64-bit field. |
*/ |
acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT", |
acpi_gbl_FADT.dsdt, |
acpi_gbl_FADT.Xdsdt); |
/* If Hardware Reduced flag is set, we are all done */ |
if (acpi_gbl_reduced_hardware) { |
return; |
} |
/* Examine all of the 64-bit extended address fields (X fields) */ |
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { |
/* |
* Get the 32-bit and 64-bit addresses, as well as the register |
* length and register name. |
*/ |
address32 = *ACPI_ADD_PTR(u32, |
&acpi_gbl_FADT, |
fadt_info_table[i].address32); |
address64 = ACPI_ADD_PTR(struct acpi_generic_address, |
&acpi_gbl_FADT, |
fadt_info_table[i].address64); |
length = *ACPI_ADD_PTR(u8, |
&acpi_gbl_FADT, |
fadt_info_table[i].length); |
name = fadt_info_table[i].name; |
flags = fadt_info_table[i].flags; |
/* |
* Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" |
* generic address structures as necessary. Later code will always use |
* the 64-bit address structures. |
* |
* November 2013: |
* Now always use the 64-bit address if it is valid (non-zero), in |
* accordance with the ACPI specification which states that a 64-bit |
* address supersedes the 32-bit version. This behavior can be |
* overridden by the acpi_gbl_use32_bit_fadt_addresses flag. |
* |
* During 64-bit address construction and verification, |
* these cases are handled: |
* |
* Address32 zero, Address64 [don't care] - Use Address64 |
* |
* Address32 non-zero, Address64 zero - Copy/use Address32 |
* Address32 non-zero == Address64 non-zero - Use Address64 |
* Address32 non-zero != Address64 non-zero - Warning, use Address64 |
* |
* Override: if acpi_gbl_use32_bit_fadt_addresses is TRUE, and: |
* Address32 non-zero != Address64 non-zero - Warning, copy/use Address32 |
* |
* Note: space_id is always I/O for 32-bit legacy address fields |
*/ |
if (address32) { |
if (!address64->address) { |
/* 64-bit address is zero, use 32-bit address */ |
acpi_tb_init_generic_address(address64, |
ACPI_ADR_SPACE_SYSTEM_IO, |
*ACPI_ADD_PTR(u8, |
&acpi_gbl_FADT, |
fadt_info_table |
[i]. |
length), |
(u64)address32, |
name, flags); |
} else if (address64->address != (u64)address32) { |
/* Address mismatch */ |
ACPI_BIOS_WARNING((AE_INFO, |
"32/64X address mismatch in FADT/%s: " |
"0x%8.8X/0x%8.8X%8.8X, using %u-bit address", |
name, address32, |
ACPI_FORMAT_UINT64 |
(address64->address), |
acpi_gbl_use32_bit_fadt_addresses |
? 32 : 64)); |
if (acpi_gbl_use32_bit_fadt_addresses) { |
/* 32-bit address override */ |
acpi_tb_init_generic_address(address64, |
ACPI_ADR_SPACE_SYSTEM_IO, |
*ACPI_ADD_PTR |
(u8, |
&acpi_gbl_FADT, |
fadt_info_table |
[i]. |
length), |
(u64) |
address32, |
name, |
flags); |
} |
} |
} |
/* |
* For each extended field, check for length mismatch between the |
* legacy length field and the corresponding 64-bit X length field. |
* Note: If the legacy length field is > 0xFF bits, ignore this |
* check. (GPE registers can be larger than the 64-bit GAS structure |
* can accomodate, 0xFF bits). |
*/ |
if (address64->address && |
(ACPI_MUL_8(length) <= ACPI_UINT8_MAX) && |
(address64->bit_width != ACPI_MUL_8(length))) { |
ACPI_BIOS_WARNING((AE_INFO, |
"32/64X length mismatch in FADT/%s: %u/%u", |
name, ACPI_MUL_8(length), |
address64->bit_width)); |
} |
if (fadt_info_table[i].flags & ACPI_FADT_REQUIRED) { |
/* |
* Field is required (Pm1a_event, Pm1a_control). |
* Both the address and length must be non-zero. |
*/ |
if (!address64->address || !length) { |
ACPI_BIOS_ERROR((AE_INFO, |
"Required FADT field %s has zero address and/or length: " |
"0x%8.8X%8.8X/0x%X", |
name, |
ACPI_FORMAT_UINT64(address64-> |
address), |
length)); |
} |
} else if (fadt_info_table[i].flags & ACPI_FADT_SEPARATE_LENGTH) { |
/* |
* Field is optional (Pm2_control, GPE0, GPE1) AND has its own |
* length field. If present, both the address and length must |
* be valid. |
*/ |
if ((address64->address && !length) || |
(!address64->address && length)) { |
ACPI_BIOS_WARNING((AE_INFO, |
"Optional FADT field %s has zero address or length: " |
"0x%8.8X%8.8X/0x%X", |
name, |
ACPI_FORMAT_UINT64 |
(address64->address), |
length)); |
} |
} |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_setup_fadt_registers |
* |
* PARAMETERS: None, uses acpi_gbl_FADT. |
* |
* RETURN: None |
* |
* DESCRIPTION: Initialize global ACPI PM1 register definitions. Optionally, |
* force FADT register definitions to their default lengths. |
* |
******************************************************************************/ |
static void acpi_tb_setup_fadt_registers(void) |
{ |
struct acpi_generic_address *target64; |
struct acpi_generic_address *source64; |
u8 pm1_register_byte_width; |
u32 i; |
/* |
* Optionally check all register lengths against the default values and |
* update them if they are incorrect. |
*/ |
if (acpi_gbl_use_default_register_widths) { |
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { |
target64 = |
ACPI_ADD_PTR(struct acpi_generic_address, |
&acpi_gbl_FADT, |
fadt_info_table[i].address64); |
/* |
* If a valid register (Address != 0) and the (default_length > 0) |
* (Not a GPE register), then check the width against the default. |
*/ |
if ((target64->address) && |
(fadt_info_table[i].default_length > 0) && |
(fadt_info_table[i].default_length != |
target64->bit_width)) { |
ACPI_BIOS_WARNING((AE_INFO, |
"Invalid length for FADT/%s: %u, using default %u", |
fadt_info_table[i].name, |
target64->bit_width, |
fadt_info_table[i]. |
default_length)); |
/* Incorrect size, set width to the default */ |
target64->bit_width = |
fadt_info_table[i].default_length; |
} |
} |
} |
/* |
* Get the length of the individual PM1 registers (enable and status). |
* Each register is defined to be (event block length / 2). Extra divide |
* by 8 converts bits to bytes. |
*/ |
pm1_register_byte_width = (u8) |
ACPI_DIV_16(acpi_gbl_FADT.xpm1a_event_block.bit_width); |
/* |
* Calculate separate GAS structs for the PM1x (A/B) Status and Enable |
* registers. These addresses do not appear (directly) in the FADT, so it |
* is useful to pre-calculate them from the PM1 Event Block definitions. |
* |
* The PM event blocks are split into two register blocks, first is the |
* PM Status Register block, followed immediately by the PM Enable |
* Register block. Each is of length (pm1_event_length/2) |
* |
* Note: The PM1A event block is required by the ACPI specification. |
* However, the PM1B event block is optional and is rarely, if ever, |
* used. |
*/ |
for (i = 0; i < ACPI_FADT_PM_INFO_ENTRIES; i++) { |
source64 = |
ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, |
fadt_pm_info_table[i].source); |
if (source64->address) { |
acpi_tb_init_generic_address(fadt_pm_info_table[i]. |
target, source64->space_id, |
pm1_register_byte_width, |
source64->address + |
(fadt_pm_info_table[i]. |
register_num * |
pm1_register_byte_width), |
"PmRegisters", 0); |
} |
} |
} |
/drivers/acpi/acpica/tbfind.c |
---|
0,0 → 1,152 |
/****************************************************************************** |
* |
* Module Name: tbfind - find table |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbfind") |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_find_table |
* |
* PARAMETERS: signature - String with ACPI table signature |
* oem_id - String with the table OEM ID |
* oem_table_id - String with the OEM Table ID |
* table_index - Where the table index is returned |
* |
* RETURN: Status and table index |
* |
* DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the |
* Signature, OEM ID and OEM Table ID. Returns an index that can |
* be used to get the table header or entire table. |
* |
******************************************************************************/ |
acpi_status |
acpi_tb_find_table(char *signature, |
char *oem_id, char *oem_table_id, u32 *table_index) |
{ |
acpi_status status; |
struct acpi_table_header header; |
u32 i; |
ACPI_FUNCTION_TRACE(tb_find_table); |
/* Validate the input table signature */ |
if (!acpi_is_valid_signature(signature)) { |
return_ACPI_STATUS(AE_BAD_SIGNATURE); |
} |
/* Don't allow the OEM strings to be too long */ |
if ((strlen(oem_id) > ACPI_OEM_ID_SIZE) || |
(strlen(oem_table_id) > ACPI_OEM_TABLE_ID_SIZE)) { |
return_ACPI_STATUS(AE_AML_STRING_LIMIT); |
} |
/* Normalize the input strings */ |
memset(&header, 0, sizeof(struct acpi_table_header)); |
ACPI_MOVE_NAME(header.signature, signature); |
strncpy(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); |
strncpy(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); |
/* Search for the table */ |
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { |
if (memcmp(&(acpi_gbl_root_table_list.tables[i].signature), |
header.signature, ACPI_NAME_SIZE)) { |
/* Not the requested table */ |
continue; |
} |
/* Table with matching signature has been found */ |
if (!acpi_gbl_root_table_list.tables[i].pointer) { |
/* Table is not currently mapped, map it */ |
status = |
acpi_tb_validate_table(&acpi_gbl_root_table_list. |
tables[i]); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
if (!acpi_gbl_root_table_list.tables[i].pointer) { |
continue; |
} |
} |
/* Check for table match on all IDs */ |
if (!memcmp |
(acpi_gbl_root_table_list.tables[i].pointer->signature, |
header.signature, ACPI_NAME_SIZE) && (!oem_id[0] |
|| |
!memcmp |
(acpi_gbl_root_table_list. |
tables[i].pointer-> |
oem_id, |
header.oem_id, |
ACPI_OEM_ID_SIZE)) |
&& (!oem_table_id[0] |
|| !memcmp(acpi_gbl_root_table_list.tables[i].pointer-> |
oem_table_id, header.oem_table_id, |
ACPI_OEM_TABLE_ID_SIZE))) { |
*table_index = i; |
ACPI_DEBUG_PRINT((ACPI_DB_TABLES, |
"Found table [%4.4s]\n", |
header.signature)); |
return_ACPI_STATUS(AE_OK); |
} |
} |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
/drivers/acpi/acpica/tbinstal.c |
---|
0,0 → 1,491 |
/****************************************************************************** |
* |
* Module Name: tbinstal - ACPI table installation and removal |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbinstal") |
/* Local prototypes */ |
static u8 |
acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index); |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_compare_tables |
* |
* PARAMETERS: table_desc - Table 1 descriptor to be compared |
* table_index - Index of table 2 to be compared |
* |
* RETURN: TRUE if both tables are identical. |
* |
* DESCRIPTION: This function compares a table with another table that has |
* already been installed in the root table list. |
* |
******************************************************************************/ |
static u8 |
acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) |
{ |
acpi_status status = AE_OK; |
u8 is_identical; |
struct acpi_table_header *table; |
u32 table_length; |
u8 table_flags; |
status = |
acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index], |
&table, &table_length, &table_flags); |
if (ACPI_FAILURE(status)) { |
return (FALSE); |
} |
/* |
* Check for a table match on the entire table length, |
* not just the header. |
*/ |
is_identical = (u8)((table_desc->length != table_length || |
memcmp(table_desc->pointer, table, table_length)) ? |
FALSE : TRUE); |
/* Release the acquired table */ |
acpi_tb_release_table(table, table_length, table_flags); |
return (is_identical); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_install_table_with_override |
* |
* PARAMETERS: new_table_desc - New table descriptor to install |
* override - Whether override should be performed |
* table_index - Where the table index is returned |
* |
* RETURN: None |
* |
* DESCRIPTION: Install an ACPI table into the global data structure. The |
* table override mechanism is called to allow the host |
* OS to replace any table before it is installed in the root |
* table array. |
* |
******************************************************************************/ |
void |
acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, |
u8 override, u32 *table_index) |
{ |
u32 i; |
acpi_status status; |
status = acpi_tb_get_next_table_descriptor(&i, NULL); |
if (ACPI_FAILURE(status)) { |
return; |
} |
/* |
* ACPI Table Override: |
* |
* Before we install the table, let the host OS override it with a new |
* one if desired. Any table within the RSDT/XSDT can be replaced, |
* including the DSDT which is pointed to by the FADT. |
*/ |
if (override) { |
acpi_tb_override_table(new_table_desc); |
} |
acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.tables[i], |
new_table_desc->address, |
new_table_desc->flags, |
new_table_desc->pointer); |
acpi_tb_print_table_header(new_table_desc->address, |
new_table_desc->pointer); |
/* This synchronizes acpi_gbl_dsdt_index */ |
*table_index = i; |
/* Set the global integer width (based upon revision of the DSDT) */ |
if (i == acpi_gbl_dsdt_index) { |
acpi_ut_set_integer_width(new_table_desc->pointer->revision); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_install_fixed_table |
* |
* PARAMETERS: address - Physical address of DSDT or FACS |
* signature - Table signature, NULL if no need to |
* match |
* table_index - Where the table index is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a fixed ACPI table (DSDT/FACS) into the global data |
* structure. |
* |
******************************************************************************/ |
acpi_status |
acpi_tb_install_fixed_table(acpi_physical_address address, |
char *signature, u32 *table_index) |
{ |
struct acpi_table_desc new_table_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(tb_install_fixed_table); |
if (!address) { |
ACPI_ERROR((AE_INFO, |
"Null physical address for ACPI table [%s]", |
signature)); |
return (AE_NO_MEMORY); |
} |
/* Fill a table descriptor for validation */ |
status = acpi_tb_acquire_temp_table(&new_table_desc, address, |
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not acquire table length at %8.8X%8.8X", |
ACPI_FORMAT_UINT64(address))); |
return_ACPI_STATUS(status); |
} |
/* Validate and verify a table before installation */ |
status = acpi_tb_verify_temp_table(&new_table_desc, signature); |
if (ACPI_FAILURE(status)) { |
goto release_and_exit; |
} |
/* Add the table to the global root table list */ |
acpi_tb_install_table_with_override(&new_table_desc, TRUE, table_index); |
release_and_exit: |
/* Release the temporary table descriptor */ |
acpi_tb_release_temp_table(&new_table_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_install_standard_table |
* |
* PARAMETERS: address - Address of the table (might be a virtual |
* address depending on the table_flags) |
* flags - Flags for the table |
* reload - Whether reload should be performed |
* override - Whether override should be performed |
* table_index - Where the table index is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to install an ACPI table that is |
* neither DSDT nor FACS (a "standard" table.) |
* When this function is called by "Load" or "LoadTable" opcodes, |
* or by acpi_load_table() API, the "Reload" parameter is set. |
* After sucessfully returning from this function, table is |
* "INSTALLED" but not "VALIDATED". |
* |
******************************************************************************/ |
acpi_status |
acpi_tb_install_standard_table(acpi_physical_address address, |
u8 flags, |
u8 reload, u8 override, u32 *table_index) |
{ |
u32 i; |
acpi_status status = AE_OK; |
struct acpi_table_desc new_table_desc; |
ACPI_FUNCTION_TRACE(tb_install_standard_table); |
/* Acquire a temporary table descriptor for validation */ |
status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags); |
if (ACPI_FAILURE(status)) { |
ACPI_ERROR((AE_INFO, |
"Could not acquire table length at %8.8X%8.8X", |
ACPI_FORMAT_UINT64(address))); |
return_ACPI_STATUS(status); |
} |
/* |
* Optionally do not load any SSDTs from the RSDT/XSDT. This can |
* be useful for debugging ACPI problems on some machines. |
*/ |
if (!reload && |
acpi_gbl_disable_ssdt_table_install && |
ACPI_COMPARE_NAME(&new_table_desc.signature, ACPI_SIG_SSDT)) { |
ACPI_INFO((AE_INFO, |
"Ignoring installation of %4.4s at %8.8X%8.8X", |
new_table_desc.signature.ascii, |
ACPI_FORMAT_UINT64(address))); |
goto release_and_exit; |
} |
/* Validate and verify a table before installation */ |
status = acpi_tb_verify_temp_table(&new_table_desc, NULL); |
if (ACPI_FAILURE(status)) { |
goto release_and_exit; |
} |
if (reload) { |
/* |
* Validate the incoming table signature. |
* |
* 1) Originally, we checked the table signature for "SSDT" or "PSDT". |
* 2) We added support for OEMx tables, signature "OEM". |
* 3) Valid tables were encountered with a null signature, so we just |
* gave up on validating the signature, (05/2008). |
* 4) We encountered non-AML tables such as the MADT, which caused |
* interpreter errors and kernel faults. So now, we once again allow |
* only "SSDT", "OEMx", and now, also a null signature. (05/2011). |
*/ |
if ((new_table_desc.signature.ascii[0] != 0x00) && |
(!ACPI_COMPARE_NAME |
(&new_table_desc.signature, ACPI_SIG_SSDT)) |
&& (strncmp(new_table_desc.signature.ascii, "OEM", 3))) { |
ACPI_BIOS_ERROR((AE_INFO, |
"Table has invalid signature [%4.4s] (0x%8.8X), " |
"must be SSDT or OEMx", |
acpi_ut_valid_acpi_name(new_table_desc. |
signature. |
ascii) ? |
new_table_desc.signature. |
ascii : "????", |
new_table_desc.signature.integer)); |
status = AE_BAD_SIGNATURE; |
goto release_and_exit; |
} |
/* Check if table is already registered */ |
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; |
++i) { |
/* |
* Check for a table match on the entire table length, |
* not just the header. |
*/ |
if (!acpi_tb_compare_tables(&new_table_desc, i)) { |
continue; |
} |
/* |
* Note: the current mechanism does not unregister a table if it is |
* dynamically unloaded. The related namespace entries are deleted, |
* but the table remains in the root table list. |
* |
* The assumption here is that the number of different tables that |
* will be loaded is actually small, and there is minimal overhead |
* in just keeping the table in case it is needed again. |
* |
* If this assumption changes in the future (perhaps on large |
* machines with many table load/unload operations), tables will |
* need to be unregistered when they are unloaded, and slots in the |
* root table list should be reused when empty. |
*/ |
if (acpi_gbl_root_table_list.tables[i]. |
flags & ACPI_TABLE_IS_LOADED) { |
/* Table is still loaded, this is an error */ |
status = AE_ALREADY_EXISTS; |
goto release_and_exit; |
} else { |
/* |
* Table was unloaded, allow it to be reloaded. |
* As we are going to return AE_OK to the caller, we should |
* take the responsibility of freeing the input descriptor. |
* Refill the input descriptor to ensure |
* acpi_tb_install_table_with_override() can be called again to |
* indicate the re-installation. |
*/ |
acpi_tb_uninstall_table(&new_table_desc); |
*table_index = i; |
return_ACPI_STATUS(AE_OK); |
} |
} |
} |
/* Add the table to the global root table list */ |
acpi_tb_install_table_with_override(&new_table_desc, override, |
table_index); |
release_and_exit: |
/* Release the temporary table descriptor */ |
acpi_tb_release_temp_table(&new_table_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_override_table |
* |
* PARAMETERS: old_table_desc - Validated table descriptor to be |
* overridden |
* |
* RETURN: None |
* |
* DESCRIPTION: Attempt table override by calling the OSL override functions. |
* Note: If the table is overridden, then the entire new table |
* is acquired and returned by this function. |
* Before/after invocation, the table descriptor is in a state |
* that is "VALIDATED". |
* |
******************************************************************************/ |
void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) |
{ |
acpi_status status; |
char *override_type; |
struct acpi_table_desc new_table_desc; |
struct acpi_table_header *table; |
acpi_physical_address address; |
u32 length; |
/* (1) Attempt logical override (returns a logical address) */ |
status = acpi_os_table_override(old_table_desc->pointer, &table); |
if (ACPI_SUCCESS(status) && table) { |
acpi_tb_acquire_temp_table(&new_table_desc, |
ACPI_PTR_TO_PHYSADDR(table), |
ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL); |
override_type = "Logical"; |
goto finish_override; |
} |
/* (2) Attempt physical override (returns a physical address) */ |
status = acpi_os_physical_table_override(old_table_desc->pointer, |
&address, &length); |
if (ACPI_SUCCESS(status) && address && length) { |
acpi_tb_acquire_temp_table(&new_table_desc, address, |
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); |
override_type = "Physical"; |
goto finish_override; |
} |
return; /* There was no override */ |
finish_override: |
/* Validate and verify a table before overriding */ |
status = acpi_tb_verify_temp_table(&new_table_desc, NULL); |
if (ACPI_FAILURE(status)) { |
return; |
} |
ACPI_INFO((AE_INFO, "%4.4s 0x%8.8X%8.8X" |
" %s table override, new table: 0x%8.8X%8.8X", |
old_table_desc->signature.ascii, |
ACPI_FORMAT_UINT64(old_table_desc->address), |
override_type, ACPI_FORMAT_UINT64(new_table_desc.address))); |
/* We can now uninstall the original table */ |
acpi_tb_uninstall_table(old_table_desc); |
/* |
* Replace the original table descriptor and keep its state as |
* "VALIDATED". |
*/ |
acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address, |
new_table_desc.flags, |
new_table_desc.pointer); |
acpi_tb_validate_temp_table(old_table_desc); |
/* Release the temporary table descriptor */ |
acpi_tb_release_temp_table(&new_table_desc); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_uninstall_table |
* |
* PARAMETERS: table_desc - Table descriptor |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete one internal ACPI table |
* |
******************************************************************************/ |
void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) |
{ |
ACPI_FUNCTION_TRACE(tb_uninstall_table); |
/* Table must be installed */ |
if (!table_desc->address) { |
return_VOID; |
} |
acpi_tb_invalidate_table(table_desc); |
if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == |
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) { |
ACPI_FREE(ACPI_PHYSADDR_TO_PTR(table_desc->address)); |
} |
table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); |
return_VOID; |
} |
/drivers/acpi/acpica/tbprint.c |
---|
0,0 → 1,244 |
/****************************************************************************** |
* |
* Module Name: tbprint - Table output utilities |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbprint") |
/* Local prototypes */ |
static void acpi_tb_fix_string(char *string, acpi_size length); |
static void |
acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, |
struct acpi_table_header *header); |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_fix_string |
* |
* PARAMETERS: string - String to be repaired |
* length - Maximum length |
* |
* RETURN: None |
* |
* DESCRIPTION: Replace every non-printable or non-ascii byte in the string |
* with a question mark '?'. |
* |
******************************************************************************/ |
static void acpi_tb_fix_string(char *string, acpi_size length) |
{ |
while (length && *string) { |
if (!isprint((int)*string)) { |
*string = '?'; |
} |
string++; |
length--; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_cleanup_table_header |
* |
* PARAMETERS: out_header - Where the cleaned header is returned |
* header - Input ACPI table header |
* |
* RETURN: Returns the cleaned header in out_header |
* |
* DESCRIPTION: Copy the table header and ensure that all "string" fields in |
* the header consist of printable characters. |
* |
******************************************************************************/ |
static void |
acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, |
struct acpi_table_header *header) |
{ |
memcpy(out_header, header, sizeof(struct acpi_table_header)); |
acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE); |
acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE); |
acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE); |
acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_print_table_header |
* |
* PARAMETERS: address - Table physical address |
* header - Table header |
* |
* RETURN: None |
* |
* DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP. |
* |
******************************************************************************/ |
void |
acpi_tb_print_table_header(acpi_physical_address address, |
struct acpi_table_header *header) |
{ |
struct acpi_table_header local_header; |
if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) { |
/* FACS only has signature and length fields */ |
ACPI_INFO((AE_INFO, "%-4.4s 0x%8.8X%8.8X %06X", |
header->signature, ACPI_FORMAT_UINT64(address), |
header->length)); |
} else if (ACPI_VALIDATE_RSDP_SIG(header->signature)) { |
/* RSDP has no common fields */ |
memcpy(local_header.oem_id, |
ACPI_CAST_PTR(struct acpi_table_rsdp, header)->oem_id, |
ACPI_OEM_ID_SIZE); |
acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE); |
ACPI_INFO((AE_INFO, "RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)", |
ACPI_FORMAT_UINT64(address), |
(ACPI_CAST_PTR(struct acpi_table_rsdp, header)-> |
revision > |
0) ? ACPI_CAST_PTR(struct acpi_table_rsdp, |
header)->length : 20, |
ACPI_CAST_PTR(struct acpi_table_rsdp, |
header)->revision, |
local_header.oem_id)); |
} else { |
/* Standard ACPI table with full common header */ |
acpi_tb_cleanup_table_header(&local_header, header); |
ACPI_INFO((AE_INFO, |
"%-4.4s 0x%8.8X%8.8X" |
" %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)", |
local_header.signature, ACPI_FORMAT_UINT64(address), |
local_header.length, local_header.revision, |
local_header.oem_id, local_header.oem_table_id, |
local_header.oem_revision, |
local_header.asl_compiler_id, |
local_header.asl_compiler_revision)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_validate_checksum |
* |
* PARAMETERS: table - ACPI table to verify |
* length - Length of entire table |
* |
* RETURN: Status |
* |
* DESCRIPTION: Verifies that the table checksums to zero. Optionally returns |
* exception on bad checksum. |
* |
******************************************************************************/ |
acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length) |
{ |
u8 checksum; |
/* |
* FACS/S3PT: |
* They are the odd tables, have no standard ACPI header and no checksum |
*/ |
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_S3PT) || |
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_FACS)) { |
return (AE_OK); |
} |
/* Compute the checksum on the table */ |
checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length); |
/* Checksum ok? (should be zero) */ |
if (checksum) { |
ACPI_BIOS_WARNING((AE_INFO, |
"Incorrect checksum in table [%4.4s] - 0x%2.2X, " |
"should be 0x%2.2X", |
table->signature, table->checksum, |
(u8)(table->checksum - checksum))); |
#if (ACPI_CHECKSUM_ABORT) |
return (AE_BAD_CHECKSUM); |
#endif |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_checksum |
* |
* PARAMETERS: buffer - Pointer to memory region to be checked |
* length - Length of this memory region |
* |
* RETURN: Checksum (u8) |
* |
* DESCRIPTION: Calculates circular checksum of memory region. |
* |
******************************************************************************/ |
u8 acpi_tb_checksum(u8 *buffer, u32 length) |
{ |
u8 sum = 0; |
u8 *end = buffer + length; |
while (buffer < end) { |
sum = (u8)(sum + *(buffer++)); |
} |
return (sum); |
} |
/drivers/acpi/acpica/tbutils.c |
---|
0,0 → 1,417 |
/****************************************************************************** |
* |
* Module Name: tbutils - ACPI Table utilities |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbutils") |
/* Local prototypes */ |
static acpi_physical_address |
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); |
#if (!ACPI_REDUCED_HARDWARE) |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_initialize_facs |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a permanent mapping for the FADT and save it in a global |
* for accessing the Global Lock and Firmware Waking Vector |
* |
******************************************************************************/ |
acpi_status acpi_tb_initialize_facs(void) |
{ |
struct acpi_table_facs *facs; |
/* If Hardware Reduced flag is set, there is no FACS */ |
if (acpi_gbl_reduced_hardware) { |
acpi_gbl_FACS = NULL; |
return (AE_OK); |
} else if (acpi_gbl_FADT.Xfacs && |
(!acpi_gbl_FADT.facs |
|| !acpi_gbl_use32_bit_facs_addresses)) { |
(void)acpi_get_table_by_index(acpi_gbl_xfacs_index, |
ACPI_CAST_INDIRECT_PTR(struct |
acpi_table_header, |
&facs)); |
acpi_gbl_FACS = facs; |
} else if (acpi_gbl_FADT.facs) { |
(void)acpi_get_table_by_index(acpi_gbl_facs_index, |
ACPI_CAST_INDIRECT_PTR(struct |
acpi_table_header, |
&facs)); |
acpi_gbl_FACS = facs; |
} |
/* If there is no FACS, just continue. There was already an error msg */ |
return (AE_OK); |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_check_dsdt_header |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Quick compare to check validity of the DSDT. This will detect |
* if the DSDT has been replaced from outside the OS and/or if |
* the DSDT header has been corrupted. |
* |
******************************************************************************/ |
void acpi_tb_check_dsdt_header(void) |
{ |
/* Compare original length and checksum to current values */ |
if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length || |
acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) { |
ACPI_BIOS_ERROR((AE_INFO, |
"The DSDT has been corrupted or replaced - " |
"old, new headers below")); |
acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header); |
acpi_tb_print_table_header(0, acpi_gbl_DSDT); |
ACPI_ERROR((AE_INFO, |
"Please send DMI info to linux-acpi@vger.kernel.org\n" |
"If system does not work as expected, please boot with acpi=copy_dsdt")); |
/* Disable further error messages */ |
acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length; |
acpi_gbl_original_dsdt_header.checksum = |
acpi_gbl_DSDT->checksum; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_copy_dsdt |
* |
* PARAMETERS: table_desc - Installed table to copy |
* |
* RETURN: None |
* |
* DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. |
* Some very bad BIOSs are known to either corrupt the DSDT or |
* install a new, bad DSDT. This copy works around the problem. |
* |
******************************************************************************/ |
struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) |
{ |
struct acpi_table_header *new_table; |
struct acpi_table_desc *table_desc; |
table_desc = &acpi_gbl_root_table_list.tables[table_index]; |
new_table = ACPI_ALLOCATE(table_desc->length); |
if (!new_table) { |
ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X", |
table_desc->length)); |
return (NULL); |
} |
memcpy(new_table, table_desc->pointer, table_desc->length); |
acpi_tb_uninstall_table(table_desc); |
acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. |
tables[acpi_gbl_dsdt_index], |
ACPI_PTR_TO_PHYSADDR(new_table), |
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, |
new_table); |
ACPI_INFO((AE_INFO, |
"Forced DSDT copy: length 0x%05X copied locally, original unmapped", |
new_table->length)); |
return (new_table); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_get_root_table_entry |
* |
* PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry |
* table_entry_size - sizeof 32 or 64 (RSDT or XSDT) |
* |
* RETURN: Physical address extracted from the root table |
* |
* DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on |
* both 32-bit and 64-bit platforms |
* |
* NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on |
* 64-bit platforms. |
* |
******************************************************************************/ |
static acpi_physical_address |
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) |
{ |
u64 address64; |
/* |
* Get the table physical address (32-bit for RSDT, 64-bit for XSDT): |
* Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT |
*/ |
if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) { |
/* |
* 32-bit platform, RSDT: Return 32-bit table entry |
* 64-bit platform, RSDT: Expand 32-bit to 64-bit and return |
*/ |
return ((acpi_physical_address) |
(*ACPI_CAST_PTR(u32, table_entry))); |
} else { |
/* |
* 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return |
* 64-bit platform, XSDT: Move (unaligned) 64-bit to local, |
* return 64-bit |
*/ |
ACPI_MOVE_64_TO_64(&address64, table_entry); |
#if ACPI_MACHINE_WIDTH == 32 |
if (address64 > ACPI_UINT32_MAX) { |
/* Will truncate 64-bit address to 32 bits, issue warning */ |
ACPI_BIOS_WARNING((AE_INFO, |
"64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X)," |
" truncating", |
ACPI_FORMAT_UINT64(address64))); |
} |
#endif |
return ((acpi_physical_address) (address64)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_parse_root_table |
* |
* PARAMETERS: rsdp - Pointer to the RSDP |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to parse the Root System Description |
* Table (RSDT or XSDT) |
* |
* NOTE: Tables are mapped (not copied) for efficiency. The FACS must |
* be mapped and cannot be copied because it contains the actual |
* memory location of the ACPI Global Lock. |
* |
******************************************************************************/ |
acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) |
{ |
struct acpi_table_rsdp *rsdp; |
u32 table_entry_size; |
u32 i; |
u32 table_count; |
struct acpi_table_header *table; |
acpi_physical_address address; |
u32 length; |
u8 *table_entry; |
acpi_status status; |
u32 table_index; |
ACPI_FUNCTION_TRACE(tb_parse_root_table); |
/* Map the entire RSDP and extract the address of the RSDT or XSDT */ |
rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp)); |
if (!rsdp) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
acpi_tb_print_table_header(rsdp_address, |
ACPI_CAST_PTR(struct acpi_table_header, |
rsdp)); |
/* Use XSDT if present and not overridden. Otherwise, use RSDT */ |
if ((rsdp->revision > 1) && |
rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) { |
/* |
* RSDP contains an XSDT (64-bit physical addresses). We must use |
* the XSDT if the revision is > 1 and the XSDT pointer is present, |
* as per the ACPI specification. |
*/ |
address = (acpi_physical_address) rsdp->xsdt_physical_address; |
table_entry_size = ACPI_XSDT_ENTRY_SIZE; |
} else { |
/* Root table is an RSDT (32-bit physical addresses) */ |
address = (acpi_physical_address) rsdp->rsdt_physical_address; |
table_entry_size = ACPI_RSDT_ENTRY_SIZE; |
} |
/* |
* It is not possible to map more than one entry in some environments, |
* so unmap the RSDP here before mapping other tables |
*/ |
acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); |
/* Map the RSDT/XSDT table header to get the full table length */ |
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); |
if (!table) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
acpi_tb_print_table_header(address, table); |
/* |
* Validate length of the table, and map entire table. |
* Minimum length table must contain at least one entry. |
*/ |
length = table->length; |
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); |
if (length < (sizeof(struct acpi_table_header) + table_entry_size)) { |
ACPI_BIOS_ERROR((AE_INFO, |
"Invalid table length 0x%X in RSDT/XSDT", |
length)); |
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); |
} |
table = acpi_os_map_memory(address, length); |
if (!table) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Validate the root table checksum */ |
status = acpi_tb_verify_checksum(table, length); |
if (ACPI_FAILURE(status)) { |
acpi_os_unmap_memory(table, length); |
return_ACPI_STATUS(status); |
} |
/* Get the number of entries and pointer to first entry */ |
table_count = (u32)((table->length - sizeof(struct acpi_table_header)) / |
table_entry_size); |
table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); |
/* Initialize the root table array from the RSDT/XSDT */ |
for (i = 0; i < table_count; i++) { |
/* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ |
address = |
acpi_tb_get_root_table_entry(table_entry, table_entry_size); |
/* Skip NULL entries in RSDT/XSDT */ |
if (!address) { |
goto next_table; |
} |
status = acpi_tb_install_standard_table(address, |
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, |
FALSE, TRUE, |
&table_index); |
if (ACPI_SUCCESS(status) && |
ACPI_COMPARE_NAME(&acpi_gbl_root_table_list. |
tables[table_index].signature, |
ACPI_SIG_FADT)) { |
acpi_gbl_fadt_index = table_index; |
acpi_tb_parse_fadt(); |
} |
next_table: |
table_entry += table_entry_size; |
} |
acpi_os_unmap_memory(table, length); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_is_valid_signature |
* |
* PARAMETERS: signature - Sig string to be validated |
* |
* RETURN: TRUE if signature is correct length and has valid characters |
* |
* DESCRIPTION: Validate an ACPI table signature. |
* |
******************************************************************************/ |
u8 acpi_is_valid_signature(char *signature) |
{ |
u32 i; |
/* Validate the signature length */ |
if (strlen(signature) != ACPI_NAME_SIZE) { |
return (FALSE); |
} |
/* Validate each character in the signature */ |
for (i = 0; i < ACPI_NAME_SIZE; i++) { |
if (!acpi_ut_valid_acpi_char(signature[i], i)) { |
return (FALSE); |
} |
} |
return (TRUE); |
} |
/drivers/acpi/acpica/tbxface.c |
---|
0,0 → 1,482 |
/****************************************************************************** |
* |
* Module Name: tbxface - ACPI table-oriented external interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbxface") |
/******************************************************************************* |
* |
* FUNCTION: acpi_allocate_root_table |
* |
* PARAMETERS: initial_table_count - Size of initial_table_array, in number of |
* struct acpi_table_desc structures |
* |
* RETURN: Status |
* |
* DESCRIPTION: Allocate a root table array. Used by iASL compiler and |
* acpi_initialize_tables. |
* |
******************************************************************************/ |
acpi_status acpi_allocate_root_table(u32 initial_table_count) |
{ |
acpi_gbl_root_table_list.max_table_count = initial_table_count; |
acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE; |
return (acpi_tb_resize_root_table_list()); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_initialize_tables |
* |
* PARAMETERS: initial_table_array - Pointer to an array of pre-allocated |
* struct acpi_table_desc structures. If NULL, the |
* array is dynamically allocated. |
* initial_table_count - Size of initial_table_array, in number of |
* struct acpi_table_desc structures |
* allow_resize - Flag to tell Table Manager if resize of |
* pre-allocated array is allowed. Ignored |
* if initial_table_array is NULL. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT. |
* |
* NOTE: Allows static allocation of the initial table array in order |
* to avoid the use of dynamic memory in confined environments |
* such as the kernel boot sequence where it may not be available. |
* |
* If the host OS memory managers are initialized, use NULL for |
* initial_table_array, and the table will be dynamically allocated. |
* |
******************************************************************************/ |
acpi_status __init |
acpi_initialize_tables(struct acpi_table_desc * initial_table_array, |
u32 initial_table_count, u8 allow_resize) |
{ |
acpi_physical_address rsdp_address; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_initialize_tables); |
/* |
* Setup the Root Table Array and allocate the table array |
* if requested |
*/ |
if (!initial_table_array) { |
status = acpi_allocate_root_table(initial_table_count); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} else { |
/* Root Table Array has been statically allocated by the host */ |
memset(initial_table_array, 0, |
(acpi_size) initial_table_count * |
sizeof(struct acpi_table_desc)); |
acpi_gbl_root_table_list.tables = initial_table_array; |
acpi_gbl_root_table_list.max_table_count = initial_table_count; |
acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN; |
if (allow_resize) { |
acpi_gbl_root_table_list.flags |= |
ACPI_ROOT_ALLOW_RESIZE; |
} |
} |
/* Get the address of the RSDP */ |
rsdp_address = acpi_os_get_root_pointer(); |
if (!rsdp_address) { |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
/* |
* Get the root table (RSDT or XSDT) and extract all entries to the local |
* Root Table Array. This array contains the information of the RSDT/XSDT |
* in a common, more useable format. |
*/ |
status = acpi_tb_parse_root_table(rsdp_address); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_tables) |
/******************************************************************************* |
* |
* FUNCTION: acpi_reallocate_root_table |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the |
* root list from the previously provided scratch area. Should |
* be called once dynamic memory allocation is available in the |
* kernel. |
* |
******************************************************************************/ |
acpi_status __init acpi_reallocate_root_table(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_reallocate_root_table); |
/* |
* Only reallocate the root table if the host provided a static buffer |
* for the table array in the call to acpi_initialize_tables. |
*/ |
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { |
return_ACPI_STATUS(AE_SUPPORT); |
} |
acpi_gbl_root_table_list.flags |= ACPI_ROOT_ALLOW_RESIZE; |
status = acpi_tb_resize_root_table_list(); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_reallocate_root_table) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_table_header |
* |
* PARAMETERS: signature - ACPI signature of needed table |
* instance - Which instance (for SSDTs) |
* out_table_header - The pointer to the table header to fill |
* |
* RETURN: Status and pointer to mapped table header |
* |
* DESCRIPTION: Finds an ACPI table header. |
* |
* NOTE: Caller is responsible in unmapping the header with |
* acpi_os_unmap_memory |
* |
******************************************************************************/ |
acpi_status |
acpi_get_table_header(char *signature, |
u32 instance, struct acpi_table_header *out_table_header) |
{ |
u32 i; |
u32 j; |
struct acpi_table_header *header; |
/* Parameter validation */ |
if (!signature || !out_table_header) { |
return (AE_BAD_PARAMETER); |
} |
/* Walk the root table list */ |
for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count; |
i++) { |
if (!ACPI_COMPARE_NAME |
(&(acpi_gbl_root_table_list.tables[i].signature), |
signature)) { |
continue; |
} |
if (++j < instance) { |
continue; |
} |
if (!acpi_gbl_root_table_list.tables[i].pointer) { |
if ((acpi_gbl_root_table_list.tables[i].flags & |
ACPI_TABLE_ORIGIN_MASK) == |
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) { |
header = |
acpi_os_map_memory(acpi_gbl_root_table_list. |
tables[i].address, |
sizeof(struct |
acpi_table_header)); |
if (!header) { |
return (AE_NO_MEMORY); |
} |
memcpy(out_table_header, header, |
sizeof(struct acpi_table_header)); |
acpi_os_unmap_memory(header, |
sizeof(struct |
acpi_table_header)); |
} else { |
return (AE_NOT_FOUND); |
} |
} else { |
memcpy(out_table_header, |
acpi_gbl_root_table_list.tables[i].pointer, |
sizeof(struct acpi_table_header)); |
} |
return (AE_OK); |
} |
return (AE_NOT_FOUND); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_table_header) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_table_with_size |
* |
* PARAMETERS: signature - ACPI signature of needed table |
* instance - Which instance (for SSDTs) |
* out_table - Where the pointer to the table is returned |
* |
* RETURN: Status and pointer to the requested table |
* |
* DESCRIPTION: Finds and verifies an ACPI table. Table must be in the |
* RSDT/XSDT. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_table_with_size(char *signature, |
u32 instance, struct acpi_table_header **out_table, |
acpi_size *tbl_size) |
{ |
u32 i; |
u32 j; |
acpi_status status; |
/* Parameter validation */ |
if (!signature || !out_table) { |
return (AE_BAD_PARAMETER); |
} |
/* Walk the root table list */ |
for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count; |
i++) { |
if (!ACPI_COMPARE_NAME |
(&(acpi_gbl_root_table_list.tables[i].signature), |
signature)) { |
continue; |
} |
if (++j < instance) { |
continue; |
} |
status = |
acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]); |
if (ACPI_SUCCESS(status)) { |
*out_table = acpi_gbl_root_table_list.tables[i].pointer; |
*tbl_size = acpi_gbl_root_table_list.tables[i].length; |
} |
if (!acpi_gbl_permanent_mmap) { |
acpi_gbl_root_table_list.tables[i].pointer = NULL; |
} |
return (status); |
} |
return (AE_NOT_FOUND); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_table_with_size) |
acpi_status |
acpi_get_table(char *signature, |
u32 instance, struct acpi_table_header **out_table) |
{ |
acpi_size tbl_size; |
return acpi_get_table_with_size(signature, |
instance, out_table, &tbl_size); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_table) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_table_by_index |
* |
* PARAMETERS: table_index - Table index |
* table - Where the pointer to the table is returned |
* |
* RETURN: Status and pointer to the requested table |
* |
* DESCRIPTION: Obtain a table by an index into the global table list. Used |
* internally also. |
* |
******************************************************************************/ |
acpi_status |
acpi_get_table_by_index(u32 table_index, struct acpi_table_header ** table) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_get_table_by_index); |
/* Parameter validation */ |
if (!table) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
/* Validate index */ |
if (table_index >= acpi_gbl_root_table_list.current_table_count) { |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (!acpi_gbl_root_table_list.tables[table_index].pointer) { |
/* Table is not mapped, map it */ |
status = |
acpi_tb_validate_table(&acpi_gbl_root_table_list. |
tables[table_index]); |
if (ACPI_FAILURE(status)) { |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(status); |
} |
} |
*table = acpi_gbl_root_table_list.tables[table_index].pointer; |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_table_by_index) |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_table_handler |
* |
* PARAMETERS: handler - Table event handler |
* context - Value passed to the handler on each event |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a global table event handler. |
* |
******************************************************************************/ |
acpi_status |
acpi_install_table_handler(acpi_table_handler handler, void *context) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_install_table_handler); |
if (!handler) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Don't allow more than one handler */ |
if (acpi_gbl_table_handler) { |
status = AE_ALREADY_EXISTS; |
goto cleanup; |
} |
/* Install the handler */ |
acpi_gbl_table_handler = handler; |
acpi_gbl_table_handler_context = context; |
cleanup: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_table_handler) |
/******************************************************************************* |
* |
* FUNCTION: acpi_remove_table_handler |
* |
* PARAMETERS: handler - Table event handler that was installed |
* previously. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove a table event handler |
* |
******************************************************************************/ |
acpi_status acpi_remove_table_handler(acpi_table_handler handler) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_remove_table_handler); |
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Make sure that the installed handler is the same */ |
if (!handler || handler != acpi_gbl_table_handler) { |
status = AE_BAD_PARAMETER; |
goto cleanup; |
} |
/* Remove the handler */ |
acpi_gbl_table_handler = NULL; |
cleanup: |
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_table_handler) |
/drivers/acpi/acpica/tbxfload.c |
---|
0,0 → 1,448 |
/****************************************************************************** |
* |
* Module Name: tbxfload - Table load/unload external interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbxfload") |
/******************************************************************************* |
* |
* FUNCTION: acpi_load_tables |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load the ACPI tables from the RSDT/XSDT |
* |
******************************************************************************/ |
acpi_status __init acpi_load_tables(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_load_tables); |
/* Load the namespace from the tables */ |
status = acpi_tb_load_namespace(); |
/* Don't let single failures abort the load */ |
if (status == AE_CTRL_TERMINATE) { |
status = AE_OK; |
} |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"While loading namespace from ACPI tables")); |
} |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_load_tables) |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_load_namespace |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in |
* the RSDT/XSDT. |
* |
******************************************************************************/ |
acpi_status acpi_tb_load_namespace(void) |
{ |
acpi_status status; |
u32 i; |
struct acpi_table_header *new_dsdt; |
struct acpi_table_desc *table; |
u32 tables_loaded = 0; |
u32 tables_failed = 0; |
ACPI_FUNCTION_TRACE(tb_load_namespace); |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
/* |
* Load the namespace. The DSDT is required, but any SSDT and |
* PSDT tables are optional. Verify the DSDT. |
*/ |
table = &acpi_gbl_root_table_list.tables[acpi_gbl_dsdt_index]; |
if (!acpi_gbl_root_table_list.current_table_count || |
!ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_DSDT) || |
ACPI_FAILURE(acpi_tb_validate_table(table))) { |
status = AE_NO_ACPI_TABLES; |
goto unlock_and_exit; |
} |
/* |
* Save the DSDT pointer for simple access. This is the mapped memory |
* address. We must take care here because the address of the .Tables |
* array can change dynamically as tables are loaded at run-time. Note: |
* .Pointer field is not validated until after call to acpi_tb_validate_table. |
*/ |
acpi_gbl_DSDT = table->pointer; |
/* |
* Optionally copy the entire DSDT to local memory (instead of simply |
* mapping it.) There are some BIOSs that corrupt or replace the original |
* DSDT, creating the need for this option. Default is FALSE, do not copy |
* the DSDT. |
*/ |
if (acpi_gbl_copy_dsdt_locally) { |
new_dsdt = acpi_tb_copy_dsdt(acpi_gbl_dsdt_index); |
if (new_dsdt) { |
acpi_gbl_DSDT = new_dsdt; |
} |
} |
/* |
* Save the original DSDT header for detection of table corruption |
* and/or replacement of the DSDT from outside the OS. |
*/ |
memcpy(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT, |
sizeof(struct acpi_table_header)); |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
/* Load and parse tables */ |
status = acpi_ns_load_table(acpi_gbl_dsdt_index, acpi_gbl_root_node); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, "[DSDT] table load failed")); |
tables_failed++; |
} else { |
tables_loaded++; |
} |
/* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { |
table = &acpi_gbl_root_table_list.tables[i]; |
if (!acpi_gbl_root_table_list.tables[i].address || |
(!ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_SSDT) |
&& !ACPI_COMPARE_NAME(table->signature.ascii, |
ACPI_SIG_PSDT) |
&& !ACPI_COMPARE_NAME(table->signature.ascii, |
ACPI_SIG_OSDT)) |
|| ACPI_FAILURE(acpi_tb_validate_table(table))) { |
continue; |
} |
/* Ignore errors while loading tables, get as many as possible */ |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
status = acpi_ns_load_table(i, acpi_gbl_root_node); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"(%4.4s:%8.8s) while loading table", |
table->signature.ascii, |
table->pointer->oem_table_id)); |
tables_failed++; |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
"Table [%4.4s:%8.8s] (id FF) - Table namespace load failed\n\n", |
table->signature.ascii, |
table->pointer->oem_table_id)); |
} else { |
tables_loaded++; |
} |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
} |
if (!tables_failed) { |
ACPI_INFO((AE_INFO, |
"%u ACPI AML tables successfully acquired and loaded", |
tables_loaded)); |
} else { |
ACPI_ERROR((AE_INFO, |
"%u table load failures, %u successful", |
tables_failed, tables_loaded)); |
/* Indicate at least one failure */ |
status = AE_CTRL_TERMINATE; |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_install_table |
* |
* PARAMETERS: address - Address of the ACPI table to be installed. |
* physical - Whether the address is a physical table |
* address or not |
* |
* RETURN: Status |
* |
* DESCRIPTION: Dynamically install an ACPI table. |
* Note: This function should only be invoked after |
* acpi_initialize_tables() and before acpi_load_tables(). |
* |
******************************************************************************/ |
acpi_status __init |
acpi_install_table(acpi_physical_address address, u8 physical) |
{ |
acpi_status status; |
u8 flags; |
u32 table_index; |
ACPI_FUNCTION_TRACE(acpi_install_table); |
if (physical) { |
flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL; |
} else { |
flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; |
} |
status = acpi_tb_install_standard_table(address, flags, |
FALSE, FALSE, &table_index); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) |
/******************************************************************************* |
* |
* FUNCTION: acpi_load_table |
* |
* PARAMETERS: table - Pointer to a buffer containing the ACPI |
* table to be loaded. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must |
* be a valid ACPI table with a valid ACPI table header. |
* Note1: Mainly intended to support hotplug addition of SSDTs. |
* Note2: Does not copy the incoming table. User is responsible |
* to ensure that the table is not deleted or unmapped. |
* |
******************************************************************************/ |
acpi_status acpi_load_table(struct acpi_table_header *table) |
{ |
acpi_status status; |
u32 table_index; |
ACPI_FUNCTION_TRACE(acpi_load_table); |
/* Parameter validation */ |
if (!table) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Must acquire the interpreter lock during this operation */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Install the table and load it into the namespace */ |
ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); |
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), |
ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, |
TRUE, FALSE, &table_index); |
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
/* |
* Note: Now table is "INSTALLED", it must be validated before |
* using. |
*/ |
status = |
acpi_tb_validate_table(&acpi_gbl_root_table_list. |
tables[table_index]); |
if (ACPI_FAILURE(status)) { |
goto unlock_and_exit; |
} |
status = acpi_ns_load_table(table_index, acpi_gbl_root_node); |
/* Invoke table handler if present */ |
if (acpi_gbl_table_handler) { |
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, |
acpi_gbl_table_handler_context); |
} |
unlock_and_exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_load_table) |
/******************************************************************************* |
* |
* FUNCTION: acpi_unload_parent_table |
* |
* PARAMETERS: object - Handle to any namespace object owned by |
* the table to be unloaded |
* |
* RETURN: Status |
* |
* DESCRIPTION: Via any namespace object within an SSDT or OEMx table, unloads |
* the table and deletes all namespace objects associated with |
* that table. Unloading of the DSDT is not allowed. |
* Note: Mainly intended to support hotplug removal of SSDTs. |
* |
******************************************************************************/ |
acpi_status acpi_unload_parent_table(acpi_handle object) |
{ |
struct acpi_namespace_node *node = |
ACPI_CAST_PTR(struct acpi_namespace_node, object); |
acpi_status status = AE_NOT_EXIST; |
acpi_owner_id owner_id; |
u32 i; |
ACPI_FUNCTION_TRACE(acpi_unload_parent_table); |
/* Parameter validation */ |
if (!object) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* |
* The node owner_id is currently the same as the parent table ID. |
* However, this could change in the future. |
*/ |
owner_id = node->owner_id; |
if (!owner_id) { |
/* owner_id==0 means DSDT is the owner. DSDT cannot be unloaded */ |
return_ACPI_STATUS(AE_TYPE); |
} |
/* Must acquire the interpreter lock during this operation */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Find the table in the global table list */ |
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { |
if (owner_id != acpi_gbl_root_table_list.tables[i].owner_id) { |
continue; |
} |
/* |
* Allow unload of SSDT and OEMx tables only. Do not allow unload |
* of the DSDT. No other types of tables should get here, since |
* only these types can contain AML and thus are the only types |
* that can create namespace objects. |
*/ |
if (ACPI_COMPARE_NAME |
(acpi_gbl_root_table_list.tables[i].signature.ascii, |
ACPI_SIG_DSDT)) { |
status = AE_TYPE; |
break; |
} |
/* Ensure the table is actually loaded */ |
if (!acpi_tb_is_table_loaded(i)) { |
status = AE_NOT_EXIST; |
break; |
} |
/* Invoke table handler if present */ |
if (acpi_gbl_table_handler) { |
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD, |
acpi_gbl_root_table_list. |
tables[i].pointer, |
acpi_gbl_table_handler_context); |
} |
/* |
* Delete all namespace objects owned by this table. Note that |
* these objects can appear anywhere in the namespace by virtue |
* of the AML "Scope" operator. Thus, we need to track ownership |
* by an ID, not simply a position within the hierarchy. |
*/ |
status = acpi_tb_delete_namespace_by_owner(i); |
if (ACPI_FAILURE(status)) { |
break; |
} |
status = acpi_tb_release_owner_id(i); |
acpi_tb_set_table_loaded_flag(i, FALSE); |
break; |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL(acpi_unload_parent_table) |
/drivers/acpi/acpica/tbxfroot.c |
---|
0,0 → 1,298 |
/****************************************************************************** |
* |
* Module Name: tbxfroot - Find the root ACPI table (RSDT) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#define _COMPONENT ACPI_TABLES |
ACPI_MODULE_NAME("tbxfroot") |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_get_rsdp_length |
* |
* PARAMETERS: rsdp - Pointer to RSDP |
* |
* RETURN: Table length |
* |
* DESCRIPTION: Get the length of the RSDP |
* |
******************************************************************************/ |
u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp) |
{ |
if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) { |
/* BAD Signature */ |
return (0); |
} |
/* "Length" field is available if table version >= 2 */ |
if (rsdp->revision >= 2) { |
return (rsdp->length); |
} else { |
return (ACPI_RSDP_CHECKSUM_LENGTH); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_validate_rsdp |
* |
* PARAMETERS: rsdp - Pointer to unvalidated RSDP |
* |
* RETURN: Status |
* |
* DESCRIPTION: Validate the RSDP (ptr) |
* |
******************************************************************************/ |
acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp * rsdp) |
{ |
/* |
* The signature and checksum must both be correct |
* |
* Note: Sometimes there exists more than one RSDP in memory; the valid |
* RSDP has a valid checksum, all others have an invalid checksum. |
*/ |
if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) { |
/* Nope, BAD Signature */ |
return (AE_BAD_SIGNATURE); |
} |
/* Check the standard checksum */ |
if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { |
return (AE_BAD_CHECKSUM); |
} |
/* Check extended checksum if table version >= 2 */ |
if ((rsdp->revision >= 2) && |
(acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) { |
return (AE_BAD_CHECKSUM); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_find_root_pointer |
* |
* PARAMETERS: table_address - Where the table pointer is returned |
* |
* RETURN: Status, RSDP physical address |
* |
* DESCRIPTION: Search lower 1Mbyte of memory for the root system descriptor |
* pointer structure. If it is found, set *RSDP to point to it. |
* |
* NOTE1: The RSDP must be either in the first 1K of the Extended |
* BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) |
* Only a 32-bit physical address is necessary. |
* |
* NOTE2: This function is always available, regardless of the |
* initialization state of the rest of ACPI. |
* |
******************************************************************************/ |
acpi_status __init acpi_find_root_pointer(acpi_physical_address * table_address) |
{ |
u8 *table_ptr; |
u8 *mem_rover; |
u32 physical_address; |
ACPI_FUNCTION_TRACE(acpi_find_root_pointer); |
/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ |
table_ptr = acpi_os_map_memory((acpi_physical_address) |
ACPI_EBDA_PTR_LOCATION, |
ACPI_EBDA_PTR_LENGTH); |
if (!table_ptr) { |
ACPI_ERROR((AE_INFO, |
"Could not map memory at 0x%8.8X for length %u", |
ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
ACPI_MOVE_16_TO_32(&physical_address, table_ptr); |
/* Convert segment part to physical address */ |
physical_address <<= 4; |
acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH); |
/* EBDA present? */ |
if (physical_address > 0x400) { |
/* |
* 1b) Search EBDA paragraphs (EBDA is required to be a |
* minimum of 1K length) |
*/ |
table_ptr = acpi_os_map_memory((acpi_physical_address) |
physical_address, |
ACPI_EBDA_WINDOW_SIZE); |
if (!table_ptr) { |
ACPI_ERROR((AE_INFO, |
"Could not map memory at 0x%8.8X for length %u", |
physical_address, ACPI_EBDA_WINDOW_SIZE)); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
mem_rover = |
acpi_tb_scan_memory_for_rsdp(table_ptr, |
ACPI_EBDA_WINDOW_SIZE); |
acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); |
if (mem_rover) { |
/* Return the physical address */ |
physical_address += |
(u32) ACPI_PTR_DIFF(mem_rover, table_ptr); |
*table_address = |
(acpi_physical_address) physical_address; |
return_ACPI_STATUS(AE_OK); |
} |
} |
/* |
* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh |
*/ |
table_ptr = acpi_os_map_memory((acpi_physical_address) |
ACPI_HI_RSDP_WINDOW_BASE, |
ACPI_HI_RSDP_WINDOW_SIZE); |
if (!table_ptr) { |
ACPI_ERROR((AE_INFO, |
"Could not map memory at 0x%8.8X for length %u", |
ACPI_HI_RSDP_WINDOW_BASE, |
ACPI_HI_RSDP_WINDOW_SIZE)); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
mem_rover = |
acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); |
acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); |
if (mem_rover) { |
/* Return the physical address */ |
physical_address = (u32) |
(ACPI_HI_RSDP_WINDOW_BASE + |
ACPI_PTR_DIFF(mem_rover, table_ptr)); |
*table_address = (acpi_physical_address) physical_address; |
return_ACPI_STATUS(AE_OK); |
} |
/* A valid RSDP was not found */ |
ACPI_BIOS_ERROR((AE_INFO, "A valid RSDP was not found")); |
return_ACPI_STATUS(AE_NOT_FOUND); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_tb_scan_memory_for_rsdp |
* |
* PARAMETERS: start_address - Starting pointer for search |
* length - Maximum length to search |
* |
* RETURN: Pointer to the RSDP if found, otherwise NULL. |
* |
* DESCRIPTION: Search a block of memory for the RSDP signature |
* |
******************************************************************************/ |
u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length) |
{ |
acpi_status status; |
u8 *mem_rover; |
u8 *end_address; |
ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp); |
end_address = start_address + length; |
/* Search from given start address for the requested length */ |
for (mem_rover = start_address; mem_rover < end_address; |
mem_rover += ACPI_RSDP_SCAN_STEP) { |
/* The RSDP signature and checksum must both be correct */ |
status = |
acpi_tb_validate_rsdp(ACPI_CAST_PTR |
(struct acpi_table_rsdp, mem_rover)); |
if (ACPI_SUCCESS(status)) { |
/* Sig and checksum valid, we have found a real RSDP */ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"RSDP located at physical address %p\n", |
mem_rover)); |
return_PTR(mem_rover); |
} |
/* No sig match or bad checksum, keep searching */ |
} |
/* Searched entire block, no RSDP was found */ |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Searched entire block from %p, valid RSDP was not found\n", |
start_address)); |
return_PTR(NULL); |
} |
/drivers/acpi/acpica/utaddress.c |
---|
0,0 → 1,297 |
/****************************************************************************** |
* |
* Module Name: utaddress - op_region address range check |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utaddress") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_add_address_range |
* |
* PARAMETERS: space_id - Address space ID |
* address - op_region start address |
* length - op_region length |
* region_node - op_region namespace node |
* |
* RETURN: Status |
* |
* DESCRIPTION: Add the Operation Region address range to the global list. |
* The only supported Space IDs are Memory and I/O. Called when |
* the op_region address/length operands are fully evaluated. |
* |
* MUTEX: Locks the namespace |
* |
* NOTE: Because this interface is only called when an op_region argument |
* list is evaluated, there cannot be any duplicate region_nodes. |
* Duplicate Address/Length values are allowed, however, so that multiple |
* address conflicts can be detected. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_add_address_range(acpi_adr_space_type space_id, |
acpi_physical_address address, |
u32 length, struct acpi_namespace_node *region_node) |
{ |
struct acpi_address_range *range_info; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_add_address_range); |
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && |
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Allocate/init a new info block, add it to the appropriate list */ |
range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range)); |
if (!range_info) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
range_info->start_address = address; |
range_info->end_address = (address + length - 1); |
range_info->region_node = region_node; |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
ACPI_FREE(range_info); |
return_ACPI_STATUS(status); |
} |
range_info->next = acpi_gbl_address_range_list[space_id]; |
acpi_gbl_address_range_list[space_id] = range_info; |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", |
acpi_ut_get_node_name(range_info->region_node), |
ACPI_FORMAT_UINT64(address), |
ACPI_FORMAT_UINT64(range_info->end_address))); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_remove_address_range |
* |
* PARAMETERS: space_id - Address space ID |
* region_node - op_region namespace node |
* |
* RETURN: None |
* |
* DESCRIPTION: Remove the Operation Region from the global list. The only |
* supported Space IDs are Memory and I/O. Called when an |
* op_region is deleted. |
* |
* MUTEX: Assumes the namespace is locked |
* |
******************************************************************************/ |
void |
acpi_ut_remove_address_range(acpi_adr_space_type space_id, |
struct acpi_namespace_node *region_node) |
{ |
struct acpi_address_range *range_info; |
struct acpi_address_range *prev; |
ACPI_FUNCTION_TRACE(ut_remove_address_range); |
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && |
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { |
return_VOID; |
} |
/* Get the appropriate list head and check the list */ |
range_info = prev = acpi_gbl_address_range_list[space_id]; |
while (range_info) { |
if (range_info->region_node == region_node) { |
if (range_info == prev) { /* Found at list head */ |
acpi_gbl_address_range_list[space_id] = |
range_info->next; |
} else { |
prev->next = range_info->next; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
"\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", |
acpi_ut_get_node_name(range_info-> |
region_node), |
ACPI_FORMAT_UINT64(range_info-> |
start_address), |
ACPI_FORMAT_UINT64(range_info-> |
end_address))); |
ACPI_FREE(range_info); |
return_VOID; |
} |
prev = range_info; |
range_info = range_info->next; |
} |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_check_address_range |
* |
* PARAMETERS: space_id - Address space ID |
* address - Start address |
* length - Length of address range |
* warn - TRUE if warning on overlap desired |
* |
* RETURN: Count of the number of conflicts detected. Zero is always |
* returned for Space IDs other than Memory or I/O. |
* |
* DESCRIPTION: Check if the input address range overlaps any of the |
* ASL operation region address ranges. The only supported |
* Space IDs are Memory and I/O. |
* |
* MUTEX: Assumes the namespace is locked. |
* |
******************************************************************************/ |
u32 |
acpi_ut_check_address_range(acpi_adr_space_type space_id, |
acpi_physical_address address, u32 length, u8 warn) |
{ |
struct acpi_address_range *range_info; |
acpi_physical_address end_address; |
char *pathname; |
u32 overlap_count = 0; |
ACPI_FUNCTION_TRACE(ut_check_address_range); |
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && |
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { |
return_UINT32(0); |
} |
range_info = acpi_gbl_address_range_list[space_id]; |
end_address = address + length - 1; |
/* Check entire list for all possible conflicts */ |
while (range_info) { |
/* |
* Check if the requested address/length overlaps this |
* address range. There are four cases to consider: |
* |
* 1) Input address/length is contained completely in the |
* address range |
* 2) Input address/length overlaps range at the range start |
* 3) Input address/length overlaps range at the range end |
* 4) Input address/length completely encompasses the range |
*/ |
if ((address <= range_info->end_address) && |
(end_address >= range_info->start_address)) { |
/* Found an address range overlap */ |
overlap_count++; |
if (warn) { /* Optional warning message */ |
pathname = |
acpi_ns_get_external_pathname(range_info-> |
region_node); |
ACPI_WARNING((AE_INFO, |
"%s range 0x%8.8X%8.8X-0x%8.8X%8.8X conflicts with OpRegion 0x%8.8X%8.8X-0x%8.8X%8.8X (%s)", |
acpi_ut_get_region_name(space_id), |
ACPI_FORMAT_UINT64(address), |
ACPI_FORMAT_UINT64(end_address), |
ACPI_FORMAT_UINT64(range_info-> |
start_address), |
ACPI_FORMAT_UINT64(range_info-> |
end_address), |
pathname)); |
ACPI_FREE(pathname); |
} |
} |
range_info = range_info->next; |
} |
return_UINT32(overlap_count); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_delete_address_lists |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Delete all global address range lists (called during |
* subsystem shutdown). |
* |
******************************************************************************/ |
void acpi_ut_delete_address_lists(void) |
{ |
struct acpi_address_range *next; |
struct acpi_address_range *range_info; |
int i; |
/* Delete all elements in all address range lists */ |
for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { |
next = acpi_gbl_address_range_list[i]; |
while (next) { |
range_info = next; |
next = range_info->next; |
ACPI_FREE(range_info); |
} |
acpi_gbl_address_range_list[i] = NULL; |
} |
} |
/drivers/acpi/acpica/utalloc.c |
---|
0,0 → 1,342 |
/****************************************************************************** |
* |
* Module Name: utalloc - local memory allocation routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utalloc") |
#if !defined (USE_NATIVE_ALLOCATE_ZEROED) |
/******************************************************************************* |
* |
* FUNCTION: acpi_os_allocate_zeroed |
* |
* PARAMETERS: size - Size of the allocation |
* |
* RETURN: Address of the allocated memory on success, NULL on failure. |
* |
* DESCRIPTION: Subsystem equivalent of calloc. Allocate and zero memory. |
* This is the default implementation. Can be overridden via the |
* USE_NATIVE_ALLOCATE_ZEROED flag. |
* |
******************************************************************************/ |
void *acpi_os_allocate_zeroed(acpi_size size) |
{ |
void *allocation; |
ACPI_FUNCTION_ENTRY(); |
allocation = acpi_os_allocate(size); |
if (allocation) { |
/* Clear the memory block */ |
memset(allocation, 0, size); |
} |
return (allocation); |
} |
#endif /* !USE_NATIVE_ALLOCATE_ZEROED */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_caches |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create all local caches |
* |
******************************************************************************/ |
acpi_status acpi_ut_create_caches(void) |
{ |
acpi_status status; |
/* Object Caches, for frequently used objects */ |
status = |
acpi_os_create_cache("Acpi-Namespace", |
sizeof(struct acpi_namespace_node), |
ACPI_MAX_NAMESPACE_CACHE_DEPTH, |
&acpi_gbl_namespace_cache); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = |
acpi_os_create_cache("Acpi-State", sizeof(union acpi_generic_state), |
ACPI_MAX_STATE_CACHE_DEPTH, |
&acpi_gbl_state_cache); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = |
acpi_os_create_cache("Acpi-Parse", |
sizeof(struct acpi_parse_obj_common), |
ACPI_MAX_PARSE_CACHE_DEPTH, |
&acpi_gbl_ps_node_cache); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = |
acpi_os_create_cache("Acpi-ParseExt", |
sizeof(struct acpi_parse_obj_named), |
ACPI_MAX_EXTPARSE_CACHE_DEPTH, |
&acpi_gbl_ps_node_ext_cache); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = |
acpi_os_create_cache("Acpi-Operand", |
sizeof(union acpi_operand_object), |
ACPI_MAX_OBJECT_CACHE_DEPTH, |
&acpi_gbl_operand_cache); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
/* Memory allocation lists */ |
status = acpi_ut_create_list("Acpi-Global", 0, &acpi_gbl_global_list); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = |
acpi_ut_create_list("Acpi-Namespace", |
sizeof(struct acpi_namespace_node), |
&acpi_gbl_ns_node_list); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
#endif |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_delete_caches |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Purge and delete all local caches |
* |
******************************************************************************/ |
acpi_status acpi_ut_delete_caches(void) |
{ |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
char buffer[7]; |
if (acpi_gbl_display_final_mem_stats) { |
strcpy(buffer, "MEMORY"); |
(void)acpi_db_display_statistics(buffer); |
} |
#endif |
(void)acpi_os_delete_cache(acpi_gbl_namespace_cache); |
acpi_gbl_namespace_cache = NULL; |
(void)acpi_os_delete_cache(acpi_gbl_state_cache); |
acpi_gbl_state_cache = NULL; |
(void)acpi_os_delete_cache(acpi_gbl_operand_cache); |
acpi_gbl_operand_cache = NULL; |
(void)acpi_os_delete_cache(acpi_gbl_ps_node_cache); |
acpi_gbl_ps_node_cache = NULL; |
(void)acpi_os_delete_cache(acpi_gbl_ps_node_ext_cache); |
acpi_gbl_ps_node_ext_cache = NULL; |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
/* Debug only - display leftover memory allocation, if any */ |
acpi_ut_dump_allocations(ACPI_UINT32_MAX, NULL); |
/* Free memory lists */ |
acpi_os_free(acpi_gbl_global_list); |
acpi_gbl_global_list = NULL; |
acpi_os_free(acpi_gbl_ns_node_list); |
acpi_gbl_ns_node_list = NULL; |
#endif |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_validate_buffer |
* |
* PARAMETERS: buffer - Buffer descriptor to be validated |
* |
* RETURN: Status |
* |
* DESCRIPTION: Perform parameter validation checks on an struct acpi_buffer |
* |
******************************************************************************/ |
acpi_status acpi_ut_validate_buffer(struct acpi_buffer * buffer) |
{ |
/* Obviously, the structure pointer must be valid */ |
if (!buffer) { |
return (AE_BAD_PARAMETER); |
} |
/* Special semantics for the length */ |
if ((buffer->length == ACPI_NO_BUFFER) || |
(buffer->length == ACPI_ALLOCATE_BUFFER) || |
(buffer->length == ACPI_ALLOCATE_LOCAL_BUFFER)) { |
return (AE_OK); |
} |
/* Length is valid, the buffer pointer must be also */ |
if (!buffer->pointer) { |
return (AE_BAD_PARAMETER); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_initialize_buffer |
* |
* PARAMETERS: buffer - Buffer to be validated |
* required_length - Length needed |
* |
* RETURN: Status |
* |
* DESCRIPTION: Validate that the buffer is of the required length or |
* allocate a new buffer. Returned buffer is always zeroed. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_initialize_buffer(struct acpi_buffer * buffer, |
acpi_size required_length) |
{ |
acpi_size input_buffer_length; |
/* Parameter validation */ |
if (!buffer || !required_length) { |
return (AE_BAD_PARAMETER); |
} |
/* |
* Buffer->Length is used as both an input and output parameter. Get the |
* input actual length and set the output required buffer length. |
*/ |
input_buffer_length = buffer->length; |
buffer->length = required_length; |
/* |
* The input buffer length contains the actual buffer length, or the type |
* of buffer to be allocated by this routine. |
*/ |
switch (input_buffer_length) { |
case ACPI_NO_BUFFER: |
/* Return the exception (and the required buffer length) */ |
return (AE_BUFFER_OVERFLOW); |
case ACPI_ALLOCATE_BUFFER: |
/* |
* Allocate a new buffer. We directectly call acpi_os_allocate here to |
* purposefully bypass the (optionally enabled) internal allocation |
* tracking mechanism since we only want to track internal |
* allocations. Note: The caller should use acpi_os_free to free this |
* buffer created via ACPI_ALLOCATE_BUFFER. |
*/ |
buffer->pointer = acpi_os_allocate(required_length); |
break; |
case ACPI_ALLOCATE_LOCAL_BUFFER: |
/* Allocate a new buffer with local interface to allow tracking */ |
buffer->pointer = ACPI_ALLOCATE(required_length); |
break; |
default: |
/* Existing buffer: Validate the size of the buffer */ |
if (input_buffer_length < required_length) { |
return (AE_BUFFER_OVERFLOW); |
} |
break; |
} |
/* Validate allocation from above or input buffer pointer */ |
if (!buffer->pointer) { |
return (AE_NO_MEMORY); |
} |
/* Have a valid buffer, clear it */ |
memset(buffer->pointer, 0, required_length); |
return (AE_OK); |
} |
/drivers/acpi/acpica/utbuffer.c |
---|
0,0 → 1,337 |
/****************************************************************************** |
* |
* Module Name: utbuffer - Buffer dump routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utbuffer") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_dump_buffer |
* |
* PARAMETERS: buffer - Buffer to dump |
* count - Amount to dump, in bytes |
* display - BYTE, WORD, DWORD, or QWORD display: |
* DB_BYTE_DISPLAY |
* DB_WORD_DISPLAY |
* DB_DWORD_DISPLAY |
* DB_QWORD_DISPLAY |
* base_offset - Beginning buffer offset (display only) |
* |
* RETURN: None |
* |
* DESCRIPTION: Generic dump buffer in both hex and ascii. |
* |
******************************************************************************/ |
void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset) |
{ |
u32 i = 0; |
u32 j; |
u32 temp32; |
u8 buf_char; |
if (!buffer) { |
acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n"); |
return; |
} |
if ((count < 4) || (count & 0x01)) { |
display = DB_BYTE_DISPLAY; |
} |
/* Nasty little dump buffer routine! */ |
while (i < count) { |
/* Print current offset */ |
acpi_os_printf("%6.4X: ", (base_offset + i)); |
/* Print 16 hex chars */ |
for (j = 0; j < 16;) { |
if (i + j >= count) { |
/* Dump fill spaces */ |
acpi_os_printf("%*s", ((display * 2) + 1), " "); |
j += display; |
continue; |
} |
switch (display) { |
case DB_BYTE_DISPLAY: |
default: /* Default is BYTE display */ |
acpi_os_printf("%02X ", |
buffer[(acpi_size) i + j]); |
break; |
case DB_WORD_DISPLAY: |
ACPI_MOVE_16_TO_32(&temp32, |
&buffer[(acpi_size) i + j]); |
acpi_os_printf("%04X ", temp32); |
break; |
case DB_DWORD_DISPLAY: |
ACPI_MOVE_32_TO_32(&temp32, |
&buffer[(acpi_size) i + j]); |
acpi_os_printf("%08X ", temp32); |
break; |
case DB_QWORD_DISPLAY: |
ACPI_MOVE_32_TO_32(&temp32, |
&buffer[(acpi_size) i + j]); |
acpi_os_printf("%08X", temp32); |
ACPI_MOVE_32_TO_32(&temp32, |
&buffer[(acpi_size) i + j + |
4]); |
acpi_os_printf("%08X ", temp32); |
break; |
} |
j += display; |
} |
/* |
* Print the ASCII equivalent characters but watch out for the bad |
* unprintable ones (printable chars are 0x20 through 0x7E) |
*/ |
acpi_os_printf(" "); |
for (j = 0; j < 16; j++) { |
if (i + j >= count) { |
acpi_os_printf("\n"); |
return; |
} |
/* |
* Add comment characters so rest of line is ignored when |
* compiled |
*/ |
if (j == 0) { |
acpi_os_printf("// "); |
} |
buf_char = buffer[(acpi_size) i + j]; |
if (isprint(buf_char)) { |
acpi_os_printf("%c", buf_char); |
} else { |
acpi_os_printf("."); |
} |
} |
/* Done with that line. */ |
acpi_os_printf("\n"); |
i += 16; |
} |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_debug_dump_buffer |
* |
* PARAMETERS: buffer - Buffer to dump |
* count - Amount to dump, in bytes |
* display - BYTE, WORD, DWORD, or QWORD display: |
* DB_BYTE_DISPLAY |
* DB_WORD_DISPLAY |
* DB_DWORD_DISPLAY |
* DB_QWORD_DISPLAY |
* component_ID - Caller's component ID |
* |
* RETURN: None |
* |
* DESCRIPTION: Generic dump buffer in both hex and ascii. |
* |
******************************************************************************/ |
void |
acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id) |
{ |
/* Only dump the buffer if tracing is enabled */ |
if (!((ACPI_LV_TABLES & acpi_dbg_level) && |
(component_id & acpi_dbg_layer))) { |
return; |
} |
acpi_ut_dump_buffer(buffer, count, display, 0); |
} |
#ifdef ACPI_APPLICATION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_dump_buffer_to_file |
* |
* PARAMETERS: file - File descriptor |
* buffer - Buffer to dump |
* count - Amount to dump, in bytes |
* display - BYTE, WORD, DWORD, or QWORD display: |
* DB_BYTE_DISPLAY |
* DB_WORD_DISPLAY |
* DB_DWORD_DISPLAY |
* DB_QWORD_DISPLAY |
* base_offset - Beginning buffer offset (display only) |
* |
* RETURN: None |
* |
* DESCRIPTION: Generic dump buffer in both hex and ascii to a file. |
* |
******************************************************************************/ |
void |
acpi_ut_dump_buffer_to_file(ACPI_FILE file, |
u8 *buffer, u32 count, u32 display, u32 base_offset) |
{ |
u32 i = 0; |
u32 j; |
u32 temp32; |
u8 buf_char; |
if (!buffer) { |
acpi_ut_file_printf(file, |
"Null Buffer Pointer in DumpBuffer!\n"); |
return; |
} |
if ((count < 4) || (count & 0x01)) { |
display = DB_BYTE_DISPLAY; |
} |
/* Nasty little dump buffer routine! */ |
while (i < count) { |
/* Print current offset */ |
acpi_ut_file_printf(file, "%6.4X: ", (base_offset + i)); |
/* Print 16 hex chars */ |
for (j = 0; j < 16;) { |
if (i + j >= count) { |
/* Dump fill spaces */ |
acpi_ut_file_printf(file, "%*s", |
((display * 2) + 1), " "); |
j += display; |
continue; |
} |
switch (display) { |
case DB_BYTE_DISPLAY: |
default: /* Default is BYTE display */ |
acpi_ut_file_printf(file, "%02X ", |
buffer[(acpi_size) i + j]); |
break; |
case DB_WORD_DISPLAY: |
ACPI_MOVE_16_TO_32(&temp32, |
&buffer[(acpi_size) i + j]); |
acpi_ut_file_printf(file, "%04X ", temp32); |
break; |
case DB_DWORD_DISPLAY: |
ACPI_MOVE_32_TO_32(&temp32, |
&buffer[(acpi_size) i + j]); |
acpi_ut_file_printf(file, "%08X ", temp32); |
break; |
case DB_QWORD_DISPLAY: |
ACPI_MOVE_32_TO_32(&temp32, |
&buffer[(acpi_size) i + j]); |
acpi_ut_file_printf(file, "%08X", temp32); |
ACPI_MOVE_32_TO_32(&temp32, |
&buffer[(acpi_size) i + j + |
4]); |
acpi_ut_file_printf(file, "%08X ", temp32); |
break; |
} |
j += display; |
} |
/* |
* Print the ASCII equivalent characters but watch out for the bad |
* unprintable ones (printable chars are 0x20 through 0x7E) |
*/ |
acpi_ut_file_printf(file, " "); |
for (j = 0; j < 16; j++) { |
if (i + j >= count) { |
acpi_ut_file_printf(file, "\n"); |
return; |
} |
buf_char = buffer[(acpi_size) i + j]; |
if (isprint(buf_char)) { |
acpi_ut_file_printf(file, "%c", buf_char); |
} else { |
acpi_ut_file_printf(file, "."); |
} |
} |
/* Done with that line. */ |
acpi_ut_file_printf(file, "\n"); |
i += 16; |
} |
return; |
} |
#endif |
/drivers/acpi/acpica/utcache.c |
---|
0,0 → 1,313 |
/****************************************************************************** |
* |
* Module Name: utcache - local cache allocation routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utcache") |
#ifdef ACPI_USE_LOCAL_CACHE |
/******************************************************************************* |
* |
* FUNCTION: acpi_os_create_cache |
* |
* PARAMETERS: cache_name - Ascii name for the cache |
* object_size - Size of each cached object |
* max_depth - Maximum depth of the cache (in objects) |
* return_cache - Where the new cache object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a cache object |
* |
******************************************************************************/ |
acpi_status |
acpi_os_create_cache(char *cache_name, |
u16 object_size, |
u16 max_depth, struct acpi_memory_list **return_cache) |
{ |
struct acpi_memory_list *cache; |
ACPI_FUNCTION_ENTRY(); |
if (!cache_name || !return_cache || (object_size < 16)) { |
return (AE_BAD_PARAMETER); |
} |
/* Create the cache object */ |
cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); |
if (!cache) { |
return (AE_NO_MEMORY); |
} |
/* Populate the cache object and return it */ |
memset(cache, 0, sizeof(struct acpi_memory_list)); |
cache->list_name = cache_name; |
cache->object_size = object_size; |
cache->max_depth = max_depth; |
*return_cache = cache; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_os_purge_cache |
* |
* PARAMETERS: cache - Handle to cache object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Free all objects within the requested cache. |
* |
******************************************************************************/ |
acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) |
{ |
void *next; |
acpi_status status; |
ACPI_FUNCTION_ENTRY(); |
if (!cache) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Walk the list of objects in this cache */ |
while (cache->list_head) { |
/* Delete and unlink one cached state object */ |
next = ACPI_GET_DESCRIPTOR_PTR(cache->list_head); |
ACPI_FREE(cache->list_head); |
cache->list_head = next; |
cache->current_depth--; |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_CACHES); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_os_delete_cache |
* |
* PARAMETERS: cache - Handle to cache object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Free all objects within the requested cache and delete the |
* cache object. |
* |
******************************************************************************/ |
acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) |
{ |
acpi_status status; |
ACPI_FUNCTION_ENTRY(); |
/* Purge all objects in the cache */ |
status = acpi_os_purge_cache(cache); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Now we can delete the cache object */ |
acpi_os_free(cache); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_os_release_object |
* |
* PARAMETERS: cache - Handle to cache object |
* object - The object to be released |
* |
* RETURN: None |
* |
* DESCRIPTION: Release an object to the specified cache. If cache is full, |
* the object is deleted. |
* |
******************************************************************************/ |
acpi_status |
acpi_os_release_object(struct acpi_memory_list * cache, void *object) |
{ |
acpi_status status; |
ACPI_FUNCTION_ENTRY(); |
if (!cache || !object) { |
return (AE_BAD_PARAMETER); |
} |
/* If cache is full, just free this object */ |
if (cache->current_depth >= cache->max_depth) { |
ACPI_FREE(object); |
ACPI_MEM_TRACKING(cache->total_freed++); |
} |
/* Otherwise put this object back into the cache */ |
else { |
status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Mark the object as cached */ |
memset(object, 0xCA, cache->object_size); |
ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); |
/* Put the object at the head of the cache list */ |
ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head); |
cache->list_head = object; |
cache->current_depth++; |
(void)acpi_ut_release_mutex(ACPI_MTX_CACHES); |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_os_acquire_object |
* |
* PARAMETERS: cache - Handle to cache object |
* |
* RETURN: the acquired object. NULL on error |
* |
* DESCRIPTION: Get an object from the specified cache. If cache is empty, |
* the object is allocated. |
* |
******************************************************************************/ |
void *acpi_os_acquire_object(struct acpi_memory_list *cache) |
{ |
acpi_status status; |
void *object; |
ACPI_FUNCTION_NAME(os_acquire_object); |
if (!cache) { |
return_PTR(NULL); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); |
if (ACPI_FAILURE(status)) { |
return_PTR(NULL); |
} |
ACPI_MEM_TRACKING(cache->requests++); |
/* Check the cache first */ |
if (cache->list_head) { |
/* There is an object available, use it */ |
object = cache->list_head; |
cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object); |
cache->current_depth--; |
ACPI_MEM_TRACKING(cache->hits++); |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Object %p from %s cache\n", object, |
cache->list_name)); |
status = acpi_ut_release_mutex(ACPI_MTX_CACHES); |
if (ACPI_FAILURE(status)) { |
return_PTR(NULL); |
} |
/* Clear (zero) the previously used Object */ |
memset(object, 0, cache->object_size); |
} else { |
/* The cache is empty, create a new object */ |
ACPI_MEM_TRACKING(cache->total_allocated++); |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
if ((cache->total_allocated - cache->total_freed) > |
cache->max_occupied) { |
cache->max_occupied = |
cache->total_allocated - cache->total_freed; |
} |
#endif |
/* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ |
status = acpi_ut_release_mutex(ACPI_MTX_CACHES); |
if (ACPI_FAILURE(status)) { |
return_PTR(NULL); |
} |
object = ACPI_ALLOCATE_ZEROED(cache->object_size); |
if (!object) { |
return_PTR(NULL); |
} |
} |
return_PTR(object); |
} |
#endif /* ACPI_USE_LOCAL_CACHE */ |
/drivers/acpi/acpica/utcopy.c |
---|
0,0 → 1,1011 |
/****************************************************************************** |
* |
* Module Name: utcopy - Internal to external object translation utilities |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utcopy") |
/* Local prototypes */ |
static acpi_status |
acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, |
union acpi_object *external_object, |
u8 * data_space, acpi_size * buffer_space_used); |
static acpi_status |
acpi_ut_copy_ielement_to_ielement(u8 object_type, |
union acpi_operand_object *source_object, |
union acpi_generic_state *state, |
void *context); |
static acpi_status |
acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object, |
u8 * buffer, acpi_size * space_used); |
static acpi_status |
acpi_ut_copy_esimple_to_isimple(union acpi_object *user_obj, |
union acpi_operand_object **return_obj); |
static acpi_status |
acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, |
union acpi_operand_object **internal_object); |
static acpi_status |
acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, |
union acpi_operand_object *dest_desc); |
static acpi_status |
acpi_ut_copy_ielement_to_eelement(u8 object_type, |
union acpi_operand_object *source_object, |
union acpi_generic_state *state, |
void *context); |
static acpi_status |
acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, |
union acpi_operand_object *dest_obj, |
struct acpi_walk_state *walk_state); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_isimple_to_esimple |
* |
* PARAMETERS: internal_object - Source object to be copied |
* external_object - Where to return the copied object |
* data_space - Where object data is returned (such as |
* buffer and string data) |
* buffer_space_used - Length of data_space that was used |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to copy a simple internal object to |
* an external object. |
* |
* The data_space buffer is assumed to have sufficient space for |
* the object. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, |
union acpi_object *external_object, |
u8 * data_space, acpi_size * buffer_space_used) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ut_copy_isimple_to_esimple); |
*buffer_space_used = 0; |
/* |
* Check for NULL object case (could be an uninitialized |
* package element) |
*/ |
if (!internal_object) { |
return_ACPI_STATUS(AE_OK); |
} |
/* Always clear the external object */ |
memset(external_object, 0, sizeof(union acpi_object)); |
/* |
* In general, the external object will be the same type as |
* the internal object |
*/ |
external_object->type = internal_object->common.type; |
/* However, only a limited number of external types are supported */ |
switch (internal_object->common.type) { |
case ACPI_TYPE_STRING: |
external_object->string.pointer = (char *)data_space; |
external_object->string.length = internal_object->string.length; |
*buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD((acpi_size) |
internal_object-> |
string. |
length + 1); |
memcpy((void *)data_space, |
(void *)internal_object->string.pointer, |
(acpi_size) internal_object->string.length + 1); |
break; |
case ACPI_TYPE_BUFFER: |
external_object->buffer.pointer = data_space; |
external_object->buffer.length = internal_object->buffer.length; |
*buffer_space_used = |
ACPI_ROUND_UP_TO_NATIVE_WORD(internal_object->string. |
length); |
memcpy((void *)data_space, |
(void *)internal_object->buffer.pointer, |
internal_object->buffer.length); |
break; |
case ACPI_TYPE_INTEGER: |
external_object->integer.value = internal_object->integer.value; |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
/* This is an object reference. */ |
switch (internal_object->reference.class) { |
case ACPI_REFCLASS_NAME: |
/* |
* For namepath, return the object handle ("reference") |
* We are referring to the namespace node |
*/ |
external_object->reference.handle = |
internal_object->reference.node; |
external_object->reference.actual_type = |
acpi_ns_get_type(internal_object->reference.node); |
break; |
default: |
/* All other reference types are unsupported */ |
return_ACPI_STATUS(AE_TYPE); |
} |
break; |
case ACPI_TYPE_PROCESSOR: |
external_object->processor.proc_id = |
internal_object->processor.proc_id; |
external_object->processor.pblk_address = |
internal_object->processor.address; |
external_object->processor.pblk_length = |
internal_object->processor.length; |
break; |
case ACPI_TYPE_POWER: |
external_object->power_resource.system_level = |
internal_object->power_resource.system_level; |
external_object->power_resource.resource_order = |
internal_object->power_resource.resource_order; |
break; |
default: |
/* |
* There is no corresponding external object type |
*/ |
ACPI_ERROR((AE_INFO, |
"Unsupported object type, cannot convert to external object: %s", |
acpi_ut_get_type_name(internal_object->common. |
type))); |
return_ACPI_STATUS(AE_SUPPORT); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_ielement_to_eelement |
* |
* PARAMETERS: acpi_pkg_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Copy one package element to another package element |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_ielement_to_eelement(u8 object_type, |
union acpi_operand_object *source_object, |
union acpi_generic_state *state, |
void *context) |
{ |
acpi_status status = AE_OK; |
struct acpi_pkg_info *info = (struct acpi_pkg_info *)context; |
acpi_size object_space; |
u32 this_index; |
union acpi_object *target_object; |
ACPI_FUNCTION_ENTRY(); |
this_index = state->pkg.index; |
target_object = (union acpi_object *) |
&((union acpi_object *)(state->pkg.dest_object))->package. |
elements[this_index]; |
switch (object_type) { |
case ACPI_COPY_TYPE_SIMPLE: |
/* |
* This is a simple or null object |
*/ |
status = acpi_ut_copy_isimple_to_esimple(source_object, |
target_object, |
info->free_space, |
&object_space); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
case ACPI_COPY_TYPE_PACKAGE: |
/* |
* Build the package object |
*/ |
target_object->type = ACPI_TYPE_PACKAGE; |
target_object->package.count = source_object->package.count; |
target_object->package.elements = |
ACPI_CAST_PTR(union acpi_object, info->free_space); |
/* |
* Pass the new package object back to the package walk routine |
*/ |
state->pkg.this_target_obj = target_object; |
/* |
* Save space for the array of objects (Package elements) |
* update the buffer length counter |
*/ |
object_space = ACPI_ROUND_UP_TO_NATIVE_WORD((acpi_size) |
target_object-> |
package.count * |
sizeof(union |
acpi_object)); |
break; |
default: |
return (AE_BAD_PARAMETER); |
} |
info->free_space += object_space; |
info->length += object_space; |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_ipackage_to_epackage |
* |
* PARAMETERS: internal_object - Pointer to the object we are returning |
* buffer - Where the object is returned |
* space_used - Where the object length is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to place a package object in a user |
* buffer. A package object by definition contains other objects. |
* |
* The buffer is assumed to have sufficient space for the object. |
* The caller must have verified the buffer length needed using |
* the acpi_ut_get_object_size function before calling this function. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object, |
u8 * buffer, acpi_size * space_used) |
{ |
union acpi_object *external_object; |
acpi_status status; |
struct acpi_pkg_info info; |
ACPI_FUNCTION_TRACE(ut_copy_ipackage_to_epackage); |
/* |
* First package at head of the buffer |
*/ |
external_object = ACPI_CAST_PTR(union acpi_object, buffer); |
/* |
* Free space begins right after the first package |
*/ |
info.length = ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)); |
info.free_space = |
buffer + ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)); |
info.object_space = 0; |
info.num_packages = 1; |
external_object->type = internal_object->common.type; |
external_object->package.count = internal_object->package.count; |
external_object->package.elements = ACPI_CAST_PTR(union acpi_object, |
info.free_space); |
/* |
* Leave room for an array of ACPI_OBJECTS in the buffer |
* and move the free space past it |
*/ |
info.length += (acpi_size) external_object->package.count * |
ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)); |
info.free_space += external_object->package.count * |
ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)); |
status = acpi_ut_walk_package_tree(internal_object, external_object, |
acpi_ut_copy_ielement_to_eelement, |
&info); |
*space_used = info.length; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_iobject_to_eobject |
* |
* PARAMETERS: internal_object - The internal object to be converted |
* ret_buffer - Where the object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to build an API object to be returned |
* to the caller. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *internal_object, |
struct acpi_buffer *ret_buffer) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_copy_iobject_to_eobject); |
if (internal_object->common.type == ACPI_TYPE_PACKAGE) { |
/* |
* Package object: Copy all subobjects (including |
* nested packages) |
*/ |
status = acpi_ut_copy_ipackage_to_epackage(internal_object, |
ret_buffer->pointer, |
&ret_buffer->length); |
} else { |
/* |
* Build a simple object (no nested objects) |
*/ |
status = acpi_ut_copy_isimple_to_esimple(internal_object, |
ACPI_CAST_PTR(union |
acpi_object, |
ret_buffer-> |
pointer), |
ACPI_ADD_PTR(u8, |
ret_buffer-> |
pointer, |
ACPI_ROUND_UP_TO_NATIVE_WORD |
(sizeof |
(union |
acpi_object))), |
&ret_buffer->length); |
/* |
* build simple does not include the object size in the length |
* so we add it in here |
*/ |
ret_buffer->length += sizeof(union acpi_object); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_esimple_to_isimple |
* |
* PARAMETERS: external_object - The external object to be converted |
* ret_internal_object - Where the internal object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function copies an external object to an internal one. |
* NOTE: Pointers can be copied, we don't need to copy data. |
* (The pointers have to be valid in our address space no matter |
* what we do with them!) |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, |
union acpi_operand_object **ret_internal_object) |
{ |
union acpi_operand_object *internal_object; |
ACPI_FUNCTION_TRACE(ut_copy_esimple_to_isimple); |
/* |
* Simple types supported are: String, Buffer, Integer |
*/ |
switch (external_object->type) { |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_LOCAL_REFERENCE: |
internal_object = acpi_ut_create_internal_object((u8) |
external_object-> |
type); |
if (!internal_object) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
break; |
case ACPI_TYPE_ANY: /* This is the case for a NULL object */ |
*ret_internal_object = NULL; |
return_ACPI_STATUS(AE_OK); |
default: |
/* All other types are not supported */ |
ACPI_ERROR((AE_INFO, |
"Unsupported object type, cannot convert to internal object: %s", |
acpi_ut_get_type_name(external_object->type))); |
return_ACPI_STATUS(AE_SUPPORT); |
} |
/* Must COPY string and buffer contents */ |
switch (external_object->type) { |
case ACPI_TYPE_STRING: |
internal_object->string.pointer = |
ACPI_ALLOCATE_ZEROED((acpi_size) |
external_object->string.length + 1); |
if (!internal_object->string.pointer) { |
goto error_exit; |
} |
memcpy(internal_object->string.pointer, |
external_object->string.pointer, |
external_object->string.length); |
internal_object->string.length = external_object->string.length; |
break; |
case ACPI_TYPE_BUFFER: |
internal_object->buffer.pointer = |
ACPI_ALLOCATE_ZEROED(external_object->buffer.length); |
if (!internal_object->buffer.pointer) { |
goto error_exit; |
} |
memcpy(internal_object->buffer.pointer, |
external_object->buffer.pointer, |
external_object->buffer.length); |
internal_object->buffer.length = external_object->buffer.length; |
/* Mark buffer data valid */ |
internal_object->buffer.flags |= AOPOBJ_DATA_VALID; |
break; |
case ACPI_TYPE_INTEGER: |
internal_object->integer.value = external_object->integer.value; |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
/* An incoming reference is defined to be a namespace node */ |
internal_object->reference.class = ACPI_REFCLASS_REFOF; |
internal_object->reference.object = |
external_object->reference.handle; |
break; |
default: |
/* Other types can't get here */ |
break; |
} |
*ret_internal_object = internal_object; |
return_ACPI_STATUS(AE_OK); |
error_exit: |
acpi_ut_remove_reference(internal_object); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_epackage_to_ipackage |
* |
* PARAMETERS: external_object - The external object to be converted |
* internal_object - Where the internal object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Copy an external package object to an internal package. |
* Handles nested packages. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, |
union acpi_operand_object **internal_object) |
{ |
acpi_status status = AE_OK; |
union acpi_operand_object *package_object; |
union acpi_operand_object **package_elements; |
u32 i; |
ACPI_FUNCTION_TRACE(ut_copy_epackage_to_ipackage); |
/* Create the package object */ |
package_object = |
acpi_ut_create_package_object(external_object->package.count); |
if (!package_object) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
package_elements = package_object->package.elements; |
/* |
* Recursive implementation. Probably ok, since nested external packages |
* as parameters should be very rare. |
*/ |
for (i = 0; i < external_object->package.count; i++) { |
status = |
acpi_ut_copy_eobject_to_iobject(&external_object->package. |
elements[i], |
&package_elements[i]); |
if (ACPI_FAILURE(status)) { |
/* Truncate package and delete it */ |
package_object->package.count = i; |
package_elements[i] = NULL; |
acpi_ut_remove_reference(package_object); |
return_ACPI_STATUS(status); |
} |
} |
/* Mark package data valid */ |
package_object->package.flags |= AOPOBJ_DATA_VALID; |
*internal_object = package_object; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_eobject_to_iobject |
* |
* PARAMETERS: external_object - The external object to be converted |
* internal_object - Where the internal object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Converts an external object to an internal object. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object, |
union acpi_operand_object **internal_object) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_copy_eobject_to_iobject); |
if (external_object->type == ACPI_TYPE_PACKAGE) { |
status = |
acpi_ut_copy_epackage_to_ipackage(external_object, |
internal_object); |
} else { |
/* |
* Build a simple object (no nested objects) |
*/ |
status = |
acpi_ut_copy_esimple_to_isimple(external_object, |
internal_object); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_simple_object |
* |
* PARAMETERS: source_desc - The internal object to be copied |
* dest_desc - New target object |
* |
* RETURN: Status |
* |
* DESCRIPTION: Simple copy of one internal object to another. Reference count |
* of the destination object is preserved. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, |
union acpi_operand_object *dest_desc) |
{ |
u16 reference_count; |
union acpi_operand_object *next_object; |
acpi_status status; |
acpi_size copy_size; |
/* Save fields from destination that we don't want to overwrite */ |
reference_count = dest_desc->common.reference_count; |
next_object = dest_desc->common.next_object; |
/* |
* Copy the entire source object over the destination object. |
* Note: Source can be either an operand object or namespace node. |
*/ |
copy_size = sizeof(union acpi_operand_object); |
if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_NAMED) { |
copy_size = sizeof(struct acpi_namespace_node); |
} |
memcpy(ACPI_CAST_PTR(char, dest_desc), |
ACPI_CAST_PTR(char, source_desc), copy_size); |
/* Restore the saved fields */ |
dest_desc->common.reference_count = reference_count; |
dest_desc->common.next_object = next_object; |
/* New object is not static, regardless of source */ |
dest_desc->common.flags &= ~AOPOBJ_STATIC_POINTER; |
/* Handle the objects with extra data */ |
switch (dest_desc->common.type) { |
case ACPI_TYPE_BUFFER: |
/* |
* Allocate and copy the actual buffer if and only if: |
* 1) There is a valid buffer pointer |
* 2) The buffer has a length > 0 |
*/ |
if ((source_desc->buffer.pointer) && |
(source_desc->buffer.length)) { |
dest_desc->buffer.pointer = |
ACPI_ALLOCATE(source_desc->buffer.length); |
if (!dest_desc->buffer.pointer) { |
return (AE_NO_MEMORY); |
} |
/* Copy the actual buffer data */ |
memcpy(dest_desc->buffer.pointer, |
source_desc->buffer.pointer, |
source_desc->buffer.length); |
} |
break; |
case ACPI_TYPE_STRING: |
/* |
* Allocate and copy the actual string if and only if: |
* 1) There is a valid string pointer |
* (Pointer to a NULL string is allowed) |
*/ |
if (source_desc->string.pointer) { |
dest_desc->string.pointer = |
ACPI_ALLOCATE((acpi_size) source_desc->string. |
length + 1); |
if (!dest_desc->string.pointer) { |
return (AE_NO_MEMORY); |
} |
/* Copy the actual string data */ |
memcpy(dest_desc->string.pointer, |
source_desc->string.pointer, |
(acpi_size) source_desc->string.length + 1); |
} |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
/* |
* We copied the reference object, so we now must add a reference |
* to the object pointed to by the reference |
* |
* DDBHandle reference (from Load/load_table) is a special reference, |
* it does not have a Reference.Object, so does not need to |
* increase the reference count |
*/ |
if (source_desc->reference.class == ACPI_REFCLASS_TABLE) { |
break; |
} |
acpi_ut_add_reference(source_desc->reference.object); |
break; |
case ACPI_TYPE_REGION: |
/* |
* We copied the Region Handler, so we now must add a reference |
*/ |
if (dest_desc->region.handler) { |
acpi_ut_add_reference(dest_desc->region.handler); |
} |
break; |
/* |
* For Mutex and Event objects, we cannot simply copy the underlying |
* OS object. We must create a new one. |
*/ |
case ACPI_TYPE_MUTEX: |
status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
case ACPI_TYPE_EVENT: |
status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, |
&dest_desc->event. |
os_semaphore); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
break; |
default: |
/* Nothing to do for other simple objects */ |
break; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_ielement_to_ielement |
* |
* PARAMETERS: acpi_pkg_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Copy one package element to another package element |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_ielement_to_ielement(u8 object_type, |
union acpi_operand_object *source_object, |
union acpi_generic_state *state, |
void *context) |
{ |
acpi_status status = AE_OK; |
u32 this_index; |
union acpi_operand_object **this_target_ptr; |
union acpi_operand_object *target_object; |
ACPI_FUNCTION_ENTRY(); |
this_index = state->pkg.index; |
this_target_ptr = (union acpi_operand_object **) |
&state->pkg.dest_object->package.elements[this_index]; |
switch (object_type) { |
case ACPI_COPY_TYPE_SIMPLE: |
/* A null source object indicates a (legal) null package element */ |
if (source_object) { |
/* |
* This is a simple object, just copy it |
*/ |
target_object = |
acpi_ut_create_internal_object(source_object-> |
common.type); |
if (!target_object) { |
return (AE_NO_MEMORY); |
} |
status = |
acpi_ut_copy_simple_object(source_object, |
target_object); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
*this_target_ptr = target_object; |
} else { |
/* Pass through a null element */ |
*this_target_ptr = NULL; |
} |
break; |
case ACPI_COPY_TYPE_PACKAGE: |
/* |
* This object is a package - go down another nesting level |
* Create and build the package object |
*/ |
target_object = |
acpi_ut_create_package_object(source_object->package.count); |
if (!target_object) { |
return (AE_NO_MEMORY); |
} |
target_object->common.flags = source_object->common.flags; |
/* Pass the new package object back to the package walk routine */ |
state->pkg.this_target_obj = target_object; |
/* Store the object pointer in the parent package object */ |
*this_target_ptr = target_object; |
break; |
default: |
return (AE_BAD_PARAMETER); |
} |
return (status); |
error_exit: |
acpi_ut_remove_reference(target_object); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_ipackage_to_ipackage |
* |
* PARAMETERS: source_obj - Pointer to the source package object |
* dest_obj - Where the internal object is returned |
* walk_state - Current Walk state descriptor |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to copy an internal package object |
* into another internal package object. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, |
union acpi_operand_object *dest_obj, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ut_copy_ipackage_to_ipackage); |
dest_obj->common.type = source_obj->common.type; |
dest_obj->common.flags = source_obj->common.flags; |
dest_obj->package.count = source_obj->package.count; |
/* |
* Create the object array and walk the source package tree |
*/ |
dest_obj->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) |
source_obj->package. |
count + |
1) * sizeof(void *)); |
if (!dest_obj->package.elements) { |
ACPI_ERROR((AE_INFO, "Package allocation failure")); |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* |
* Copy the package element-by-element by walking the package "tree". |
* This handles nested packages of arbitrary depth. |
*/ |
status = acpi_ut_walk_package_tree(source_obj, dest_obj, |
acpi_ut_copy_ielement_to_ielement, |
walk_state); |
if (ACPI_FAILURE(status)) { |
/* On failure, delete the destination package object */ |
acpi_ut_remove_reference(dest_obj); |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_copy_iobject_to_iobject |
* |
* PARAMETERS: source_desc - The internal object to be copied |
* dest_desc - Where the copied object is returned |
* walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Copy an internal object to a new internal object |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc, |
union acpi_operand_object **dest_desc, |
struct acpi_walk_state *walk_state) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(ut_copy_iobject_to_iobject); |
/* Create the top level object */ |
*dest_desc = acpi_ut_create_internal_object(source_desc->common.type); |
if (!*dest_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Copy the object and possible subobjects */ |
if (source_desc->common.type == ACPI_TYPE_PACKAGE) { |
status = |
acpi_ut_copy_ipackage_to_ipackage(source_desc, *dest_desc, |
walk_state); |
} else { |
status = acpi_ut_copy_simple_object(source_desc, *dest_desc); |
} |
/* Delete the allocated object if copy failed */ |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(*dest_desc); |
} |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/utdebug.c |
---|
0,0 → 1,618 |
/****************************************************************************** |
* |
* Module Name: utdebug - Debug print/trace routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utdebug") |
#ifdef ACPI_DEBUG_OUTPUT |
static acpi_thread_id acpi_gbl_prev_thread_id = (acpi_thread_id) 0xFFFFFFFF; |
static char *acpi_gbl_fn_entry_str = "----Entry"; |
static char *acpi_gbl_fn_exit_str = "----Exit-"; |
/* Local prototypes */ |
static const char *acpi_ut_trim_function_name(const char *function_name); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_init_stack_ptr_trace |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Save the current CPU stack pointer at subsystem startup |
* |
******************************************************************************/ |
void acpi_ut_init_stack_ptr_trace(void) |
{ |
acpi_size current_sp; |
acpi_gbl_entry_stack_pointer = ¤t_sp; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_track_stack_ptr |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Save the current CPU stack pointer |
* |
******************************************************************************/ |
void acpi_ut_track_stack_ptr(void) |
{ |
acpi_size current_sp; |
if (¤t_sp < acpi_gbl_lowest_stack_pointer) { |
acpi_gbl_lowest_stack_pointer = ¤t_sp; |
} |
if (acpi_gbl_nesting_level > acpi_gbl_deepest_nesting) { |
acpi_gbl_deepest_nesting = acpi_gbl_nesting_level; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_trim_function_name |
* |
* PARAMETERS: function_name - Ascii string containing a procedure name |
* |
* RETURN: Updated pointer to the function name |
* |
* DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. |
* This allows compiler macros such as __func__ to be used |
* with no change to the debug output. |
* |
******************************************************************************/ |
static const char *acpi_ut_trim_function_name(const char *function_name) |
{ |
/* All Function names are longer than 4 chars, check is safe */ |
if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_MIXED) { |
/* This is the case where the original source has not been modified */ |
return (function_name + 4); |
} |
if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_LOWER) { |
/* This is the case where the source has been 'linuxized' */ |
return (function_name + 5); |
} |
return (function_name); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_debug_print |
* |
* PARAMETERS: requested_debug_level - Requested debug print level |
* line_number - Caller's line number (for error output) |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* format - Printf format field |
* ... - Optional printf arguments |
* |
* RETURN: None |
* |
* DESCRIPTION: Print error message with prefix consisting of the module name, |
* line number, and component ID. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_debug_print(u32 requested_debug_level, |
u32 line_number, |
const char *function_name, |
const char *module_name, |
u32 component_id, const char *format, ...) |
{ |
acpi_thread_id thread_id; |
va_list args; |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(requested_debug_level, component_id)) { |
return; |
} |
/* |
* Thread tracking and context switch notification |
*/ |
thread_id = acpi_os_get_thread_id(); |
if (thread_id != acpi_gbl_prev_thread_id) { |
if (ACPI_LV_THREADS & acpi_dbg_level) { |
acpi_os_printf |
("\n**** Context Switch from TID %u to TID %u ****\n\n", |
(u32)acpi_gbl_prev_thread_id, (u32)thread_id); |
} |
acpi_gbl_prev_thread_id = thread_id; |
acpi_gbl_nesting_level = 0; |
} |
/* |
* Display the module name, current line number, thread ID (if requested), |
* current procedure nesting level, and the current procedure name |
*/ |
acpi_os_printf("%9s-%04ld ", module_name, line_number); |
#ifdef ACPI_APPLICATION |
/* |
* For acpi_exec/iASL only, emit the thread ID and nesting level. |
* Note: nesting level is really only useful during a single-thread |
* execution. Otherwise, multiple threads will keep resetting the |
* level. |
*/ |
if (ACPI_LV_THREADS & acpi_dbg_level) { |
acpi_os_printf("[%u] ", (u32)thread_id); |
} |
acpi_os_printf("[%02ld] ", acpi_gbl_nesting_level); |
#endif |
acpi_os_printf("%-22.22s: ", acpi_ut_trim_function_name(function_name)); |
va_start(args, format); |
acpi_os_vprintf(format, args); |
va_end(args); |
} |
ACPI_EXPORT_SYMBOL(acpi_debug_print) |
/******************************************************************************* |
* |
* FUNCTION: acpi_debug_print_raw |
* |
* PARAMETERS: requested_debug_level - Requested debug print level |
* line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* format - Printf format field |
* ... - Optional printf arguments |
* |
* RETURN: None |
* |
* DESCRIPTION: Print message with no headers. Has same interface as |
* debug_print so that the same macros can be used. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_debug_print_raw(u32 requested_debug_level, |
u32 line_number, |
const char *function_name, |
const char *module_name, |
u32 component_id, const char *format, ...) |
{ |
va_list args; |
/* Check if debug output enabled */ |
if (!ACPI_IS_DEBUG_ENABLED(requested_debug_level, component_id)) { |
return; |
} |
va_start(args, format); |
acpi_os_vprintf(format, args); |
va_end(args); |
} |
ACPI_EXPORT_SYMBOL(acpi_debug_print_raw) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_trace |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* |
* RETURN: None |
* |
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level |
* |
******************************************************************************/ |
void |
acpi_ut_trace(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id) |
{ |
acpi_gbl_nesting_level++; |
acpi_ut_track_stack_ptr(); |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, module_name, |
component_id, "%s\n", acpi_gbl_fn_entry_str); |
} |
} |
ACPI_EXPORT_SYMBOL(acpi_ut_trace) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_trace_ptr |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* pointer - Pointer to display |
* |
* RETURN: None |
* |
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level |
* |
******************************************************************************/ |
void |
acpi_ut_trace_ptr(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, void *pointer) |
{ |
acpi_gbl_nesting_level++; |
acpi_ut_track_stack_ptr(); |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, module_name, |
component_id, "%s %p\n", acpi_gbl_fn_entry_str, |
pointer); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_trace_str |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* string - Additional string to display |
* |
* RETURN: None |
* |
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level |
* |
******************************************************************************/ |
void |
acpi_ut_trace_str(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, char *string) |
{ |
acpi_gbl_nesting_level++; |
acpi_ut_track_stack_ptr(); |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, module_name, |
component_id, "%s %s\n", acpi_gbl_fn_entry_str, |
string); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_trace_u32 |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* integer - Integer to display |
* |
* RETURN: None |
* |
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level |
* |
******************************************************************************/ |
void |
acpi_ut_trace_u32(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, u32 integer) |
{ |
acpi_gbl_nesting_level++; |
acpi_ut_track_stack_ptr(); |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, module_name, |
component_id, "%s %08X\n", |
acpi_gbl_fn_entry_str, integer); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_exit |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* |
* RETURN: None |
* |
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level |
* |
******************************************************************************/ |
void |
acpi_ut_exit(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id) |
{ |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, module_name, |
component_id, "%s\n", acpi_gbl_fn_exit_str); |
} |
if (acpi_gbl_nesting_level) { |
acpi_gbl_nesting_level--; |
} |
} |
ACPI_EXPORT_SYMBOL(acpi_ut_exit) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_status_exit |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* status - Exit status code |
* |
* RETURN: None |
* |
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level. Prints exit status also. |
* |
******************************************************************************/ |
void |
acpi_ut_status_exit(u32 line_number, |
const char *function_name, |
const char *module_name, |
u32 component_id, acpi_status status) |
{ |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
if (ACPI_SUCCESS(status)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, |
module_name, component_id, "%s %s\n", |
acpi_gbl_fn_exit_str, |
acpi_format_exception(status)); |
} else { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, |
module_name, component_id, |
"%s ****Exception****: %s\n", |
acpi_gbl_fn_exit_str, |
acpi_format_exception(status)); |
} |
} |
if (acpi_gbl_nesting_level) { |
acpi_gbl_nesting_level--; |
} |
} |
ACPI_EXPORT_SYMBOL(acpi_ut_status_exit) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_value_exit |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* value - Value to be printed with exit msg |
* |
* RETURN: None |
* |
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level. Prints exit value also. |
* |
******************************************************************************/ |
void |
acpi_ut_value_exit(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, u64 value) |
{ |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, module_name, |
component_id, "%s %8.8X%8.8X\n", |
acpi_gbl_fn_exit_str, |
ACPI_FORMAT_UINT64(value)); |
} |
if (acpi_gbl_nesting_level) { |
acpi_gbl_nesting_level--; |
} |
} |
ACPI_EXPORT_SYMBOL(acpi_ut_value_exit) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_ptr_exit |
* |
* PARAMETERS: line_number - Caller's line number |
* function_name - Caller's procedure name |
* module_name - Caller's module name |
* component_id - Caller's component ID |
* ptr - Pointer to display |
* |
* RETURN: None |
* |
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is |
* set in debug_level. Prints exit value also. |
* |
******************************************************************************/ |
void |
acpi_ut_ptr_exit(u32 line_number, |
const char *function_name, |
const char *module_name, u32 component_id, u8 *ptr) |
{ |
/* Check if enabled up-front for performance */ |
if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) { |
acpi_debug_print(ACPI_LV_FUNCTIONS, |
line_number, function_name, module_name, |
component_id, "%s %p\n", acpi_gbl_fn_exit_str, |
ptr); |
} |
if (acpi_gbl_nesting_level) { |
acpi_gbl_nesting_level--; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_trace_point |
* |
* PARAMETERS: type - Trace event type |
* begin - TRUE if before execution |
* aml - Executed AML address |
* pathname - Object path |
* pointer - Pointer to the related object |
* |
* RETURN: None |
* |
* DESCRIPTION: Interpreter execution trace. |
* |
******************************************************************************/ |
void |
acpi_trace_point(acpi_trace_event_type type, u8 begin, u8 *aml, char *pathname) |
{ |
ACPI_FUNCTION_ENTRY(); |
acpi_ex_trace_point(type, begin, aml, pathname); |
#ifdef ACPI_USE_SYSTEM_TRACER |
acpi_os_trace_point(type, begin, aml, pathname); |
#endif |
} |
ACPI_EXPORT_SYMBOL(acpi_trace_point) |
#endif |
#ifdef ACPI_APPLICATION |
/******************************************************************************* |
* |
* FUNCTION: acpi_log_error |
* |
* PARAMETERS: format - Printf format field |
* ... - Optional printf arguments |
* |
* RETURN: None |
* |
* DESCRIPTION: Print error message to the console, used by applications. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE acpi_log_error(const char *format, ...) |
{ |
va_list args; |
va_start(args, format); |
(void)acpi_ut_file_vprintf(ACPI_FILE_ERR, format, args); |
va_end(args); |
} |
ACPI_EXPORT_SYMBOL(acpi_log_error) |
#endif |
/drivers/acpi/acpica/utdecode.c |
---|
0,0 → 1,558 |
/****************************************************************************** |
* |
* Module Name: utdecode - Utility decoding routines (value-to-string) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utdecode") |
/* |
* Properties of the ACPI Object Types, both internal and external. |
* The table is indexed by values of acpi_object_type |
*/ |
const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES] = { |
ACPI_NS_NORMAL, /* 00 Any */ |
ACPI_NS_NORMAL, /* 01 Number */ |
ACPI_NS_NORMAL, /* 02 String */ |
ACPI_NS_NORMAL, /* 03 Buffer */ |
ACPI_NS_NORMAL, /* 04 Package */ |
ACPI_NS_NORMAL, /* 05 field_unit */ |
ACPI_NS_NEWSCOPE, /* 06 Device */ |
ACPI_NS_NORMAL, /* 07 Event */ |
ACPI_NS_NEWSCOPE, /* 08 Method */ |
ACPI_NS_NORMAL, /* 09 Mutex */ |
ACPI_NS_NORMAL, /* 10 Region */ |
ACPI_NS_NEWSCOPE, /* 11 Power */ |
ACPI_NS_NEWSCOPE, /* 12 Processor */ |
ACPI_NS_NEWSCOPE, /* 13 Thermal */ |
ACPI_NS_NORMAL, /* 14 buffer_field */ |
ACPI_NS_NORMAL, /* 15 ddb_handle */ |
ACPI_NS_NORMAL, /* 16 Debug Object */ |
ACPI_NS_NORMAL, /* 17 def_field */ |
ACPI_NS_NORMAL, /* 18 bank_field */ |
ACPI_NS_NORMAL, /* 19 index_field */ |
ACPI_NS_NORMAL, /* 20 Reference */ |
ACPI_NS_NORMAL, /* 21 Alias */ |
ACPI_NS_NORMAL, /* 22 method_alias */ |
ACPI_NS_NORMAL, /* 23 Notify */ |
ACPI_NS_NORMAL, /* 24 Address Handler */ |
ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */ |
ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */ |
ACPI_NS_NEWSCOPE, /* 27 Scope */ |
ACPI_NS_NORMAL, /* 28 Extra */ |
ACPI_NS_NORMAL, /* 29 Data */ |
ACPI_NS_NORMAL /* 30 Invalid */ |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_region_name |
* |
* PARAMETERS: Space ID - ID for the region |
* |
* RETURN: Decoded region space_id name |
* |
* DESCRIPTION: Translate a Space ID into a name string (Debug only) |
* |
******************************************************************************/ |
/* Region type decoding */ |
const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { |
"SystemMemory", /* 0x00 */ |
"SystemIO", /* 0x01 */ |
"PCI_Config", /* 0x02 */ |
"EmbeddedControl", /* 0x03 */ |
"SMBus", /* 0x04 */ |
"SystemCMOS", /* 0x05 */ |
"PCIBARTarget", /* 0x06 */ |
"IPMI", /* 0x07 */ |
"GeneralPurposeIo", /* 0x08 */ |
"GenericSerialBus", /* 0x09 */ |
"PCC" /* 0x0A */ |
}; |
char *acpi_ut_get_region_name(u8 space_id) |
{ |
if (space_id >= ACPI_USER_REGION_BEGIN) { |
return ("UserDefinedRegion"); |
} else if (space_id == ACPI_ADR_SPACE_DATA_TABLE) { |
return ("DataTable"); |
} else if (space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { |
return ("FunctionalFixedHW"); |
} else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) { |
return ("InvalidSpaceId"); |
} |
return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id])); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_event_name |
* |
* PARAMETERS: event_id - Fixed event ID |
* |
* RETURN: Decoded event ID name |
* |
* DESCRIPTION: Translate a Event ID into a name string (Debug only) |
* |
******************************************************************************/ |
/* Event type decoding */ |
static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = { |
"PM_Timer", |
"GlobalLock", |
"PowerButton", |
"SleepButton", |
"RealTimeClock", |
}; |
char *acpi_ut_get_event_name(u32 event_id) |
{ |
if (event_id > ACPI_EVENT_MAX) { |
return ("InvalidEventID"); |
} |
return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id])); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_type_name |
* |
* PARAMETERS: type - An ACPI object type |
* |
* RETURN: Decoded ACPI object type name |
* |
* DESCRIPTION: Translate a Type ID into a name string (Debug only) |
* |
******************************************************************************/ |
/* |
* Elements of acpi_gbl_ns_type_names below must match |
* one-to-one with values of acpi_object_type |
* |
* The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; |
* when stored in a table it really means that we have thus far seen no |
* evidence to indicate what type is actually going to be stored for this entry. |
*/ |
static const char acpi_gbl_bad_type[] = "UNDEFINED"; |
/* Printable names of the ACPI object types */ |
static const char *acpi_gbl_ns_type_names[] = { |
/* 00 */ "Untyped", |
/* 01 */ "Integer", |
/* 02 */ "String", |
/* 03 */ "Buffer", |
/* 04 */ "Package", |
/* 05 */ "FieldUnit", |
/* 06 */ "Device", |
/* 07 */ "Event", |
/* 08 */ "Method", |
/* 09 */ "Mutex", |
/* 10 */ "Region", |
/* 11 */ "Power", |
/* 12 */ "Processor", |
/* 13 */ "Thermal", |
/* 14 */ "BufferField", |
/* 15 */ "DdbHandle", |
/* 16 */ "DebugObject", |
/* 17 */ "RegionField", |
/* 18 */ "BankField", |
/* 19 */ "IndexField", |
/* 20 */ "Reference", |
/* 21 */ "Alias", |
/* 22 */ "MethodAlias", |
/* 23 */ "Notify", |
/* 24 */ "AddrHandler", |
/* 25 */ "ResourceDesc", |
/* 26 */ "ResourceFld", |
/* 27 */ "Scope", |
/* 28 */ "Extra", |
/* 29 */ "Data", |
/* 30 */ "Invalid" |
}; |
char *acpi_ut_get_type_name(acpi_object_type type) |
{ |
if (type > ACPI_TYPE_INVALID) { |
return (ACPI_CAST_PTR(char, acpi_gbl_bad_type)); |
} |
return (ACPI_CAST_PTR(char, acpi_gbl_ns_type_names[type])); |
} |
char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) |
{ |
ACPI_FUNCTION_TRACE(ut_get_object_type_name); |
if (!obj_desc) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n")); |
return_PTR("[NULL Object Descriptor]"); |
} |
/* These descriptor types share a common area */ |
if ((ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) && |
(ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_NAMED)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Invalid object descriptor type: 0x%2.2X [%s] (%p)\n", |
ACPI_GET_DESCRIPTOR_TYPE(obj_desc), |
acpi_ut_get_descriptor_name(obj_desc), |
obj_desc)); |
return_PTR("Invalid object"); |
} |
return_PTR(acpi_ut_get_type_name(obj_desc->common.type)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_node_name |
* |
* PARAMETERS: object - A namespace node |
* |
* RETURN: ASCII name of the node |
* |
* DESCRIPTION: Validate the node and return the node's ACPI name. |
* |
******************************************************************************/ |
char *acpi_ut_get_node_name(void *object) |
{ |
struct acpi_namespace_node *node = (struct acpi_namespace_node *)object; |
/* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ |
if (!object) { |
return ("NULL"); |
} |
/* Check for Root node */ |
if ((object == ACPI_ROOT_OBJECT) || (object == acpi_gbl_root_node)) { |
return ("\"\\\" "); |
} |
/* Descriptor must be a namespace node */ |
if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { |
return ("####"); |
} |
/* |
* Ensure name is valid. The name was validated/repaired when the node |
* was created, but make sure it has not been corrupted. |
*/ |
acpi_ut_repair_name(node->name.ascii); |
/* Return the name */ |
return (node->name.ascii); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_descriptor_name |
* |
* PARAMETERS: object - An ACPI object |
* |
* RETURN: Decoded name of the descriptor type |
* |
* DESCRIPTION: Validate object and return the descriptor type |
* |
******************************************************************************/ |
/* Printable names of object descriptor types */ |
static const char *acpi_gbl_desc_type_names[] = { |
/* 00 */ "Not a Descriptor", |
/* 01 */ "Cached", |
/* 02 */ "State-Generic", |
/* 03 */ "State-Update", |
/* 04 */ "State-Package", |
/* 05 */ "State-Control", |
/* 06 */ "State-RootParseScope", |
/* 07 */ "State-ParseScope", |
/* 08 */ "State-WalkScope", |
/* 09 */ "State-Result", |
/* 10 */ "State-Notify", |
/* 11 */ "State-Thread", |
/* 12 */ "Walk", |
/* 13 */ "Parser", |
/* 14 */ "Operand", |
/* 15 */ "Node" |
}; |
char *acpi_ut_get_descriptor_name(void *object) |
{ |
if (!object) { |
return ("NULL OBJECT"); |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(object) > ACPI_DESC_TYPE_MAX) { |
return ("Not a Descriptor"); |
} |
return (ACPI_CAST_PTR(char, |
acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE |
(object)])); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_reference_name |
* |
* PARAMETERS: object - An ACPI reference object |
* |
* RETURN: Decoded name of the type of reference |
* |
* DESCRIPTION: Decode a reference object sub-type to a string. |
* |
******************************************************************************/ |
/* Printable names of reference object sub-types */ |
static const char *acpi_gbl_ref_class_names[] = { |
/* 00 */ "Local", |
/* 01 */ "Argument", |
/* 02 */ "RefOf", |
/* 03 */ "Index", |
/* 04 */ "DdbHandle", |
/* 05 */ "Named Object", |
/* 06 */ "Debug" |
}; |
const char *acpi_ut_get_reference_name(union acpi_operand_object *object) |
{ |
if (!object) { |
return ("NULL Object"); |
} |
if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) { |
return ("Not an Operand object"); |
} |
if (object->common.type != ACPI_TYPE_LOCAL_REFERENCE) { |
return ("Not a Reference object"); |
} |
if (object->reference.class > ACPI_REFCLASS_MAX) { |
return ("Unknown Reference class"); |
} |
return (acpi_gbl_ref_class_names[object->reference.class]); |
} |
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
/* |
* Strings and procedures used for debug only |
*/ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_mutex_name |
* |
* PARAMETERS: mutex_id - The predefined ID for this mutex. |
* |
* RETURN: Decoded name of the internal mutex |
* |
* DESCRIPTION: Translate a mutex ID into a name string (Debug only) |
* |
******************************************************************************/ |
/* Names for internal mutex objects, used for debug output */ |
static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { |
"ACPI_MTX_Interpreter", |
"ACPI_MTX_Namespace", |
"ACPI_MTX_Tables", |
"ACPI_MTX_Events", |
"ACPI_MTX_Caches", |
"ACPI_MTX_Memory", |
}; |
char *acpi_ut_get_mutex_name(u32 mutex_id) |
{ |
if (mutex_id > ACPI_MAX_MUTEX) { |
return ("Invalid Mutex ID"); |
} |
return (acpi_gbl_mutex_names[mutex_id]); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_notify_name |
* |
* PARAMETERS: notify_value - Value from the Notify() request |
* |
* RETURN: Decoded name for the notify value |
* |
* DESCRIPTION: Translate a Notify Value to a notify namestring. |
* |
******************************************************************************/ |
/* Names for Notify() values, used for debug output */ |
static const char *acpi_gbl_generic_notify[ACPI_NOTIFY_MAX + 1] = { |
/* 00 */ "Bus Check", |
/* 01 */ "Device Check", |
/* 02 */ "Device Wake", |
/* 03 */ "Eject Request", |
/* 04 */ "Device Check Light", |
/* 05 */ "Frequency Mismatch", |
/* 06 */ "Bus Mode Mismatch", |
/* 07 */ "Power Fault", |
/* 08 */ "Capabilities Check", |
/* 09 */ "Device PLD Check", |
/* 0A */ "Reserved", |
/* 0B */ "System Locality Update", |
/* 0C */ "Shutdown Request", |
/* 0D */ "System Resource Affinity Update" |
}; |
static const char *acpi_gbl_device_notify[4] = { |
/* 80 */ "Status Change", |
/* 81 */ "Information Change", |
/* 82 */ "Device-Specific Change", |
/* 83 */ "Device-Specific Change" |
}; |
static const char *acpi_gbl_processor_notify[4] = { |
/* 80 */ "Performance Capability Change", |
/* 81 */ "C-State Change", |
/* 82 */ "Throttling Capability Change", |
/* 83 */ "Device-Specific Change" |
}; |
static const char *acpi_gbl_thermal_notify[4] = { |
/* 80 */ "Thermal Status Change", |
/* 81 */ "Thermal Trip Point Change", |
/* 82 */ "Thermal Device List Change", |
/* 83 */ "Thermal Relationship Change" |
}; |
const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type) |
{ |
/* 00 - 0D are common to all object types */ |
if (notify_value <= ACPI_NOTIFY_MAX) { |
return (acpi_gbl_generic_notify[notify_value]); |
} |
/* 0D - 7F are reserved */ |
if (notify_value <= ACPI_MAX_SYS_NOTIFY) { |
return ("Reserved"); |
} |
/* 80 - 83 are per-object-type */ |
if (notify_value <= 0x83) { |
switch (type) { |
case ACPI_TYPE_ANY: |
case ACPI_TYPE_DEVICE: |
return (acpi_gbl_device_notify[notify_value - 0x80]); |
case ACPI_TYPE_PROCESSOR: |
return (acpi_gbl_processor_notify[notify_value - 0x80]); |
case ACPI_TYPE_THERMAL: |
return (acpi_gbl_thermal_notify[notify_value - 0x80]); |
default: |
return ("Target object type does not support notifies"); |
} |
} |
/* 84 - BF are device-specific */ |
if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) { |
return ("Device-Specific"); |
} |
/* C0 and above are hardware-specific */ |
return ("Hardware-Specific"); |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_valid_object_type |
* |
* PARAMETERS: type - Object type to be validated |
* |
* RETURN: TRUE if valid object type, FALSE otherwise |
* |
* DESCRIPTION: Validate an object type |
* |
******************************************************************************/ |
u8 acpi_ut_valid_object_type(acpi_object_type type) |
{ |
if (type > ACPI_TYPE_LOCAL_MAX) { |
/* Note: Assumes all TYPEs are contiguous (external/local) */ |
return (FALSE); |
} |
return (TRUE); |
} |
/drivers/acpi/acpica/utdelete.c |
---|
0,0 → 1,758 |
/******************************************************************************* |
* |
* Module Name: utdelete - object deletion and reference count utilities |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#include "acnamesp.h" |
#include "acevents.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utdelete") |
/* Local prototypes */ |
static void acpi_ut_delete_internal_obj(union acpi_operand_object *object); |
static void |
acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_delete_internal_obj |
* |
* PARAMETERS: object - Object to be deleted |
* |
* RETURN: None |
* |
* DESCRIPTION: Low level object deletion, after reference counts have been |
* updated (All reference counts, including sub-objects!) |
* |
******************************************************************************/ |
static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) |
{ |
void *obj_pointer = NULL; |
union acpi_operand_object *handler_desc; |
union acpi_operand_object *second_desc; |
union acpi_operand_object *next_desc; |
union acpi_operand_object *start_desc; |
union acpi_operand_object **last_obj_ptr; |
ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); |
if (!object) { |
return_VOID; |
} |
/* |
* Must delete or free any pointers within the object that are not |
* actual ACPI objects (for example, a raw buffer pointer). |
*/ |
switch (object->common.type) { |
case ACPI_TYPE_STRING: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"**** String %p, ptr %p\n", object, |
object->string.pointer)); |
/* Free the actual string buffer */ |
if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { |
/* But only if it is NOT a pointer into an ACPI table */ |
obj_pointer = object->string.pointer; |
} |
break; |
case ACPI_TYPE_BUFFER: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"**** Buffer %p, ptr %p\n", object, |
object->buffer.pointer)); |
/* Free the actual buffer */ |
if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { |
/* But only if it is NOT a pointer into an ACPI table */ |
obj_pointer = object->buffer.pointer; |
} |
break; |
case ACPI_TYPE_PACKAGE: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
" **** Package of count %X\n", |
object->package.count)); |
/* |
* Elements of the package are not handled here, they are deleted |
* separately |
*/ |
/* Free the (variable length) element pointer array */ |
obj_pointer = object->package.elements; |
break; |
/* |
* These objects have a possible list of notify handlers. |
* Device object also may have a GPE block. |
*/ |
case ACPI_TYPE_DEVICE: |
if (object->device.gpe_block) { |
(void)acpi_ev_delete_gpe_block(object->device. |
gpe_block); |
} |
/*lint -fallthrough */ |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_THERMAL: |
/* Walk the address handler list for this object */ |
handler_desc = object->common_notify.handler; |
while (handler_desc) { |
next_desc = handler_desc->address_space.next; |
acpi_ut_remove_reference(handler_desc); |
handler_desc = next_desc; |
} |
break; |
case ACPI_TYPE_MUTEX: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"***** Mutex %p, OS Mutex %p\n", |
object, object->mutex.os_mutex)); |
if (object == acpi_gbl_global_lock_mutex) { |
/* Global Lock has extra semaphore */ |
(void) |
acpi_os_delete_semaphore |
(acpi_gbl_global_lock_semaphore); |
acpi_gbl_global_lock_semaphore = NULL; |
acpi_os_delete_mutex(object->mutex.os_mutex); |
acpi_gbl_global_lock_mutex = NULL; |
} else { |
acpi_ex_unlink_mutex(object); |
acpi_os_delete_mutex(object->mutex.os_mutex); |
} |
break; |
case ACPI_TYPE_EVENT: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"***** Event %p, OS Semaphore %p\n", |
object, object->event.os_semaphore)); |
(void)acpi_os_delete_semaphore(object->event.os_semaphore); |
object->event.os_semaphore = NULL; |
break; |
case ACPI_TYPE_METHOD: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"***** Method %p\n", object)); |
/* Delete the method mutex if it exists */ |
if (object->method.mutex) { |
acpi_os_delete_mutex(object->method.mutex->mutex. |
os_mutex); |
acpi_ut_delete_object_desc(object->method.mutex); |
object->method.mutex = NULL; |
} |
if (object->method.node) { |
object->method.node = NULL; |
} |
break; |
case ACPI_TYPE_REGION: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"***** Region %p\n", object)); |
/* |
* Update address_range list. However, only permanent regions |
* are installed in this list. (Not created within a method) |
*/ |
if (!(object->region.node->flags & ANOBJ_TEMPORARY)) { |
acpi_ut_remove_address_range(object->region.space_id, |
object->region.node); |
} |
second_desc = acpi_ns_get_secondary_object(object); |
if (second_desc) { |
/* |
* Free the region_context if and only if the handler is one of the |
* default handlers -- and therefore, we created the context object |
* locally, it was not created by an external caller. |
*/ |
handler_desc = object->region.handler; |
if (handler_desc) { |
next_desc = |
handler_desc->address_space.region_list; |
start_desc = next_desc; |
last_obj_ptr = |
&handler_desc->address_space.region_list; |
/* Remove the region object from the handler list */ |
while (next_desc) { |
if (next_desc == object) { |
*last_obj_ptr = |
next_desc->region.next; |
break; |
} |
/* Walk the linked list of handlers */ |
last_obj_ptr = &next_desc->region.next; |
next_desc = next_desc->region.next; |
/* Prevent infinite loop if list is corrupted */ |
if (next_desc == start_desc) { |
ACPI_ERROR((AE_INFO, |
"Circular region list in address handler object %p", |
handler_desc)); |
return_VOID; |
} |
} |
if (handler_desc->address_space.handler_flags & |
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { |
/* Deactivate region and free region context */ |
if (handler_desc->address_space.setup) { |
(void)handler_desc-> |
address_space.setup(object, |
ACPI_REGION_DEACTIVATE, |
handler_desc-> |
address_space. |
context, |
&second_desc-> |
extra. |
region_context); |
} |
} |
acpi_ut_remove_reference(handler_desc); |
} |
/* Now we can free the Extra object */ |
acpi_ut_delete_object_desc(second_desc); |
} |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"***** Buffer Field %p\n", object)); |
second_desc = acpi_ns_get_secondary_object(object); |
if (second_desc) { |
acpi_ut_delete_object_desc(second_desc); |
} |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"***** Bank Field %p\n", object)); |
second_desc = acpi_ns_get_secondary_object(object); |
if (second_desc) { |
acpi_ut_delete_object_desc(second_desc); |
} |
break; |
default: |
break; |
} |
/* Free any allocated memory (pointer within the object) found above */ |
if (obj_pointer) { |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"Deleting Object Subptr %p\n", obj_pointer)); |
ACPI_FREE(obj_pointer); |
} |
/* Now the object can be safely deleted */ |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n", |
object, acpi_ut_get_object_type_name(object))); |
acpi_ut_delete_object_desc(object); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_delete_internal_object_list |
* |
* PARAMETERS: obj_list - Pointer to the list to be deleted |
* |
* RETURN: None |
* |
* DESCRIPTION: This function deletes an internal object list, including both |
* simple objects and package objects |
* |
******************************************************************************/ |
void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list) |
{ |
union acpi_operand_object **internal_obj; |
ACPI_FUNCTION_ENTRY(); |
/* Walk the null-terminated internal list */ |
for (internal_obj = obj_list; *internal_obj; internal_obj++) { |
acpi_ut_remove_reference(*internal_obj); |
} |
/* Free the combined parameter pointer list and object array */ |
ACPI_FREE(obj_list); |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_update_ref_count |
* |
* PARAMETERS: object - Object whose ref count is to be updated |
* action - What to do (REF_INCREMENT or REF_DECREMENT) |
* |
* RETURN: None. Sets new reference count within the object |
* |
* DESCRIPTION: Modify the reference count for an internal acpi object |
* |
******************************************************************************/ |
static void |
acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) |
{ |
u16 original_count; |
u16 new_count = 0; |
acpi_cpu_flags lock_flags; |
ACPI_FUNCTION_NAME(ut_update_ref_count); |
if (!object) { |
return; |
} |
/* |
* Always get the reference count lock. Note: Interpreter and/or |
* Namespace is not always locked when this function is called. |
*/ |
lock_flags = acpi_os_acquire_lock(acpi_gbl_reference_count_lock); |
original_count = object->common.reference_count; |
/* Perform the reference count action (increment, decrement) */ |
switch (action) { |
case REF_INCREMENT: |
new_count = original_count + 1; |
object->common.reference_count = new_count; |
acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags); |
/* The current reference count should never be zero here */ |
if (!original_count) { |
ACPI_WARNING((AE_INFO, |
"Obj %p, Reference Count was zero before increment\n", |
object)); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"Obj %p Type %.2X Refs %.2X [Incremented]\n", |
object, object->common.type, new_count)); |
break; |
case REF_DECREMENT: |
/* The current reference count must be non-zero */ |
if (original_count) { |
new_count = original_count - 1; |
object->common.reference_count = new_count; |
} |
acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags); |
if (!original_count) { |
ACPI_WARNING((AE_INFO, |
"Obj %p, Reference Count is already zero, cannot decrement\n", |
object)); |
} |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"Obj %p Type %.2X Refs %.2X [Decremented]\n", |
object, object->common.type, new_count)); |
/* Actually delete the object on a reference count of zero */ |
if (new_count == 0) { |
acpi_ut_delete_internal_obj(object); |
} |
break; |
default: |
acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags); |
ACPI_ERROR((AE_INFO, "Unknown Reference Count action (0x%X)", |
action)); |
return; |
} |
/* |
* Sanity check the reference count, for debug purposes only. |
* (A deleted object will have a huge reference count) |
*/ |
if (new_count > ACPI_MAX_REFERENCE_COUNT) { |
ACPI_WARNING((AE_INFO, |
"Large Reference Count (0x%X) in object %p, Type=0x%.2X", |
new_count, object, object->common.type)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_update_object_reference |
* |
* PARAMETERS: object - Increment ref count for this object |
* and all sub-objects |
* action - Either REF_INCREMENT or REF_DECREMENT |
* |
* RETURN: Status |
* |
* DESCRIPTION: Increment the object reference count |
* |
* Object references are incremented when: |
* 1) An object is attached to a Node (namespace object) |
* 2) An object is copied (all subobjects must be incremented) |
* |
* Object references are decremented when: |
* 1) An object is detached from an Node |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) |
{ |
acpi_status status = AE_OK; |
union acpi_generic_state *state_list = NULL; |
union acpi_operand_object *next_object = NULL; |
union acpi_operand_object *prev_object; |
union acpi_generic_state *state; |
u32 i; |
ACPI_FUNCTION_NAME(ut_update_object_reference); |
while (object) { |
/* Make sure that this isn't a namespace handle */ |
if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) { |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"Object %p is NS handle\n", object)); |
return (AE_OK); |
} |
/* |
* All sub-objects must have their reference count incremented also. |
* Different object types have different subobjects. |
*/ |
switch (object->common.type) { |
case ACPI_TYPE_DEVICE: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_POWER: |
case ACPI_TYPE_THERMAL: |
/* |
* Update the notify objects for these types (if present) |
* Two lists, system and device notify handlers. |
*/ |
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { |
prev_object = |
object->common_notify.notify_list[i]; |
while (prev_object) { |
next_object = |
prev_object->notify.next[i]; |
acpi_ut_update_ref_count(prev_object, |
action); |
prev_object = next_object; |
} |
} |
break; |
case ACPI_TYPE_PACKAGE: |
/* |
* We must update all the sub-objects of the package, |
* each of whom may have their own sub-objects. |
*/ |
for (i = 0; i < object->package.count; i++) { |
/* |
* Null package elements are legal and can be simply |
* ignored. |
*/ |
next_object = object->package.elements[i]; |
if (!next_object) { |
continue; |
} |
switch (next_object->common.type) { |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_STRING: |
case ACPI_TYPE_BUFFER: |
/* |
* For these very simple sub-objects, we can just |
* update the reference count here and continue. |
* Greatly increases performance of this operation. |
*/ |
acpi_ut_update_ref_count(next_object, |
action); |
break; |
default: |
/* |
* For complex sub-objects, push them onto the stack |
* for later processing (this eliminates recursion.) |
*/ |
status = |
acpi_ut_create_update_state_and_push |
(next_object, action, &state_list); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
break; |
} |
} |
next_object = NULL; |
break; |
case ACPI_TYPE_BUFFER_FIELD: |
next_object = object->buffer_field.buffer_obj; |
break; |
case ACPI_TYPE_LOCAL_REGION_FIELD: |
next_object = object->field.region_obj; |
break; |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
next_object = object->bank_field.bank_obj; |
status = |
acpi_ut_create_update_state_and_push(object-> |
bank_field. |
region_obj, |
action, |
&state_list); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
break; |
case ACPI_TYPE_LOCAL_INDEX_FIELD: |
next_object = object->index_field.index_obj; |
status = |
acpi_ut_create_update_state_and_push(object-> |
index_field. |
data_obj, |
action, |
&state_list); |
if (ACPI_FAILURE(status)) { |
goto error_exit; |
} |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
/* |
* The target of an Index (a package, string, or buffer) or a named |
* reference must track changes to the ref count of the index or |
* target object. |
*/ |
if ((object->reference.class == ACPI_REFCLASS_INDEX) || |
(object->reference.class == ACPI_REFCLASS_NAME)) { |
next_object = object->reference.object; |
} |
break; |
case ACPI_TYPE_REGION: |
default: |
break; /* No subobjects for all other types */ |
} |
/* |
* Now we can update the count in the main object. This can only |
* happen after we update the sub-objects in case this causes the |
* main object to be deleted. |
*/ |
acpi_ut_update_ref_count(object, action); |
object = NULL; |
/* Move on to the next object to be updated */ |
if (next_object) { |
object = next_object; |
next_object = NULL; |
} else if (state_list) { |
state = acpi_ut_pop_generic_state(&state_list); |
object = state->update.object; |
acpi_ut_delete_generic_state(state); |
} |
} |
return (AE_OK); |
error_exit: |
ACPI_EXCEPTION((AE_INFO, status, |
"Could not update object reference count")); |
/* Free any stacked Update State objects */ |
while (state_list) { |
state = acpi_ut_pop_generic_state(&state_list); |
acpi_ut_delete_generic_state(state); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_add_reference |
* |
* PARAMETERS: object - Object whose reference count is to be |
* incremented |
* |
* RETURN: None |
* |
* DESCRIPTION: Add one reference to an ACPI object |
* |
******************************************************************************/ |
void acpi_ut_add_reference(union acpi_operand_object *object) |
{ |
ACPI_FUNCTION_NAME(ut_add_reference); |
/* Ensure that we have a valid object */ |
if (!acpi_ut_valid_internal_object(object)) { |
return; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"Obj %p Current Refs=%X [To Be Incremented]\n", |
object, object->common.reference_count)); |
/* Increment the reference count */ |
(void)acpi_ut_update_object_reference(object, REF_INCREMENT); |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_remove_reference |
* |
* PARAMETERS: object - Object whose ref count will be decremented |
* |
* RETURN: None |
* |
* DESCRIPTION: Decrement the reference count of an ACPI internal object |
* |
******************************************************************************/ |
void acpi_ut_remove_reference(union acpi_operand_object *object) |
{ |
ACPI_FUNCTION_NAME(ut_remove_reference); |
/* |
* Allow a NULL pointer to be passed in, just ignore it. This saves |
* each caller from having to check. Also, ignore NS nodes. |
*/ |
if (!object || |
(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) { |
return; |
} |
/* Ensure that we have a valid object */ |
if (!acpi_ut_valid_internal_object(object)) { |
return; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, |
"Obj %p Current Refs=%X [To Be Decremented]\n", |
object, object->common.reference_count)); |
/* |
* Decrement the reference count, and only actually delete the object |
* if the reference count becomes 0. (Must also decrement the ref count |
* of all subobjects!) |
*/ |
(void)acpi_ut_update_object_reference(object, REF_DECREMENT); |
return; |
} |
/drivers/acpi/acpica/uterror.c |
---|
0,0 → 1,289 |
/******************************************************************************* |
* |
* Module Name: uterror - Various internal error/warning output functions |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("uterror") |
/* |
* This module contains internal error functions that may |
* be configured out. |
*/ |
#if !defined (ACPI_NO_ERROR_MESSAGES) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_predefined_warning |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* pathname - Full pathname to the node |
* node_flags - From Namespace node for the method/object |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Warnings for the predefined validation module. Messages are |
* only emitted the first time a problem with a particular |
* method/object is detected. This prevents a flood of error |
* messages for methods that are repeatedly evaluated. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_ut_predefined_warning(const char *module_name, |
u32 line_number, |
char *pathname, |
u8 node_flags, const char *format, ...) |
{ |
va_list arg_list; |
/* |
* Warning messages for this method/object will be disabled after the |
* first time a validation fails or an object is successfully repaired. |
*/ |
if (node_flags & ANOBJ_EVALUATED) { |
return; |
} |
acpi_os_printf(ACPI_MSG_WARNING "%s: ", pathname); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_predefined_info |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* pathname - Full pathname to the node |
* node_flags - From Namespace node for the method/object |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Info messages for the predefined validation module. Messages |
* are only emitted the first time a problem with a particular |
* method/object is detected. This prevents a flood of |
* messages for methods that are repeatedly evaluated. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_ut_predefined_info(const char *module_name, |
u32 line_number, |
char *pathname, u8 node_flags, const char *format, ...) |
{ |
va_list arg_list; |
/* |
* Warning messages for this method/object will be disabled after the |
* first time a validation fails or an object is successfully repaired. |
*/ |
if (node_flags & ANOBJ_EVALUATED) { |
return; |
} |
acpi_os_printf(ACPI_MSG_INFO "%s: ", pathname); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_predefined_bios_error |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* pathname - Full pathname to the node |
* node_flags - From Namespace node for the method/object |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: BIOS error message for predefined names. Messages |
* are only emitted the first time a problem with a particular |
* method/object is detected. This prevents a flood of |
* messages for methods that are repeatedly evaluated. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_ut_predefined_bios_error(const char *module_name, |
u32 line_number, |
char *pathname, |
u8 node_flags, const char *format, ...) |
{ |
va_list arg_list; |
/* |
* Warning messages for this method/object will be disabled after the |
* first time a validation fails or an object is successfully repaired. |
*/ |
if (node_flags & ANOBJ_EVALUATED) { |
return; |
} |
acpi_os_printf(ACPI_MSG_BIOS_ERROR "%s: ", pathname); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_namespace_error |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* internal_name - Name or path of the namespace node |
* lookup_status - Exception code from NS lookup |
* |
* RETURN: None |
* |
* DESCRIPTION: Print error message with the full pathname for the NS node. |
* |
******************************************************************************/ |
void |
acpi_ut_namespace_error(const char *module_name, |
u32 line_number, |
const char *internal_name, acpi_status lookup_status) |
{ |
acpi_status status; |
u32 bad_name; |
char *name = NULL; |
ACPI_MSG_REDIRECT_BEGIN; |
acpi_os_printf(ACPI_MSG_ERROR); |
if (lookup_status == AE_BAD_CHARACTER) { |
/* There is a non-ascii character in the name */ |
ACPI_MOVE_32_TO_32(&bad_name, |
ACPI_CAST_PTR(u32, internal_name)); |
acpi_os_printf("[0x%.8X] (NON-ASCII)", bad_name); |
} else { |
/* Convert path to external format */ |
status = acpi_ns_externalize_name(ACPI_UINT32_MAX, |
internal_name, NULL, &name); |
/* Print target name */ |
if (ACPI_SUCCESS(status)) { |
acpi_os_printf("[%s]", name); |
} else { |
acpi_os_printf("[COULD NOT EXTERNALIZE NAME]"); |
} |
if (name) { |
ACPI_FREE(name); |
} |
} |
acpi_os_printf(" Namespace lookup failure, %s", |
acpi_format_exception(lookup_status)); |
ACPI_MSG_SUFFIX; |
ACPI_MSG_REDIRECT_END; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_method_error |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* message - Error message to use on failure |
* prefix_node - Prefix relative to the path |
* path - Path to the node (optional) |
* method_status - Execution status |
* |
* RETURN: None |
* |
* DESCRIPTION: Print error message with the full pathname for the method. |
* |
******************************************************************************/ |
void |
acpi_ut_method_error(const char *module_name, |
u32 line_number, |
const char *message, |
struct acpi_namespace_node *prefix_node, |
const char *path, acpi_status method_status) |
{ |
acpi_status status; |
struct acpi_namespace_node *node = prefix_node; |
ACPI_MSG_REDIRECT_BEGIN; |
acpi_os_printf(ACPI_MSG_ERROR); |
if (path) { |
status = |
acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH, |
&node); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("[Could not get node by pathname]"); |
} |
} |
acpi_ns_print_node_pathname(node, message); |
acpi_os_printf(", %s", acpi_format_exception(method_status)); |
ACPI_MSG_SUFFIX; |
ACPI_MSG_REDIRECT_END; |
} |
#endif /* ACPI_NO_ERROR_MESSAGES */ |
/drivers/acpi/acpica/uteval.c |
---|
0,0 → 1,349 |
/****************************************************************************** |
* |
* Module Name: uteval - Object evaluation |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("uteval") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_evaluate_object |
* |
* PARAMETERS: prefix_node - Starting node |
* path - Path to object from starting node |
* expected_return_types - Bitmap of allowed return types |
* return_desc - Where a return value is stored |
* |
* RETURN: Status |
* |
* DESCRIPTION: Evaluates a namespace object and verifies the type of the |
* return object. Common code that simplifies accessing objects |
* that have required return objects of fixed types. |
* |
* NOTE: Internal function, no parameter validation |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, |
char *path, |
u32 expected_return_btypes, |
union acpi_operand_object **return_desc) |
{ |
struct acpi_evaluate_info *info; |
acpi_status status; |
u32 return_btype; |
ACPI_FUNCTION_TRACE(ut_evaluate_object); |
/* Allocate the evaluation information block */ |
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
if (!info) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
info->prefix_node = prefix_node; |
info->relative_pathname = path; |
/* Evaluate the object/method */ |
status = acpi_ns_evaluate(info); |
if (ACPI_FAILURE(status)) { |
if (status == AE_NOT_FOUND) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[%4.4s.%s] was not found\n", |
acpi_ut_get_node_name(prefix_node), |
path)); |
} else { |
ACPI_ERROR_METHOD("Method execution failed", |
prefix_node, path, status); |
} |
goto cleanup; |
} |
/* Did we get a return object? */ |
if (!info->return_object) { |
if (expected_return_btypes) { |
ACPI_ERROR_METHOD("No object was returned from", |
prefix_node, path, AE_NOT_EXIST); |
status = AE_NOT_EXIST; |
} |
goto cleanup; |
} |
/* Map the return object type to the bitmapped type */ |
switch ((info->return_object)->common.type) { |
case ACPI_TYPE_INTEGER: |
return_btype = ACPI_BTYPE_INTEGER; |
break; |
case ACPI_TYPE_BUFFER: |
return_btype = ACPI_BTYPE_BUFFER; |
break; |
case ACPI_TYPE_STRING: |
return_btype = ACPI_BTYPE_STRING; |
break; |
case ACPI_TYPE_PACKAGE: |
return_btype = ACPI_BTYPE_PACKAGE; |
break; |
default: |
return_btype = 0; |
break; |
} |
if ((acpi_gbl_enable_interpreter_slack) && (!expected_return_btypes)) { |
/* |
* We received a return object, but one was not expected. This can |
* happen frequently if the "implicit return" feature is enabled. |
* Just delete the return object and return AE_OK. |
*/ |
acpi_ut_remove_reference(info->return_object); |
goto cleanup; |
} |
/* Is the return object one of the expected types? */ |
if (!(expected_return_btypes & return_btype)) { |
ACPI_ERROR_METHOD("Return object type is incorrect", |
prefix_node, path, AE_TYPE); |
ACPI_ERROR((AE_INFO, |
"Type returned from %s was incorrect: %s, expected Btypes: 0x%X", |
path, |
acpi_ut_get_object_type_name(info->return_object), |
expected_return_btypes)); |
/* On error exit, we must delete the return object */ |
acpi_ut_remove_reference(info->return_object); |
status = AE_TYPE; |
goto cleanup; |
} |
/* Object type is OK, return it */ |
*return_desc = info->return_object; |
cleanup: |
ACPI_FREE(info); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_evaluate_numeric_object |
* |
* PARAMETERS: object_name - Object name to be evaluated |
* device_node - Node for the device |
* value - Where the value is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Evaluates a numeric namespace object for a selected device |
* and stores result in *Value. |
* |
* NOTE: Internal function, no parameter validation |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_evaluate_numeric_object(char *object_name, |
struct acpi_namespace_node *device_node, |
u64 *value) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_evaluate_numeric_object); |
status = acpi_ut_evaluate_object(device_node, object_name, |
ACPI_BTYPE_INTEGER, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get the returned Integer */ |
*value = obj_desc->integer.value; |
/* On exit, we must delete the return object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_execute_STA |
* |
* PARAMETERS: device_node - Node for the device |
* flags - Where the status flags are returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Executes _STA for selected device and stores results in |
* *Flags. If _STA does not exist, then the device is assumed |
* to be present/functional/enabled (as per the ACPI spec). |
* |
* NOTE: Internal function, no parameter validation |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_execute_STA); |
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__STA, |
ACPI_BTYPE_INTEGER, &obj_desc); |
if (ACPI_FAILURE(status)) { |
if (AE_NOT_FOUND == status) { |
/* |
* if _STA does not exist, then (as per the ACPI specification), |
* the returned flags will indicate that the device is present, |
* functional, and enabled. |
*/ |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"_STA on %4.4s was not found, assuming device is present\n", |
acpi_ut_get_node_name(device_node))); |
*flags = ACPI_UINT32_MAX; |
status = AE_OK; |
} |
return_ACPI_STATUS(status); |
} |
/* Extract the status flags */ |
*flags = (u32) obj_desc->integer.value; |
/* On exit, we must delete the return object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_execute_power_methods |
* |
* PARAMETERS: device_node - Node for the device |
* method_names - Array of power method names |
* method_count - Number of methods to execute |
* out_values - Where the power method values are returned |
* |
* RETURN: Status, out_values |
* |
* DESCRIPTION: Executes the specified power methods for the device and returns |
* the result(s). |
* |
* NOTE: Internal function, no parameter validation |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, |
const char **method_names, |
u8 method_count, u8 *out_values) |
{ |
union acpi_operand_object *obj_desc; |
acpi_status status; |
acpi_status final_status = AE_NOT_FOUND; |
u32 i; |
ACPI_FUNCTION_TRACE(ut_execute_power_methods); |
for (i = 0; i < method_count; i++) { |
/* |
* Execute the power method (_sx_d or _sx_w). The only allowable |
* return type is an Integer. |
*/ |
status = acpi_ut_evaluate_object(device_node, |
ACPI_CAST_PTR(char, |
method_names[i]), |
ACPI_BTYPE_INTEGER, &obj_desc); |
if (ACPI_SUCCESS(status)) { |
out_values[i] = (u8)obj_desc->integer.value; |
/* Delete the return object */ |
acpi_ut_remove_reference(obj_desc); |
final_status = AE_OK; /* At least one value is valid */ |
continue; |
} |
out_values[i] = ACPI_UINT8_MAX; |
if (status == AE_NOT_FOUND) { |
continue; /* Ignore if not found */ |
} |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"Failed %s on Device %4.4s, %s\n", |
ACPI_CAST_PTR(char, method_names[i]), |
acpi_ut_get_node_name(device_node), |
acpi_format_exception(status))); |
} |
return_ACPI_STATUS(final_status); |
} |
/drivers/acpi/acpica/utexcep.c |
---|
0,0 → 1,159 |
/******************************************************************************* |
* |
* Module Name: utexcep - Exception code support |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#define ACPI_DEFINE_EXCEPTION_TABLE |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utexcep") |
/******************************************************************************* |
* |
* FUNCTION: acpi_format_exception |
* |
* PARAMETERS: status - The acpi_status code to be formatted |
* |
* RETURN: A string containing the exception text. A valid pointer is |
* always returned. |
* |
* DESCRIPTION: This function translates an ACPI exception into an ASCII |
* string. Returns "unknown status" string for invalid codes. |
* |
******************************************************************************/ |
const char *acpi_format_exception(acpi_status status) |
{ |
const struct acpi_exception_info *exception; |
ACPI_FUNCTION_ENTRY(); |
exception = acpi_ut_validate_exception(status); |
if (!exception) { |
/* Exception code was not recognized */ |
ACPI_ERROR((AE_INFO, |
"Unknown exception code: 0x%8.8X", status)); |
return ("UNKNOWN_STATUS_CODE"); |
} |
return (exception->name); |
} |
ACPI_EXPORT_SYMBOL(acpi_format_exception) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_validate_exception |
* |
* PARAMETERS: status - The acpi_status code to be formatted |
* |
* RETURN: A string containing the exception text. NULL if exception is |
* not valid. |
* |
* DESCRIPTION: This function validates and translates an ACPI exception into |
* an ASCII string. |
* |
******************************************************************************/ |
const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status status) |
{ |
u32 sub_status; |
const struct acpi_exception_info *exception = NULL; |
ACPI_FUNCTION_ENTRY(); |
/* |
* Status is composed of two parts, a "type" and an actual code |
*/ |
sub_status = (status & ~AE_CODE_MASK); |
switch (status & AE_CODE_MASK) { |
case AE_CODE_ENVIRONMENTAL: |
if (sub_status <= AE_CODE_ENV_MAX) { |
exception = &acpi_gbl_exception_names_env[sub_status]; |
} |
break; |
case AE_CODE_PROGRAMMER: |
if (sub_status <= AE_CODE_PGM_MAX) { |
exception = &acpi_gbl_exception_names_pgm[sub_status]; |
} |
break; |
case AE_CODE_ACPI_TABLES: |
if (sub_status <= AE_CODE_TBL_MAX) { |
exception = &acpi_gbl_exception_names_tbl[sub_status]; |
} |
break; |
case AE_CODE_AML: |
if (sub_status <= AE_CODE_AML_MAX) { |
exception = &acpi_gbl_exception_names_aml[sub_status]; |
} |
break; |
case AE_CODE_CONTROL: |
if (sub_status <= AE_CODE_CTRL_MAX) { |
exception = &acpi_gbl_exception_names_ctrl[sub_status]; |
} |
break; |
default: |
break; |
} |
if (!exception || !exception->name) { |
return (NULL); |
} |
return (exception); |
} |
/drivers/acpi/acpica/utfileio.c |
---|
0,0 → 1,334 |
/******************************************************************************* |
* |
* Module Name: utfileio - simple file I/O routines |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "actables.h" |
#include "acapps.h" |
#include "errno.h" |
#ifdef ACPI_ASL_COMPILER |
#include "aslcompiler.h" |
#endif |
#define _COMPONENT ACPI_CA_DEBUGGER |
ACPI_MODULE_NAME("utfileio") |
#ifdef ACPI_APPLICATION |
/* Local prototypes */ |
static acpi_status |
acpi_ut_check_text_mode_corruption(u8 *table, |
u32 table_length, u32 file_length); |
static acpi_status |
acpi_ut_read_table(FILE * fp, |
struct acpi_table_header **table, u32 *table_length); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_check_text_mode_corruption |
* |
* PARAMETERS: table - Table buffer |
* table_length - Length of table from the table header |
* file_length - Length of the file that contains the table |
* |
* RETURN: Status |
* |
* DESCRIPTION: Check table for text mode file corruption where all linefeed |
* characters (LF) have been replaced by carriage return linefeed |
* pairs (CR/LF). |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_check_text_mode_corruption(u8 *table, u32 table_length, u32 file_length) |
{ |
u32 i; |
u32 pairs = 0; |
if (table_length != file_length) { |
ACPI_WARNING((AE_INFO, |
"File length (0x%X) is not the same as the table length (0x%X)", |
file_length, table_length)); |
} |
/* Scan entire table to determine if each LF has been prefixed with a CR */ |
for (i = 1; i < file_length; i++) { |
if (table[i] == 0x0A) { |
if (table[i - 1] != 0x0D) { |
/* The LF does not have a preceding CR, table not corrupted */ |
return (AE_OK); |
} else { |
/* Found a CR/LF pair */ |
pairs++; |
} |
i++; |
} |
} |
if (!pairs) { |
return (AE_OK); |
} |
/* |
* Entire table scanned, each CR is part of a CR/LF pair -- |
* meaning that the table was treated as a text file somewhere. |
* |
* NOTE: We can't "fix" the table, because any existing CR/LF pairs in the |
* original table are left untouched by the text conversion process -- |
* meaning that we cannot simply replace CR/LF pairs with LFs. |
*/ |
acpi_os_printf("Table has been corrupted by text mode conversion\n"); |
acpi_os_printf("All LFs (%u) were changed to CR/LF pairs\n", pairs); |
acpi_os_printf("Table cannot be repaired!\n"); |
return (AE_BAD_VALUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_read_table |
* |
* PARAMETERS: fp - File that contains table |
* table - Return value, buffer with table |
* table_length - Return value, length of table |
* |
* RETURN: Status |
* |
* DESCRIPTION: Load the DSDT from the file pointer |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_read_table(FILE * fp, |
struct acpi_table_header **table, u32 *table_length) |
{ |
struct acpi_table_header table_header; |
u32 actual; |
acpi_status status; |
u32 file_size; |
u8 standard_header = TRUE; |
s32 count; |
/* Get the file size */ |
file_size = cm_get_file_size(fp); |
if (file_size == ACPI_UINT32_MAX) { |
return (AE_ERROR); |
} |
if (file_size < 4) { |
return (AE_BAD_HEADER); |
} |
/* Read the signature */ |
fseek(fp, 0, SEEK_SET); |
count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); |
if (count != sizeof(struct acpi_table_header)) { |
acpi_os_printf("Could not read the table header\n"); |
return (AE_BAD_HEADER); |
} |
/* The RSDP table does not have standard ACPI header */ |
if (ACPI_VALIDATE_RSDP_SIG(table_header.signature)) { |
*table_length = file_size; |
standard_header = FALSE; |
} else { |
#if 0 |
/* Validate the table header/length */ |
status = acpi_tb_validate_table_header(&table_header); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Table header is invalid!\n"); |
return (status); |
} |
#endif |
/* File size must be at least as long as the Header-specified length */ |
if (table_header.length > file_size) { |
acpi_os_printf |
("TableHeader length [0x%X] greater than the input file size [0x%X]\n", |
table_header.length, file_size); |
#ifdef ACPI_ASL_COMPILER |
acpi_os_printf("File is corrupt or is ASCII text -- " |
"it must be a binary file\n"); |
#endif |
return (AE_BAD_HEADER); |
} |
#ifdef ACPI_OBSOLETE_CODE |
/* We only support a limited number of table types */ |
if (!ACPI_COMPARE_NAME |
((char *)table_header.signature, ACPI_SIG_DSDT) |
&& !ACPI_COMPARE_NAME((char *)table_header.signature, |
ACPI_SIG_PSDT) |
&& !ACPI_COMPARE_NAME((char *)table_header.signature, |
ACPI_SIG_SSDT)) { |
acpi_os_printf |
("Table signature [%4.4s] is invalid or not supported\n", |
(char *)table_header.signature); |
ACPI_DUMP_BUFFER(&table_header, |
sizeof(struct acpi_table_header)); |
return (AE_ERROR); |
} |
#endif |
*table_length = table_header.length; |
} |
/* Allocate a buffer for the table */ |
*table = acpi_os_allocate((size_t) file_size); |
if (!*table) { |
acpi_os_printf |
("Could not allocate memory for ACPI table %4.4s (size=0x%X)\n", |
table_header.signature, *table_length); |
return (AE_NO_MEMORY); |
} |
/* Get the rest of the table */ |
fseek(fp, 0, SEEK_SET); |
actual = fread(*table, 1, (size_t) file_size, fp); |
if (actual == file_size) { |
if (standard_header) { |
/* Now validate the checksum */ |
status = acpi_tb_verify_checksum((void *)*table, |
ACPI_CAST_PTR(struct |
acpi_table_header, |
*table)-> |
length); |
if (status == AE_BAD_CHECKSUM) { |
status = |
acpi_ut_check_text_mode_corruption((u8 *) |
*table, |
file_size, |
(*table)-> |
length); |
return (status); |
} |
} |
return (AE_OK); |
} |
if (actual > 0) { |
acpi_os_printf("Warning - reading table, asked for %X got %X\n", |
file_size, actual); |
return (AE_OK); |
} |
acpi_os_printf("Error - could not read the table file\n"); |
acpi_os_free(*table); |
*table = NULL; |
*table_length = 0; |
return (AE_ERROR); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_read_table_from_file |
* |
* PARAMETERS: filename - File where table is located |
* table - Where a pointer to the table is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get an ACPI table from a file |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table) |
{ |
FILE *file; |
u32 file_size; |
u32 table_length; |
acpi_status status = AE_ERROR; |
/* Open the file, get current size */ |
file = fopen(filename, "rb"); |
if (!file) { |
perror("Could not open input file"); |
if (errno == ENOENT) { |
return (AE_NOT_EXIST); |
} |
return (status); |
} |
file_size = cm_get_file_size(file); |
if (file_size == ACPI_UINT32_MAX) { |
goto exit; |
} |
/* Get the entire file */ |
fprintf(stderr, |
"Reading ACPI table from file %12s - Length %.8u (0x%06X)\n", |
filename, file_size, file_size); |
status = acpi_ut_read_table(file, table, &table_length); |
if (ACPI_FAILURE(status)) { |
acpi_os_printf("Could not get table from the file\n"); |
} |
exit: |
fclose(file); |
return (status); |
} |
#endif |
/drivers/acpi/acpica/utglobal.c |
---|
0,0 → 1,230 |
/****************************************************************************** |
* |
* Module Name: utglobal - Global variables for the ACPI subsystem |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#define DEFINE_ACPI_GLOBALS |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utglobal") |
/******************************************************************************* |
* |
* Static global variable initialization. |
* |
******************************************************************************/ |
/* Various state name strings */ |
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { |
"\\_S0_", |
"\\_S1_", |
"\\_S2_", |
"\\_S3_", |
"\\_S4_", |
"\\_S5_" |
}; |
const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS] = { |
"_S0W", |
"_S1W", |
"_S2W", |
"_S3W", |
"_S4W" |
}; |
const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS] = { |
"_S1D", |
"_S2D", |
"_S3D", |
"_S4D" |
}; |
/******************************************************************************* |
* |
* Namespace globals |
* |
******************************************************************************/ |
/* |
* Predefined ACPI Names (Built-in to the Interpreter) |
* |
* NOTES: |
* 1) _SB_ is defined to be a device to allow \_SB_._INI to be run |
* during the initialization sequence. |
* 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to |
* perform a Notify() operation on it. 09/2010: Changed to type Device. |
* This still allows notifies, but does not confuse host code that |
* searches for valid thermal_zone objects. |
*/ |
const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = { |
{"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL}, |
{"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, |
{"_SB_", ACPI_TYPE_DEVICE, NULL}, |
{"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, |
{"_TZ_", ACPI_TYPE_DEVICE, NULL}, |
/* |
* March, 2015: |
* The _REV object is in the process of being deprecated, because |
* other ACPI implementations permanently return 2. Thus, it |
* has little or no value. Return 2 for compatibility with |
* other ACPI implementations. |
*/ |
{"_REV", ACPI_TYPE_INTEGER, ACPI_CAST_PTR(char, 2)}, |
{"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, |
{"_GL_", ACPI_TYPE_MUTEX, ACPI_CAST_PTR(char, 1)}, |
#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) |
{"_OSI", ACPI_TYPE_METHOD, ACPI_CAST_PTR(char, 1)}, |
#endif |
/* Table terminator */ |
{NULL, ACPI_TYPE_ANY, NULL} |
}; |
#if (!ACPI_REDUCED_HARDWARE) |
/****************************************************************************** |
* |
* Event and Hardware globals |
* |
******************************************************************************/ |
struct acpi_bit_register_info acpi_gbl_bit_register_info[ACPI_NUM_BITREG] = { |
/* Name Parent Register Register Bit Position Register Bit Mask */ |
/* ACPI_BITREG_TIMER_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_TIMER_STATUS, |
ACPI_BITMASK_TIMER_STATUS}, |
/* ACPI_BITREG_BUS_MASTER_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_BUS_MASTER_STATUS, |
ACPI_BITMASK_BUS_MASTER_STATUS}, |
/* ACPI_BITREG_GLOBAL_LOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_GLOBAL_LOCK_STATUS, |
ACPI_BITMASK_GLOBAL_LOCK_STATUS}, |
/* ACPI_BITREG_POWER_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_POWER_BUTTON_STATUS, |
ACPI_BITMASK_POWER_BUTTON_STATUS}, |
/* ACPI_BITREG_SLEEP_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_SLEEP_BUTTON_STATUS, |
ACPI_BITMASK_SLEEP_BUTTON_STATUS}, |
/* ACPI_BITREG_RT_CLOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_RT_CLOCK_STATUS, |
ACPI_BITMASK_RT_CLOCK_STATUS}, |
/* ACPI_BITREG_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_WAKE_STATUS, |
ACPI_BITMASK_WAKE_STATUS}, |
/* ACPI_BITREG_PCIEXP_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, |
ACPI_BITPOSITION_PCIEXP_WAKE_STATUS, |
ACPI_BITMASK_PCIEXP_WAKE_STATUS}, |
/* ACPI_BITREG_TIMER_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, |
ACPI_BITPOSITION_TIMER_ENABLE, |
ACPI_BITMASK_TIMER_ENABLE}, |
/* ACPI_BITREG_GLOBAL_LOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, |
ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE, |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, |
/* ACPI_BITREG_POWER_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, |
ACPI_BITPOSITION_POWER_BUTTON_ENABLE, |
ACPI_BITMASK_POWER_BUTTON_ENABLE}, |
/* ACPI_BITREG_SLEEP_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, |
ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE, |
ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, |
/* ACPI_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, |
ACPI_BITPOSITION_RT_CLOCK_ENABLE, |
ACPI_BITMASK_RT_CLOCK_ENABLE}, |
/* ACPI_BITREG_PCIEXP_WAKE_DISABLE */ {ACPI_REGISTER_PM1_ENABLE, |
ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE, |
ACPI_BITMASK_PCIEXP_WAKE_DISABLE}, |
/* ACPI_BITREG_SCI_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, |
ACPI_BITPOSITION_SCI_ENABLE, |
ACPI_BITMASK_SCI_ENABLE}, |
/* ACPI_BITREG_BUS_MASTER_RLD */ {ACPI_REGISTER_PM1_CONTROL, |
ACPI_BITPOSITION_BUS_MASTER_RLD, |
ACPI_BITMASK_BUS_MASTER_RLD}, |
/* ACPI_BITREG_GLOBAL_LOCK_RELEASE */ {ACPI_REGISTER_PM1_CONTROL, |
ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE, |
ACPI_BITMASK_GLOBAL_LOCK_RELEASE}, |
/* ACPI_BITREG_SLEEP_TYPE */ {ACPI_REGISTER_PM1_CONTROL, |
ACPI_BITPOSITION_SLEEP_TYPE, |
ACPI_BITMASK_SLEEP_TYPE}, |
/* ACPI_BITREG_SLEEP_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, |
ACPI_BITPOSITION_SLEEP_ENABLE, |
ACPI_BITMASK_SLEEP_ENABLE}, |
/* ACPI_BITREG_ARB_DIS */ {ACPI_REGISTER_PM2_CONTROL, |
ACPI_BITPOSITION_ARB_DISABLE, |
ACPI_BITMASK_ARB_DISABLE} |
}; |
struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] = { |
/* ACPI_EVENT_PMTIMER */ {ACPI_BITREG_TIMER_STATUS, |
ACPI_BITREG_TIMER_ENABLE, |
ACPI_BITMASK_TIMER_STATUS, |
ACPI_BITMASK_TIMER_ENABLE}, |
/* ACPI_EVENT_GLOBAL */ {ACPI_BITREG_GLOBAL_LOCK_STATUS, |
ACPI_BITREG_GLOBAL_LOCK_ENABLE, |
ACPI_BITMASK_GLOBAL_LOCK_STATUS, |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, |
/* ACPI_EVENT_POWER_BUTTON */ {ACPI_BITREG_POWER_BUTTON_STATUS, |
ACPI_BITREG_POWER_BUTTON_ENABLE, |
ACPI_BITMASK_POWER_BUTTON_STATUS, |
ACPI_BITMASK_POWER_BUTTON_ENABLE}, |
/* ACPI_EVENT_SLEEP_BUTTON */ {ACPI_BITREG_SLEEP_BUTTON_STATUS, |
ACPI_BITREG_SLEEP_BUTTON_ENABLE, |
ACPI_BITMASK_SLEEP_BUTTON_STATUS, |
ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, |
/* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, |
ACPI_BITREG_RT_CLOCK_ENABLE, |
ACPI_BITMASK_RT_CLOCK_STATUS, |
ACPI_BITMASK_RT_CLOCK_ENABLE}, |
}; |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/* Public globals */ |
ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) |
ACPI_EXPORT_SYMBOL(acpi_dbg_level) |
ACPI_EXPORT_SYMBOL(acpi_dbg_layer) |
ACPI_EXPORT_SYMBOL(acpi_gpe_count) |
ACPI_EXPORT_SYMBOL(acpi_current_gpe_count) |
/drivers/acpi/acpica/uthex.c |
---|
0,0 → 1,100 |
/****************************************************************************** |
* |
* Module Name: uthex -- Hex/ASCII support functions |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_COMPILER |
ACPI_MODULE_NAME("uthex") |
/* Hex to ASCII conversion table */ |
static char acpi_gbl_hex_to_ascii[] = { |
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', |
'E', 'F' |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_hex_to_ascii_char |
* |
* PARAMETERS: integer - Contains the hex digit |
* position - bit position of the digit within the |
* integer (multiple of 4) |
* |
* RETURN: The converted Ascii character |
* |
* DESCRIPTION: Convert a hex digit to an Ascii character |
* |
******************************************************************************/ |
char acpi_ut_hex_to_ascii_char(u64 integer, u32 position) |
{ |
return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_ascii_char_to_hex |
* |
* PARAMETERS: hex_char - Hex character in Ascii |
* |
* RETURN: The binary value of the ascii/hex character |
* |
* DESCRIPTION: Perform ascii-to-hex translation |
* |
******************************************************************************/ |
u8 acpi_ut_ascii_char_to_hex(int hex_char) |
{ |
if (hex_char <= 0x39) { |
return ((u8)(hex_char - 0x30)); |
} |
if (hex_char <= 0x46) { |
return ((u8)(hex_char - 0x37)); |
} |
return ((u8)(hex_char - 0x57)); |
} |
/drivers/acpi/acpica/utids.c |
---|
0,0 → 1,506 |
/****************************************************************************** |
* |
* Module Name: utids - support for device Ids - HID, UID, CID, SUB, CLS |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acinterp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utids") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_execute_HID |
* |
* PARAMETERS: device_node - Node for the device |
* return_id - Where the string HID is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Executes the _HID control method that returns the hardware |
* ID of the device. The HID is either an 32-bit encoded EISAID |
* Integer or a String. A string is always returned. An EISAID |
* is converted to a string. |
* |
* NOTE: Internal function, no parameter validation |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_execute_HID(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id **return_id) |
{ |
union acpi_operand_object *obj_desc; |
struct acpi_pnp_device_id *hid; |
u32 length; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_execute_HID); |
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID, |
ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, |
&obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get the size of the String to be returned, includes null terminator */ |
if (obj_desc->common.type == ACPI_TYPE_INTEGER) { |
length = ACPI_EISAID_STRING_SIZE; |
} else { |
length = obj_desc->string.length + 1; |
} |
/* Allocate a buffer for the HID */ |
hid = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + |
(acpi_size) length); |
if (!hid) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Area for the string starts after PNP_DEVICE_ID struct */ |
hid->string = |
ACPI_ADD_PTR(char, hid, sizeof(struct acpi_pnp_device_id)); |
/* Convert EISAID to a string or simply copy existing string */ |
if (obj_desc->common.type == ACPI_TYPE_INTEGER) { |
acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value); |
} else { |
strcpy(hid->string, obj_desc->string.pointer); |
} |
hid->length = length; |
*return_id = hid; |
cleanup: |
/* On exit, we must delete the return object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_execute_SUB |
* |
* PARAMETERS: device_node - Node for the device |
* return_id - Where the _SUB is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Executes the _SUB control method that returns the subsystem |
* ID of the device. The _SUB value is always a string containing |
* either a valid PNP or ACPI ID. |
* |
* NOTE: Internal function, no parameter validation |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id **return_id) |
{ |
union acpi_operand_object *obj_desc; |
struct acpi_pnp_device_id *sub; |
u32 length; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_execute_SUB); |
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__SUB, |
ACPI_BTYPE_STRING, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get the size of the String to be returned, includes null terminator */ |
length = obj_desc->string.length + 1; |
/* Allocate a buffer for the SUB */ |
sub = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + |
(acpi_size) length); |
if (!sub) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Area for the string starts after PNP_DEVICE_ID struct */ |
sub->string = |
ACPI_ADD_PTR(char, sub, sizeof(struct acpi_pnp_device_id)); |
/* Simply copy existing string */ |
strcpy(sub->string, obj_desc->string.pointer); |
sub->length = length; |
*return_id = sub; |
cleanup: |
/* On exit, we must delete the return object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_execute_UID |
* |
* PARAMETERS: device_node - Node for the device |
* return_id - Where the string UID is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Executes the _UID control method that returns the unique |
* ID of the device. The UID is either a 64-bit Integer (NOT an |
* EISAID) or a string. Always returns a string. A 64-bit integer |
* is converted to a decimal string. |
* |
* NOTE: Internal function, no parameter validation |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_execute_UID(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id **return_id) |
{ |
union acpi_operand_object *obj_desc; |
struct acpi_pnp_device_id *uid; |
u32 length; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_execute_UID); |
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID, |
ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, |
&obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get the size of the String to be returned, includes null terminator */ |
if (obj_desc->common.type == ACPI_TYPE_INTEGER) { |
length = ACPI_MAX64_DECIMAL_DIGITS + 1; |
} else { |
length = obj_desc->string.length + 1; |
} |
/* Allocate a buffer for the UID */ |
uid = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + |
(acpi_size) length); |
if (!uid) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Area for the string starts after PNP_DEVICE_ID struct */ |
uid->string = |
ACPI_ADD_PTR(char, uid, sizeof(struct acpi_pnp_device_id)); |
/* Convert an Integer to string, or just copy an existing string */ |
if (obj_desc->common.type == ACPI_TYPE_INTEGER) { |
acpi_ex_integer_to_string(uid->string, obj_desc->integer.value); |
} else { |
strcpy(uid->string, obj_desc->string.pointer); |
} |
uid->length = length; |
*return_id = uid; |
cleanup: |
/* On exit, we must delete the return object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_execute_CID |
* |
* PARAMETERS: device_node - Node for the device |
* return_cid_list - Where the CID list is returned |
* |
* RETURN: Status, list of CID strings |
* |
* DESCRIPTION: Executes the _CID control method that returns one or more |
* compatible hardware IDs for the device. |
* |
* NOTE: Internal function, no parameter validation |
* |
* A _CID method can return either a single compatible ID or a package of |
* compatible IDs. Each compatible ID can be one of the following: |
* 1) Integer (32 bit compressed EISA ID) or |
* 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") |
* |
* The Integer CIDs are converted to string format by this function. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_execute_CID(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id_list **return_cid_list) |
{ |
union acpi_operand_object **cid_objects; |
union acpi_operand_object *obj_desc; |
struct acpi_pnp_device_id_list *cid_list; |
char *next_id_string; |
u32 string_area_size; |
u32 length; |
u32 cid_list_size; |
acpi_status status; |
u32 count; |
u32 i; |
ACPI_FUNCTION_TRACE(ut_execute_CID); |
/* Evaluate the _CID method for this device */ |
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID, |
ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING |
| ACPI_BTYPE_PACKAGE, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Get the count and size of the returned _CIDs. _CID can return either |
* a Package of Integers/Strings or a single Integer or String. |
* Note: This section also validates that all CID elements are of the |
* correct type (Integer or String). |
*/ |
if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { |
count = obj_desc->package.count; |
cid_objects = obj_desc->package.elements; |
} else { /* Single Integer or String CID */ |
count = 1; |
cid_objects = &obj_desc; |
} |
string_area_size = 0; |
for (i = 0; i < count; i++) { |
/* String lengths include null terminator */ |
switch (cid_objects[i]->common.type) { |
case ACPI_TYPE_INTEGER: |
string_area_size += ACPI_EISAID_STRING_SIZE; |
break; |
case ACPI_TYPE_STRING: |
string_area_size += cid_objects[i]->string.length + 1; |
break; |
default: |
status = AE_TYPE; |
goto cleanup; |
} |
} |
/* |
* Now that we know the length of the CIDs, allocate return buffer: |
* 1) Size of the base structure + |
* 2) Size of the CID PNP_DEVICE_ID array + |
* 3) Size of the actual CID strings |
*/ |
cid_list_size = sizeof(struct acpi_pnp_device_id_list) + |
((count - 1) * sizeof(struct acpi_pnp_device_id)) + |
string_area_size; |
cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size); |
if (!cid_list) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Area for CID strings starts after the CID PNP_DEVICE_ID array */ |
next_id_string = ACPI_CAST_PTR(char, cid_list->ids) + |
((acpi_size) count * sizeof(struct acpi_pnp_device_id)); |
/* Copy/convert the CIDs to the return buffer */ |
for (i = 0; i < count; i++) { |
if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) { |
/* Convert the Integer (EISAID) CID to a string */ |
acpi_ex_eisa_id_to_string(next_id_string, |
cid_objects[i]->integer. |
value); |
length = ACPI_EISAID_STRING_SIZE; |
} else { /* ACPI_TYPE_STRING */ |
/* Copy the String CID from the returned object */ |
strcpy(next_id_string, cid_objects[i]->string.pointer); |
length = cid_objects[i]->string.length + 1; |
} |
cid_list->ids[i].string = next_id_string; |
cid_list->ids[i].length = length; |
next_id_string += length; |
} |
/* Finish the CID list */ |
cid_list->count = count; |
cid_list->list_size = cid_list_size; |
*return_cid_list = cid_list; |
cleanup: |
/* On exit, we must delete the _CID return object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_execute_CLS |
* |
* PARAMETERS: device_node - Node for the device |
* return_id - Where the _CLS is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Executes the _CLS control method that returns PCI-defined |
* class code of the device. The _CLS value is always a package |
* containing PCI class information as a list of integers. |
* The returned string has format "BBSSPP", where: |
* BB = Base-class code |
* SS = Sub-class code |
* PP = Programming Interface code |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_execute_CLS(struct acpi_namespace_node *device_node, |
struct acpi_pnp_device_id **return_id) |
{ |
union acpi_operand_object *obj_desc; |
union acpi_operand_object **cls_objects; |
u32 count; |
struct acpi_pnp_device_id *cls; |
u32 length; |
acpi_status status; |
u8 class_code[3] = { 0, 0, 0 }; |
ACPI_FUNCTION_TRACE(ut_execute_CLS); |
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CLS, |
ACPI_BTYPE_PACKAGE, &obj_desc); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Get the size of the String to be returned, includes null terminator */ |
length = ACPI_PCICLS_STRING_SIZE; |
cls_objects = obj_desc->package.elements; |
count = obj_desc->package.count; |
if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { |
if (count > 0 |
&& cls_objects[0]->common.type == ACPI_TYPE_INTEGER) { |
class_code[0] = (u8)cls_objects[0]->integer.value; |
} |
if (count > 1 |
&& cls_objects[1]->common.type == ACPI_TYPE_INTEGER) { |
class_code[1] = (u8)cls_objects[1]->integer.value; |
} |
if (count > 2 |
&& cls_objects[2]->common.type == ACPI_TYPE_INTEGER) { |
class_code[2] = (u8)cls_objects[2]->integer.value; |
} |
} |
/* Allocate a buffer for the CLS */ |
cls = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + |
(acpi_size) length); |
if (!cls) { |
status = AE_NO_MEMORY; |
goto cleanup; |
} |
/* Area for the string starts after PNP_DEVICE_ID struct */ |
cls->string = |
ACPI_ADD_PTR(char, cls, sizeof(struct acpi_pnp_device_id)); |
/* Simply copy existing string */ |
acpi_ex_pci_cls_to_string(cls->string, class_code); |
cls->length = length; |
*return_id = cls; |
cleanup: |
/* On exit, we must delete the return object */ |
acpi_ut_remove_reference(obj_desc); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/utinit.c |
---|
0,0 → 1,325 |
/****************************************************************************** |
* |
* Module Name: utinit - Common ACPI subsystem initialization |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#include "acevents.h" |
#include "actables.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utinit") |
/* Local prototypes */ |
static void acpi_ut_terminate(void); |
#if (!ACPI_REDUCED_HARDWARE) |
static void acpi_ut_free_gpe_lists(void); |
#else |
#define acpi_ut_free_gpe_lists() |
#endif /* !ACPI_REDUCED_HARDWARE */ |
#if (!ACPI_REDUCED_HARDWARE) |
/****************************************************************************** |
* |
* FUNCTION: acpi_ut_free_gpe_lists |
* |
* PARAMETERS: none |
* |
* RETURN: none |
* |
* DESCRIPTION: Free global GPE lists |
* |
******************************************************************************/ |
static void acpi_ut_free_gpe_lists(void) |
{ |
struct acpi_gpe_block_info *gpe_block; |
struct acpi_gpe_block_info *next_gpe_block; |
struct acpi_gpe_xrupt_info *gpe_xrupt_info; |
struct acpi_gpe_xrupt_info *next_gpe_xrupt_info; |
/* Free global GPE blocks and related info structures */ |
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; |
while (gpe_xrupt_info) { |
gpe_block = gpe_xrupt_info->gpe_block_list_head; |
while (gpe_block) { |
next_gpe_block = gpe_block->next; |
ACPI_FREE(gpe_block->event_info); |
ACPI_FREE(gpe_block->register_info); |
ACPI_FREE(gpe_block); |
gpe_block = next_gpe_block; |
} |
next_gpe_xrupt_info = gpe_xrupt_info->next; |
ACPI_FREE(gpe_xrupt_info); |
gpe_xrupt_info = next_gpe_xrupt_info; |
} |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_init_globals |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize ACPICA globals. All globals that require specific |
* initialization should be initialized here. This allows for |
* a warm restart. |
* |
******************************************************************************/ |
acpi_status acpi_ut_init_globals(void) |
{ |
acpi_status status; |
u32 i; |
ACPI_FUNCTION_TRACE(ut_init_globals); |
/* Create all memory caches */ |
status = acpi_ut_create_caches(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Address Range lists */ |
for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { |
acpi_gbl_address_range_list[i] = NULL; |
} |
/* Mutex locked flags */ |
for (i = 0; i < ACPI_NUM_MUTEX; i++) { |
acpi_gbl_mutex_info[i].mutex = NULL; |
acpi_gbl_mutex_info[i].thread_id = ACPI_MUTEX_NOT_ACQUIRED; |
acpi_gbl_mutex_info[i].use_count = 0; |
} |
for (i = 0; i < ACPI_NUM_OWNERID_MASKS; i++) { |
acpi_gbl_owner_id_mask[i] = 0; |
} |
/* Last owner_ID is never valid */ |
acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS - 1] = 0x80000000; |
/* Event counters */ |
acpi_method_count = 0; |
acpi_sci_count = 0; |
acpi_gpe_count = 0; |
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
acpi_fixed_event_count[i] = 0; |
} |
#if (!ACPI_REDUCED_HARDWARE) |
/* GPE/SCI support */ |
acpi_gbl_all_gpes_initialized = FALSE; |
acpi_gbl_gpe_xrupt_list_head = NULL; |
acpi_gbl_gpe_fadt_blocks[0] = NULL; |
acpi_gbl_gpe_fadt_blocks[1] = NULL; |
acpi_current_gpe_count = 0; |
acpi_gbl_global_event_handler = NULL; |
acpi_gbl_sci_handler_list = NULL; |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/* Global handlers */ |
acpi_gbl_global_notify[0].handler = NULL; |
acpi_gbl_global_notify[1].handler = NULL; |
acpi_gbl_exception_handler = NULL; |
acpi_gbl_init_handler = NULL; |
acpi_gbl_table_handler = NULL; |
acpi_gbl_interface_handler = NULL; |
/* Global Lock support */ |
acpi_gbl_global_lock_semaphore = NULL; |
acpi_gbl_global_lock_mutex = NULL; |
acpi_gbl_global_lock_acquired = FALSE; |
acpi_gbl_global_lock_handle = 0; |
acpi_gbl_global_lock_present = FALSE; |
/* Miscellaneous variables */ |
acpi_gbl_DSDT = NULL; |
acpi_gbl_cm_single_step = FALSE; |
acpi_gbl_shutdown = FALSE; |
acpi_gbl_ns_lookup_count = 0; |
acpi_gbl_ps_find_count = 0; |
acpi_gbl_acpi_hardware_present = TRUE; |
acpi_gbl_last_owner_id_index = 0; |
acpi_gbl_next_owner_id_offset = 0; |
acpi_gbl_debugger_configuration = DEBUGGER_THREADING; |
acpi_gbl_osi_mutex = NULL; |
acpi_gbl_reg_methods_executed = FALSE; |
acpi_gbl_max_loop_iterations = 0xFFFF; |
/* Hardware oriented */ |
acpi_gbl_events_initialized = FALSE; |
acpi_gbl_system_awake_and_running = TRUE; |
/* Namespace */ |
acpi_gbl_module_code_list = NULL; |
acpi_gbl_root_node = NULL; |
acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; |
acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED; |
acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE; |
acpi_gbl_root_node_struct.parent = NULL; |
acpi_gbl_root_node_struct.child = NULL; |
acpi_gbl_root_node_struct.peer = NULL; |
acpi_gbl_root_node_struct.object = NULL; |
#ifdef ACPI_DISASSEMBLER |
acpi_gbl_external_list = NULL; |
acpi_gbl_num_external_methods = 0; |
acpi_gbl_resolved_external_methods = 0; |
#endif |
#ifdef ACPI_DEBUG_OUTPUT |
acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX); |
#endif |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
acpi_gbl_display_final_mem_stats = FALSE; |
acpi_gbl_disable_mem_tracking = FALSE; |
#endif |
return_ACPI_STATUS(AE_OK); |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ut_terminate |
* |
* PARAMETERS: none |
* |
* RETURN: none |
* |
* DESCRIPTION: Free global memory |
* |
******************************************************************************/ |
static void acpi_ut_terminate(void) |
{ |
ACPI_FUNCTION_TRACE(ut_terminate); |
acpi_ut_free_gpe_lists(); |
acpi_ut_delete_address_lists(); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_subsystem_shutdown |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Shutdown the various components. Do not delete the mutex |
* objects here, because the AML debugger may be still running. |
* |
******************************************************************************/ |
void acpi_ut_subsystem_shutdown(void) |
{ |
ACPI_FUNCTION_TRACE(ut_subsystem_shutdown); |
/* Just exit if subsystem is already shutdown */ |
if (acpi_gbl_shutdown) { |
ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated")); |
return_VOID; |
} |
/* Subsystem appears active, go ahead and shut it down */ |
acpi_gbl_shutdown = TRUE; |
acpi_gbl_startup_flags = 0; |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n")); |
#ifndef ACPI_ASL_COMPILER |
/* Close the acpi_event Handling */ |
acpi_ev_terminate(); |
/* Delete any dynamic _OSI interfaces */ |
acpi_ut_interface_terminate(); |
#endif |
/* Close the Namespace */ |
acpi_ns_terminate(); |
/* Delete the ACPI tables */ |
acpi_tb_terminate(); |
/* Close the globals */ |
acpi_ut_terminate(); |
/* Purge the local caches */ |
(void)acpi_ut_delete_caches(); |
return_VOID; |
} |
/drivers/acpi/acpica/utlock.c |
---|
0,0 → 1,175 |
/****************************************************************************** |
* |
* Module Name: utlock - Reader/Writer lock interfaces |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utlock") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_rw_lock |
* acpi_ut_delete_rw_lock |
* |
* PARAMETERS: lock - Pointer to a valid RW lock |
* |
* RETURN: Status |
* |
* DESCRIPTION: Reader/writer lock creation and deletion interfaces. |
* |
******************************************************************************/ |
acpi_status acpi_ut_create_rw_lock(struct acpi_rw_lock *lock) |
{ |
acpi_status status; |
lock->num_readers = 0; |
status = acpi_os_create_mutex(&lock->reader_mutex); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = acpi_os_create_mutex(&lock->writer_mutex); |
return (status); |
} |
void acpi_ut_delete_rw_lock(struct acpi_rw_lock *lock) |
{ |
acpi_os_delete_mutex(lock->reader_mutex); |
acpi_os_delete_mutex(lock->writer_mutex); |
lock->num_readers = 0; |
lock->reader_mutex = NULL; |
lock->writer_mutex = NULL; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_acquire_read_lock |
* acpi_ut_release_read_lock |
* |
* PARAMETERS: lock - Pointer to a valid RW lock |
* |
* RETURN: Status |
* |
* DESCRIPTION: Reader interfaces for reader/writer locks. On acquisition, |
* only the first reader acquires the write mutex. On release, |
* only the last reader releases the write mutex. Although this |
* algorithm can in theory starve writers, this should not be a |
* problem with ACPICA since the subsystem is infrequently used |
* in comparison to (for example) an I/O system. |
* |
******************************************************************************/ |
acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock) |
{ |
acpi_status status; |
status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Acquire the write lock only for the first reader */ |
lock->num_readers++; |
if (lock->num_readers == 1) { |
status = |
acpi_os_acquire_mutex(lock->writer_mutex, |
ACPI_WAIT_FOREVER); |
} |
acpi_os_release_mutex(lock->reader_mutex); |
return (status); |
} |
acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock) |
{ |
acpi_status status; |
status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Release the write lock only for the very last reader */ |
lock->num_readers--; |
if (lock->num_readers == 0) { |
acpi_os_release_mutex(lock->writer_mutex); |
} |
acpi_os_release_mutex(lock->reader_mutex); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_acquire_write_lock |
* acpi_ut_release_write_lock |
* |
* PARAMETERS: lock - Pointer to a valid RW lock |
* |
* RETURN: Status |
* |
* DESCRIPTION: Writer interfaces for reader/writer locks. Simply acquire or |
* release the writer mutex associated with the lock. Acquisition |
* of the lock is fully exclusive and will block all readers and |
* writers until it is released. |
* |
******************************************************************************/ |
acpi_status acpi_ut_acquire_write_lock(struct acpi_rw_lock *lock) |
{ |
acpi_status status; |
status = acpi_os_acquire_mutex(lock->writer_mutex, ACPI_WAIT_FOREVER); |
return (status); |
} |
void acpi_ut_release_write_lock(struct acpi_rw_lock *lock) |
{ |
acpi_os_release_mutex(lock->writer_mutex); |
} |
/drivers/acpi/acpica/utmath.c |
---|
0,0 → 1,324 |
/******************************************************************************* |
* |
* Module Name: utmath - Integer math support routines |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utmath") |
/* |
* Optional support for 64-bit double-precision integer divide. This code |
* is configurable and is implemented in order to support 32-bit kernel |
* environments where a 64-bit double-precision math library is not available. |
* |
* Support for a more normal 64-bit divide/modulo (with check for a divide- |
* by-zero) appears after this optional section of code. |
*/ |
#ifndef ACPI_USE_NATIVE_DIVIDE |
/* Structures used only for 64-bit divide */ |
typedef struct uint64_struct { |
u32 lo; |
u32 hi; |
} uint64_struct; |
typedef union uint64_overlay { |
u64 full; |
struct uint64_struct part; |
} uint64_overlay; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_short_divide |
* |
* PARAMETERS: dividend - 64-bit dividend |
* divisor - 32-bit divisor |
* out_quotient - Pointer to where the quotient is returned |
* out_remainder - Pointer to where the remainder is returned |
* |
* RETURN: Status (Checks for divide-by-zero) |
* |
* DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits) |
* divide and modulo. The result is a 64-bit quotient and a |
* 32-bit remainder. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_short_divide(u64 dividend, |
u32 divisor, u64 *out_quotient, u32 *out_remainder) |
{ |
union uint64_overlay dividend_ovl; |
union uint64_overlay quotient; |
u32 remainder32; |
ACPI_FUNCTION_TRACE(ut_short_divide); |
/* Always check for a zero divisor */ |
if (divisor == 0) { |
ACPI_ERROR((AE_INFO, "Divide by zero")); |
return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); |
} |
dividend_ovl.full = dividend; |
/* |
* The quotient is 64 bits, the remainder is always 32 bits, |
* and is generated by the second divide. |
*/ |
ACPI_DIV_64_BY_32(0, dividend_ovl.part.hi, divisor, |
quotient.part.hi, remainder32); |
ACPI_DIV_64_BY_32(remainder32, dividend_ovl.part.lo, divisor, |
quotient.part.lo, remainder32); |
/* Return only what was requested */ |
if (out_quotient) { |
*out_quotient = quotient.full; |
} |
if (out_remainder) { |
*out_remainder = remainder32; |
} |
return_ACPI_STATUS(AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_divide |
* |
* PARAMETERS: in_dividend - Dividend |
* in_divisor - Divisor |
* out_quotient - Pointer to where the quotient is returned |
* out_remainder - Pointer to where the remainder is returned |
* |
* RETURN: Status (Checks for divide-by-zero) |
* |
* DESCRIPTION: Perform a divide and modulo. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_divide(u64 in_dividend, |
u64 in_divisor, u64 *out_quotient, u64 *out_remainder) |
{ |
union uint64_overlay dividend; |
union uint64_overlay divisor; |
union uint64_overlay quotient; |
union uint64_overlay remainder; |
union uint64_overlay normalized_dividend; |
union uint64_overlay normalized_divisor; |
u32 partial1; |
union uint64_overlay partial2; |
union uint64_overlay partial3; |
ACPI_FUNCTION_TRACE(ut_divide); |
/* Always check for a zero divisor */ |
if (in_divisor == 0) { |
ACPI_ERROR((AE_INFO, "Divide by zero")); |
return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); |
} |
divisor.full = in_divisor; |
dividend.full = in_dividend; |
if (divisor.part.hi == 0) { |
/* |
* 1) Simplest case is where the divisor is 32 bits, we can |
* just do two divides |
*/ |
remainder.part.hi = 0; |
/* |
* The quotient is 64 bits, the remainder is always 32 bits, |
* and is generated by the second divide. |
*/ |
ACPI_DIV_64_BY_32(0, dividend.part.hi, divisor.part.lo, |
quotient.part.hi, partial1); |
ACPI_DIV_64_BY_32(partial1, dividend.part.lo, divisor.part.lo, |
quotient.part.lo, remainder.part.lo); |
} |
else { |
/* |
* 2) The general case where the divisor is a full 64 bits |
* is more difficult |
*/ |
quotient.part.hi = 0; |
normalized_dividend = dividend; |
normalized_divisor = divisor; |
/* Normalize the operands (shift until the divisor is < 32 bits) */ |
do { |
ACPI_SHIFT_RIGHT_64(normalized_divisor.part.hi, |
normalized_divisor.part.lo); |
ACPI_SHIFT_RIGHT_64(normalized_dividend.part.hi, |
normalized_dividend.part.lo); |
} while (normalized_divisor.part.hi != 0); |
/* Partial divide */ |
ACPI_DIV_64_BY_32(normalized_dividend.part.hi, |
normalized_dividend.part.lo, |
normalized_divisor.part.lo, |
quotient.part.lo, partial1); |
/* |
* The quotient is always 32 bits, and simply requires adjustment. |
* The 64-bit remainder must be generated. |
*/ |
partial1 = quotient.part.lo * divisor.part.hi; |
partial2.full = (u64) quotient.part.lo * divisor.part.lo; |
partial3.full = (u64) partial2.part.hi + partial1; |
remainder.part.hi = partial3.part.lo; |
remainder.part.lo = partial2.part.lo; |
if (partial3.part.hi == 0) { |
if (partial3.part.lo >= dividend.part.hi) { |
if (partial3.part.lo == dividend.part.hi) { |
if (partial2.part.lo > dividend.part.lo) { |
quotient.part.lo--; |
remainder.full -= divisor.full; |
} |
} else { |
quotient.part.lo--; |
remainder.full -= divisor.full; |
} |
} |
remainder.full = remainder.full - dividend.full; |
remainder.part.hi = (u32) - ((s32) remainder.part.hi); |
remainder.part.lo = (u32) - ((s32) remainder.part.lo); |
if (remainder.part.lo) { |
remainder.part.hi--; |
} |
} |
} |
/* Return only what was requested */ |
if (out_quotient) { |
*out_quotient = quotient.full; |
} |
if (out_remainder) { |
*out_remainder = remainder.full; |
} |
return_ACPI_STATUS(AE_OK); |
} |
#else |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_short_divide, acpi_ut_divide |
* |
* PARAMETERS: See function headers above |
* |
* DESCRIPTION: Native versions of the ut_divide functions. Use these if either |
* 1) The target is a 64-bit platform and therefore 64-bit |
* integer math is supported directly by the machine. |
* 2) The target is a 32-bit or 16-bit platform, and the |
* double-precision integer math library is available to |
* perform the divide. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_short_divide(u64 in_dividend, |
u32 divisor, u64 *out_quotient, u32 *out_remainder) |
{ |
ACPI_FUNCTION_TRACE(ut_short_divide); |
/* Always check for a zero divisor */ |
if (divisor == 0) { |
ACPI_ERROR((AE_INFO, "Divide by zero")); |
return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); |
} |
/* Return only what was requested */ |
if (out_quotient) { |
*out_quotient = in_dividend / divisor; |
} |
if (out_remainder) { |
*out_remainder = (u32) (in_dividend % divisor); |
} |
return_ACPI_STATUS(AE_OK); |
} |
acpi_status |
acpi_ut_divide(u64 in_dividend, |
u64 in_divisor, u64 *out_quotient, u64 *out_remainder) |
{ |
ACPI_FUNCTION_TRACE(ut_divide); |
/* Always check for a zero divisor */ |
if (in_divisor == 0) { |
ACPI_ERROR((AE_INFO, "Divide by zero")); |
return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); |
} |
/* Return only what was requested */ |
if (out_quotient) { |
*out_quotient = in_dividend / in_divisor; |
} |
if (out_remainder) { |
*out_remainder = in_dividend % in_divisor; |
} |
return_ACPI_STATUS(AE_OK); |
} |
#endif |
/drivers/acpi/acpica/utmisc.c |
---|
0,0 → 1,412 |
/******************************************************************************* |
* |
* Module Name: utmisc - common utility procedures |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utmisc") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_is_pci_root_bridge |
* |
* PARAMETERS: id - The HID/CID in string format |
* |
* RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge |
* |
* DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. |
* |
******************************************************************************/ |
u8 acpi_ut_is_pci_root_bridge(char *id) |
{ |
/* |
* Check if this is a PCI root bridge. |
* ACPI 3.0+: check for a PCI Express root also. |
*/ |
if (!(strcmp(id, |
PCI_ROOT_HID_STRING)) || |
!(strcmp(id, PCI_EXPRESS_ROOT_HID_STRING))) { |
return (TRUE); |
} |
return (FALSE); |
} |
#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_NAMES_APP) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_is_aml_table |
* |
* PARAMETERS: table - An ACPI table |
* |
* RETURN: TRUE if table contains executable AML; FALSE otherwise |
* |
* DESCRIPTION: Check ACPI Signature for a table that contains AML code. |
* Currently, these are DSDT,SSDT,PSDT. All other table types are |
* data tables that do not contain AML code. |
* |
******************************************************************************/ |
u8 acpi_ut_is_aml_table(struct acpi_table_header *table) |
{ |
/* These are the only tables that contain executable AML */ |
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) || |
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) || |
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT) || |
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT)) { |
return (TRUE); |
} |
return (FALSE); |
} |
#endif |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_dword_byte_swap |
* |
* PARAMETERS: value - Value to be converted |
* |
* RETURN: u32 integer with bytes swapped |
* |
* DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) |
* |
******************************************************************************/ |
u32 acpi_ut_dword_byte_swap(u32 value) |
{ |
union { |
u32 value; |
u8 bytes[4]; |
} out; |
union { |
u32 value; |
u8 bytes[4]; |
} in; |
ACPI_FUNCTION_ENTRY(); |
in.value = value; |
out.bytes[0] = in.bytes[3]; |
out.bytes[1] = in.bytes[2]; |
out.bytes[2] = in.bytes[1]; |
out.bytes[3] = in.bytes[0]; |
return (out.value); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_set_integer_width |
* |
* PARAMETERS: Revision From DSDT header |
* |
* RETURN: None |
* |
* DESCRIPTION: Set the global integer bit width based upon the revision |
* of the DSDT. For Revision 1 and 0, Integers are 32 bits. |
* For Revision 2 and above, Integers are 64 bits. Yes, this |
* makes a difference. |
* |
******************************************************************************/ |
void acpi_ut_set_integer_width(u8 revision) |
{ |
if (revision < 2) { |
/* 32-bit case */ |
acpi_gbl_integer_bit_width = 32; |
acpi_gbl_integer_nybble_width = 8; |
acpi_gbl_integer_byte_width = 4; |
} else { |
/* 64-bit case (ACPI 2.0+) */ |
acpi_gbl_integer_bit_width = 64; |
acpi_gbl_integer_nybble_width = 16; |
acpi_gbl_integer_byte_width = 8; |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_update_state_and_push |
* |
* PARAMETERS: object - Object to be added to the new state |
* action - Increment/Decrement |
* state_list - List the state will be added to |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a new state and push it |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_create_update_state_and_push(union acpi_operand_object *object, |
u16 action, |
union acpi_generic_state **state_list) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_ENTRY(); |
/* Ignore null objects; these are expected */ |
if (!object) { |
return (AE_OK); |
} |
state = acpi_ut_create_update_state(object, action); |
if (!state) { |
return (AE_NO_MEMORY); |
} |
acpi_ut_push_generic_state(state_list, state); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_walk_package_tree |
* |
* PARAMETERS: source_object - The package to walk |
* target_object - Target object (if package is being copied) |
* walk_callback - Called once for each package element |
* context - Passed to the callback function |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walk through a package |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_walk_package_tree(union acpi_operand_object *source_object, |
void *target_object, |
acpi_pkg_callback walk_callback, void *context) |
{ |
acpi_status status = AE_OK; |
union acpi_generic_state *state_list = NULL; |
union acpi_generic_state *state; |
u32 this_index; |
union acpi_operand_object *this_source_obj; |
ACPI_FUNCTION_TRACE(ut_walk_package_tree); |
state = acpi_ut_create_pkg_state(source_object, target_object, 0); |
if (!state) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
while (state) { |
/* Get one element of the package */ |
this_index = state->pkg.index; |
this_source_obj = (union acpi_operand_object *) |
state->pkg.source_object->package.elements[this_index]; |
/* |
* Check for: |
* 1) An uninitialized package element. It is completely |
* legal to declare a package and leave it uninitialized |
* 2) Not an internal object - can be a namespace node instead |
* 3) Any type other than a package. Packages are handled in else |
* case below. |
*/ |
if ((!this_source_obj) || |
(ACPI_GET_DESCRIPTOR_TYPE(this_source_obj) != |
ACPI_DESC_TYPE_OPERAND) |
|| (this_source_obj->common.type != ACPI_TYPE_PACKAGE)) { |
status = |
walk_callback(ACPI_COPY_TYPE_SIMPLE, |
this_source_obj, state, context); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
state->pkg.index++; |
while (state->pkg.index >= |
state->pkg.source_object->package.count) { |
/* |
* We've handled all of the objects at this level, This means |
* that we have just completed a package. That package may |
* have contained one or more packages itself. |
* |
* Delete this state and pop the previous state (package). |
*/ |
acpi_ut_delete_generic_state(state); |
state = acpi_ut_pop_generic_state(&state_list); |
/* Finished when there are no more states */ |
if (!state) { |
/* |
* We have handled all of the objects in the top level |
* package just add the length of the package objects |
* and exit |
*/ |
return_ACPI_STATUS(AE_OK); |
} |
/* |
* Go back up a level and move the index past the just |
* completed package object. |
*/ |
state->pkg.index++; |
} |
} else { |
/* This is a subobject of type package */ |
status = |
walk_callback(ACPI_COPY_TYPE_PACKAGE, |
this_source_obj, state, context); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Push the current state and create a new one |
* The callback above returned a new target package object. |
*/ |
acpi_ut_push_generic_state(&state_list, state); |
state = acpi_ut_create_pkg_state(this_source_obj, |
state->pkg. |
this_target_obj, 0); |
if (!state) { |
/* Free any stacked Update State objects */ |
while (state_list) { |
state = |
acpi_ut_pop_generic_state |
(&state_list); |
acpi_ut_delete_generic_state(state); |
} |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
} |
} |
/* We should never get here */ |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
#ifdef ACPI_DEBUG_OUTPUT |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_display_init_pathname |
* |
* PARAMETERS: type - Object type of the node |
* obj_handle - Handle whose pathname will be displayed |
* path - Additional path string to be appended. |
* (NULL if no extra path) |
* |
* RETURN: acpi_status |
* |
* DESCRIPTION: Display full pathname of an object, DEBUG ONLY |
* |
******************************************************************************/ |
void |
acpi_ut_display_init_pathname(u8 type, |
struct acpi_namespace_node *obj_handle, |
char *path) |
{ |
acpi_status status; |
struct acpi_buffer buffer; |
ACPI_FUNCTION_ENTRY(); |
/* Only print the path if the appropriate debug level is enabled */ |
if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { |
return; |
} |
/* Get the full pathname to the node */ |
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); |
if (ACPI_FAILURE(status)) { |
return; |
} |
/* Print what we're doing */ |
switch (type) { |
case ACPI_TYPE_METHOD: |
acpi_os_printf("Executing "); |
break; |
default: |
acpi_os_printf("Initializing "); |
break; |
} |
/* Print the object type and pathname */ |
acpi_os_printf("%-12s %s", |
acpi_ut_get_type_name(type), (char *)buffer.pointer); |
/* Extra path is used to append names like _STA, _INI, etc. */ |
if (path) { |
acpi_os_printf(".%s", path); |
} |
acpi_os_printf("\n"); |
ACPI_FREE(buffer.pointer); |
} |
#endif |
/drivers/acpi/acpica/utmutex.c |
---|
0,0 → 1,381 |
/******************************************************************************* |
* |
* Module Name: utmutex - local mutex support |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utmutex") |
/* Local prototypes */ |
static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id); |
static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_mutex_initialize |
* |
* PARAMETERS: None. |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create the system mutex objects. This includes mutexes, |
* spin locks, and reader/writer locks. |
* |
******************************************************************************/ |
acpi_status acpi_ut_mutex_initialize(void) |
{ |
u32 i; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_mutex_initialize); |
/* Create each of the predefined mutex objects */ |
for (i = 0; i < ACPI_NUM_MUTEX; i++) { |
status = acpi_ut_create_mutex(i); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* Create the spinlocks for use at interrupt level or for speed */ |
status = acpi_os_create_lock (&acpi_gbl_gpe_lock); |
if (ACPI_FAILURE (status)) { |
return_ACPI_STATUS (status); |
} |
status = acpi_os_create_lock (&acpi_gbl_hardware_lock); |
if (ACPI_FAILURE (status)) { |
return_ACPI_STATUS (status); |
} |
status = acpi_os_create_lock(&acpi_gbl_reference_count_lock); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Mutex for _OSI support */ |
status = acpi_os_create_mutex(&acpi_gbl_osi_mutex); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Create the reader/writer lock for namespace access */ |
status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
#ifdef ACPI_DEBUGGER |
/* Debugger Support */ |
status = acpi_os_create_mutex(&acpi_gbl_db_command_ready); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
status = acpi_os_create_mutex(&acpi_gbl_db_command_complete); |
#endif |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_mutex_terminate |
* |
* PARAMETERS: None. |
* |
* RETURN: None. |
* |
* DESCRIPTION: Delete all of the system mutex objects. This includes mutexes, |
* spin locks, and reader/writer locks. |
* |
******************************************************************************/ |
void acpi_ut_mutex_terminate(void) |
{ |
u32 i; |
ACPI_FUNCTION_TRACE(ut_mutex_terminate); |
/* Delete each predefined mutex object */ |
for (i = 0; i < ACPI_NUM_MUTEX; i++) { |
acpi_ut_delete_mutex(i); |
} |
acpi_os_delete_mutex(acpi_gbl_osi_mutex); |
/* Delete the spinlocks */ |
acpi_os_delete_lock(acpi_gbl_gpe_lock); |
acpi_os_delete_lock(acpi_gbl_hardware_lock); |
acpi_os_delete_lock(acpi_gbl_reference_count_lock); |
/* Delete the reader/writer lock */ |
acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock); |
#ifdef ACPI_DEBUGGER |
acpi_os_delete_mutex(acpi_gbl_db_command_ready); |
acpi_os_delete_mutex(acpi_gbl_db_command_complete); |
#endif |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_mutex |
* |
* PARAMETERS: mutex_ID - ID of the mutex to be created |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a mutex object. |
* |
******************************************************************************/ |
static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id); |
if (!acpi_gbl_mutex_info[mutex_id].mutex) { |
status = |
acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex); |
acpi_gbl_mutex_info[mutex_id].thread_id = |
ACPI_MUTEX_NOT_ACQUIRED; |
acpi_gbl_mutex_info[mutex_id].use_count = 0; |
} |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_delete_mutex |
* |
* PARAMETERS: mutex_ID - ID of the mutex to be deleted |
* |
* RETURN: Status |
* |
* DESCRIPTION: Delete a mutex object. |
* |
******************************************************************************/ |
static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) |
{ |
ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id); |
acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex); |
acpi_gbl_mutex_info[mutex_id].mutex = NULL; |
acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_acquire_mutex |
* |
* PARAMETERS: mutex_ID - ID of the mutex to be acquired |
* |
* RETURN: Status |
* |
* DESCRIPTION: Acquire a mutex object. |
* |
******************************************************************************/ |
acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) |
{ |
acpi_status status; |
acpi_thread_id this_thread_id; |
ACPI_FUNCTION_NAME(ut_acquire_mutex); |
if (mutex_id > ACPI_MAX_MUTEX) { |
return (AE_BAD_PARAMETER); |
} |
this_thread_id = acpi_os_get_thread_id(); |
#ifdef ACPI_MUTEX_DEBUG |
{ |
u32 i; |
/* |
* Mutex debug code, for internal debugging only. |
* |
* Deadlock prevention. Check if this thread owns any mutexes of value |
* greater than or equal to this one. If so, the thread has violated |
* the mutex ordering rule. This indicates a coding error somewhere in |
* the ACPI subsystem code. |
*/ |
for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { |
if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { |
if (i == mutex_id) { |
ACPI_ERROR((AE_INFO, |
"Mutex [%s] already acquired by this thread [%u]", |
acpi_ut_get_mutex_name |
(mutex_id), |
(u32)this_thread_id)); |
return (AE_ALREADY_ACQUIRED); |
} |
ACPI_ERROR((AE_INFO, |
"Invalid acquire order: Thread %u owns [%s], wants [%s]", |
(u32)this_thread_id, |
acpi_ut_get_mutex_name(i), |
acpi_ut_get_mutex_name(mutex_id))); |
return (AE_ACQUIRE_DEADLOCK); |
} |
} |
} |
#endif |
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, |
"Thread %u attempting to acquire Mutex [%s]\n", |
(u32)this_thread_id, |
acpi_ut_get_mutex_name(mutex_id))); |
status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, |
ACPI_WAIT_FOREVER); |
if (ACPI_SUCCESS(status)) { |
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, |
"Thread %u acquired Mutex [%s]\n", |
(u32)this_thread_id, |
acpi_ut_get_mutex_name(mutex_id))); |
acpi_gbl_mutex_info[mutex_id].use_count++; |
acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; |
} else { |
ACPI_EXCEPTION((AE_INFO, status, |
"Thread %u could not acquire Mutex [0x%X]", |
(u32)this_thread_id, mutex_id)); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_release_mutex |
* |
* PARAMETERS: mutex_ID - ID of the mutex to be released |
* |
* RETURN: Status |
* |
* DESCRIPTION: Release a mutex object. |
* |
******************************************************************************/ |
acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) |
{ |
ACPI_FUNCTION_NAME(ut_release_mutex); |
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n", |
(u32)acpi_os_get_thread_id(), |
acpi_ut_get_mutex_name(mutex_id))); |
if (mutex_id > ACPI_MAX_MUTEX) { |
return (AE_BAD_PARAMETER); |
} |
/* |
* Mutex must be acquired in order to release it! |
*/ |
if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) { |
ACPI_ERROR((AE_INFO, |
"Mutex [0x%X] is not acquired, cannot release", |
mutex_id)); |
return (AE_NOT_ACQUIRED); |
} |
#ifdef ACPI_MUTEX_DEBUG |
{ |
u32 i; |
/* |
* Mutex debug code, for internal debugging only. |
* |
* Deadlock prevention. Check if this thread owns any mutexes of value |
* greater than this one. If so, the thread has violated the mutex |
* ordering rule. This indicates a coding error somewhere in |
* the ACPI subsystem code. |
*/ |
for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { |
if (acpi_gbl_mutex_info[i].thread_id == |
acpi_os_get_thread_id()) { |
if (i == mutex_id) { |
continue; |
} |
ACPI_ERROR((AE_INFO, |
"Invalid release order: owns [%s], releasing [%s]", |
acpi_ut_get_mutex_name(i), |
acpi_ut_get_mutex_name(mutex_id))); |
return (AE_RELEASE_DEADLOCK); |
} |
} |
} |
#endif |
/* Mark unlocked FIRST */ |
acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; |
acpi_os_release_mutex(acpi_gbl_mutex_info[mutex_id].mutex); |
return (AE_OK); |
} |
/drivers/acpi/acpica/utnonansi.c |
---|
0,0 → 1,380 |
/******************************************************************************* |
* |
* Module Name: utnonansi - Non-ansi C library functions |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utnonansi") |
/* |
* Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit |
* version of strtoul. |
*/ |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_strlwr (strlwr) |
* |
* PARAMETERS: src_string - The source string to convert |
* |
* RETURN: None |
* |
* DESCRIPTION: Convert a string to lowercase |
* |
******************************************************************************/ |
void acpi_ut_strlwr(char *src_string) |
{ |
char *string; |
ACPI_FUNCTION_ENTRY(); |
if (!src_string) { |
return; |
} |
/* Walk entire string, lowercasing the letters */ |
for (string = src_string; *string; string++) { |
*string = (char)tolower((int)*string); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_strupr (strupr) |
* |
* PARAMETERS: src_string - The source string to convert |
* |
* RETURN: None |
* |
* DESCRIPTION: Convert a string to uppercase |
* |
******************************************************************************/ |
void acpi_ut_strupr(char *src_string) |
{ |
char *string; |
ACPI_FUNCTION_ENTRY(); |
if (!src_string) { |
return; |
} |
/* Walk entire string, uppercasing the letters */ |
for (string = src_string; *string; string++) { |
*string = (char)toupper((int)*string); |
} |
} |
/****************************************************************************** |
* |
* FUNCTION: acpi_ut_stricmp (stricmp) |
* |
* PARAMETERS: string1 - first string to compare |
* string2 - second string to compare |
* |
* RETURN: int that signifies string relationship. Zero means strings |
* are equal. |
* |
* DESCRIPTION: Case-insensitive string compare. Implementation of the |
* non-ANSI stricmp function. |
* |
******************************************************************************/ |
int acpi_ut_stricmp(char *string1, char *string2) |
{ |
int c1; |
int c2; |
do { |
c1 = tolower((int)*string1); |
c2 = tolower((int)*string2); |
string1++; |
string2++; |
} |
while ((c1 == c2) && (c1)); |
return (c1 - c2); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_strtoul64 |
* |
* PARAMETERS: string - Null terminated string |
* base - Radix of the string: 16 or ACPI_ANY_BASE; |
* ACPI_ANY_BASE means 'in behalf of to_integer' |
* ret_integer - Where the converted integer is returned |
* |
* RETURN: Status and Converted value |
* |
* DESCRIPTION: Convert a string into an unsigned value. Performs either a |
* 32-bit or 64-bit conversion, depending on the current mode |
* of the interpreter. |
* |
* NOTE: Does not support Octal strings, not needed. |
* |
******************************************************************************/ |
acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) |
{ |
u32 this_digit = 0; |
u64 return_value = 0; |
u64 quotient; |
u64 dividend; |
u32 to_integer_op = (base == ACPI_ANY_BASE); |
u32 mode32 = (acpi_gbl_integer_byte_width == 4); |
u8 valid_digits = 0; |
u8 sign_of0x = 0; |
u8 term = 0; |
ACPI_FUNCTION_TRACE_STR(ut_stroul64, string); |
switch (base) { |
case ACPI_ANY_BASE: |
case 16: |
break; |
default: |
/* Invalid Base */ |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
if (!string) { |
goto error_exit; |
} |
/* Skip over any white space in the buffer */ |
while ((*string) && (isspace((int)*string) || *string == '\t')) { |
string++; |
} |
if (to_integer_op) { |
/* |
* Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. |
* We need to determine if it is decimal or hexadecimal. |
*/ |
if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { |
sign_of0x = 1; |
base = 16; |
/* Skip over the leading '0x' */ |
string += 2; |
} else { |
base = 10; |
} |
} |
/* Any string left? Check that '0x' is not followed by white space. */ |
if (!(*string) || isspace((int)*string) || *string == '\t') { |
if (to_integer_op) { |
goto error_exit; |
} else { |
goto all_done; |
} |
} |
/* |
* Perform a 32-bit or 64-bit conversion, depending upon the current |
* execution mode of the interpreter |
*/ |
dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; |
/* Main loop: convert the string to a 32- or 64-bit integer */ |
while (*string) { |
if (isdigit((int)*string)) { |
/* Convert ASCII 0-9 to Decimal value */ |
this_digit = ((u8)*string) - '0'; |
} else if (base == 10) { |
/* Digit is out of range; possible in to_integer case only */ |
term = 1; |
} else { |
this_digit = (u8)toupper((int)*string); |
if (isxdigit((int)this_digit)) { |
/* Convert ASCII Hex char to value */ |
this_digit = this_digit - 'A' + 10; |
} else { |
term = 1; |
} |
} |
if (term) { |
if (to_integer_op) { |
goto error_exit; |
} else { |
break; |
} |
} else if ((valid_digits == 0) && (this_digit == 0) |
&& !sign_of0x) { |
/* Skip zeros */ |
string++; |
continue; |
} |
valid_digits++; |
if (sign_of0x |
&& ((valid_digits > 16) |
|| ((valid_digits > 8) && mode32))) { |
/* |
* This is to_integer operation case. |
* No any restrictions for string-to-integer conversion, |
* see ACPI spec. |
*/ |
goto error_exit; |
} |
/* Divide the digit into the correct position */ |
(void)acpi_ut_short_divide((dividend - (u64)this_digit), |
base, "ient, NULL); |
if (return_value > quotient) { |
if (to_integer_op) { |
goto error_exit; |
} else { |
break; |
} |
} |
return_value *= base; |
return_value += this_digit; |
string++; |
} |
/* All done, normal exit */ |
all_done: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", |
ACPI_FORMAT_UINT64(return_value))); |
*ret_integer = return_value; |
return_ACPI_STATUS(AE_OK); |
error_exit: |
/* Base was set/validated above */ |
if (base == 10) { |
return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT); |
} else { |
return_ACPI_STATUS(AE_BAD_HEX_CONSTANT); |
} |
} |
#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat |
* |
* PARAMETERS: Adds a "DestSize" parameter to each of the standard string |
* functions. This is the size of the Destination buffer. |
* |
* RETURN: TRUE if the operation would overflow the destination buffer. |
* |
* DESCRIPTION: Safe versions of standard Clib string functions. Ensure that |
* the result of the operation will not overflow the output string |
* buffer. |
* |
* NOTE: These functions are typically only helpful for processing |
* user input and command lines. For most ACPICA code, the |
* required buffer length is precisely calculated before buffer |
* allocation, so the use of these functions is unnecessary. |
* |
******************************************************************************/ |
u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source) |
{ |
if (strlen(source) >= dest_size) { |
return (TRUE); |
} |
strcpy(dest, source); |
return (FALSE); |
} |
u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source) |
{ |
if ((strlen(dest) + strlen(source)) >= dest_size) { |
return (TRUE); |
} |
strcat(dest, source); |
return (FALSE); |
} |
u8 |
acpi_ut_safe_strncat(char *dest, |
acpi_size dest_size, |
char *source, acpi_size max_transfer_length) |
{ |
acpi_size actual_transfer_length; |
actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source)); |
if ((strlen(dest) + actual_transfer_length) >= dest_size) { |
return (TRUE); |
} |
strncat(dest, source, max_transfer_length); |
return (FALSE); |
} |
#endif |
/drivers/acpi/acpica/utobject.c |
---|
0,0 → 1,706 |
/****************************************************************************** |
* |
* Module Name: utobject - ACPI object create/delete/size/cache routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utobject") |
/* Local prototypes */ |
static acpi_status |
acpi_ut_get_simple_object_size(union acpi_operand_object *obj, |
acpi_size * obj_length); |
static acpi_status |
acpi_ut_get_package_object_size(union acpi_operand_object *obj, |
acpi_size * obj_length); |
static acpi_status |
acpi_ut_get_element_length(u8 object_type, |
union acpi_operand_object *source_object, |
union acpi_generic_state *state, void *context); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_internal_object_dbg |
* |
* PARAMETERS: module_name - Source file name of caller |
* line_number - Line number of caller |
* component_id - Component type of caller |
* type - ACPI Type of the new object |
* |
* RETURN: A new internal object, null on failure |
* |
* DESCRIPTION: Create and initialize a new internal object. |
* |
* NOTE: We always allocate the worst-case object descriptor because |
* these objects are cached, and we want them to be |
* one-size-satisifies-any-request. This in itself may not be |
* the most memory efficient, but the efficiency of the object |
* cache should more than make up for this! |
* |
******************************************************************************/ |
union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char |
*module_name, |
u32 line_number, |
u32 component_id, |
acpi_object_type |
type) |
{ |
union acpi_operand_object *object; |
union acpi_operand_object *second_object; |
ACPI_FUNCTION_TRACE_STR(ut_create_internal_object_dbg, |
acpi_ut_get_type_name(type)); |
/* Allocate the raw object descriptor */ |
object = |
acpi_ut_allocate_object_desc_dbg(module_name, line_number, |
component_id); |
if (!object) { |
return_PTR(NULL); |
} |
switch (type) { |
case ACPI_TYPE_REGION: |
case ACPI_TYPE_BUFFER_FIELD: |
case ACPI_TYPE_LOCAL_BANK_FIELD: |
/* These types require a secondary object */ |
second_object = acpi_ut_allocate_object_desc_dbg(module_name, |
line_number, |
component_id); |
if (!second_object) { |
acpi_ut_delete_object_desc(object); |
return_PTR(NULL); |
} |
second_object->common.type = ACPI_TYPE_LOCAL_EXTRA; |
second_object->common.reference_count = 1; |
/* Link the second object to the first */ |
object->common.next_object = second_object; |
break; |
default: |
/* All others have no secondary object */ |
break; |
} |
/* Save the object type in the object descriptor */ |
object->common.type = (u8) type; |
/* Init the reference count */ |
object->common.reference_count = 1; |
/* Any per-type initialization should go here */ |
return_PTR(object); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_package_object |
* |
* PARAMETERS: count - Number of package elements |
* |
* RETURN: Pointer to a new Package object, null on failure |
* |
* DESCRIPTION: Create a fully initialized package object |
* |
******************************************************************************/ |
union acpi_operand_object *acpi_ut_create_package_object(u32 count) |
{ |
union acpi_operand_object *package_desc; |
union acpi_operand_object **package_elements; |
ACPI_FUNCTION_TRACE_U32(ut_create_package_object, count); |
/* Create a new Package object */ |
package_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE); |
if (!package_desc) { |
return_PTR(NULL); |
} |
/* |
* Create the element array. Count+1 allows the array to be null |
* terminated. |
*/ |
package_elements = ACPI_ALLOCATE_ZEROED(((acpi_size) count + |
1) * sizeof(void *)); |
if (!package_elements) { |
ACPI_FREE(package_desc); |
return_PTR(NULL); |
} |
package_desc->package.count = count; |
package_desc->package.elements = package_elements; |
return_PTR(package_desc); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_integer_object |
* |
* PARAMETERS: initial_value - Initial value for the integer |
* |
* RETURN: Pointer to a new Integer object, null on failure |
* |
* DESCRIPTION: Create an initialized integer object |
* |
******************************************************************************/ |
union acpi_operand_object *acpi_ut_create_integer_object(u64 initial_value) |
{ |
union acpi_operand_object *integer_desc; |
ACPI_FUNCTION_TRACE(ut_create_integer_object); |
/* Create and initialize a new integer object */ |
integer_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!integer_desc) { |
return_PTR(NULL); |
} |
integer_desc->integer.value = initial_value; |
return_PTR(integer_desc); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_buffer_object |
* |
* PARAMETERS: buffer_size - Size of buffer to be created |
* |
* RETURN: Pointer to a new Buffer object, null on failure |
* |
* DESCRIPTION: Create a fully initialized buffer object |
* |
******************************************************************************/ |
union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size) |
{ |
union acpi_operand_object *buffer_desc; |
u8 *buffer = NULL; |
ACPI_FUNCTION_TRACE_U32(ut_create_buffer_object, buffer_size); |
/* Create a new Buffer object */ |
buffer_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER); |
if (!buffer_desc) { |
return_PTR(NULL); |
} |
/* Create an actual buffer only if size > 0 */ |
if (buffer_size > 0) { |
/* Allocate the actual buffer */ |
buffer = ACPI_ALLOCATE_ZEROED(buffer_size); |
if (!buffer) { |
ACPI_ERROR((AE_INFO, "Could not allocate size %u", |
(u32) buffer_size)); |
acpi_ut_remove_reference(buffer_desc); |
return_PTR(NULL); |
} |
} |
/* Complete buffer object initialization */ |
buffer_desc->buffer.flags |= AOPOBJ_DATA_VALID; |
buffer_desc->buffer.pointer = buffer; |
buffer_desc->buffer.length = (u32) buffer_size; |
/* Return the new buffer descriptor */ |
return_PTR(buffer_desc); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_string_object |
* |
* PARAMETERS: string_size - Size of string to be created. Does not |
* include NULL terminator, this is added |
* automatically. |
* |
* RETURN: Pointer to a new String object |
* |
* DESCRIPTION: Create a fully initialized string object |
* |
******************************************************************************/ |
union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size) |
{ |
union acpi_operand_object *string_desc; |
char *string; |
ACPI_FUNCTION_TRACE_U32(ut_create_string_object, string_size); |
/* Create a new String object */ |
string_desc = acpi_ut_create_internal_object(ACPI_TYPE_STRING); |
if (!string_desc) { |
return_PTR(NULL); |
} |
/* |
* Allocate the actual string buffer -- (Size + 1) for NULL terminator. |
* NOTE: Zero-length strings are NULL terminated |
*/ |
string = ACPI_ALLOCATE_ZEROED(string_size + 1); |
if (!string) { |
ACPI_ERROR((AE_INFO, "Could not allocate size %u", |
(u32) string_size)); |
acpi_ut_remove_reference(string_desc); |
return_PTR(NULL); |
} |
/* Complete string object initialization */ |
string_desc->string.pointer = string; |
string_desc->string.length = (u32) string_size; |
/* Return the new string descriptor */ |
return_PTR(string_desc); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_valid_internal_object |
* |
* PARAMETERS: object - Object to be validated |
* |
* RETURN: TRUE if object is valid, FALSE otherwise |
* |
* DESCRIPTION: Validate a pointer to be of type union acpi_operand_object |
* |
******************************************************************************/ |
u8 acpi_ut_valid_internal_object(void *object) |
{ |
ACPI_FUNCTION_NAME(ut_valid_internal_object); |
/* Check for a null pointer */ |
if (!object) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "**** Null Object Ptr\n")); |
return (FALSE); |
} |
/* Check the descriptor type field */ |
switch (ACPI_GET_DESCRIPTOR_TYPE(object)) { |
case ACPI_DESC_TYPE_OPERAND: |
/* The object appears to be a valid union acpi_operand_object */ |
return (TRUE); |
default: |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"%p is not an ACPI operand obj [%s]\n", |
object, acpi_ut_get_descriptor_name(object))); |
break; |
} |
return (FALSE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_allocate_object_desc_dbg |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* component_id - Caller's component ID (for error output) |
* |
* RETURN: Pointer to newly allocated object descriptor. Null on error |
* |
* DESCRIPTION: Allocate a new object descriptor. Gracefully handle |
* error conditions. |
* |
******************************************************************************/ |
void *acpi_ut_allocate_object_desc_dbg(const char *module_name, |
u32 line_number, u32 component_id) |
{ |
union acpi_operand_object *object; |
ACPI_FUNCTION_TRACE(ut_allocate_object_desc_dbg); |
object = acpi_os_acquire_object(acpi_gbl_operand_cache); |
if (!object) { |
ACPI_ERROR((module_name, line_number, |
"Could not allocate an object descriptor")); |
return_PTR(NULL); |
} |
/* Mark the descriptor type */ |
ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_OPERAND); |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p Size %X\n", |
object, (u32) sizeof(union acpi_operand_object))); |
return_PTR(object); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_delete_object_desc |
* |
* PARAMETERS: object - An Acpi internal object to be deleted |
* |
* RETURN: None. |
* |
* DESCRIPTION: Free an ACPI object descriptor or add it to the object cache |
* |
******************************************************************************/ |
void acpi_ut_delete_object_desc(union acpi_operand_object *object) |
{ |
ACPI_FUNCTION_TRACE_PTR(ut_delete_object_desc, object); |
/* Object must be of type union acpi_operand_object */ |
if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) { |
ACPI_ERROR((AE_INFO, |
"%p is not an ACPI Operand object [%s]", object, |
acpi_ut_get_descriptor_name(object))); |
return_VOID; |
} |
(void)acpi_os_release_object(acpi_gbl_operand_cache, object); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_simple_object_size |
* |
* PARAMETERS: internal_object - An ACPI operand object |
* obj_length - Where the length is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to determine the space required to |
* contain a simple object for return to an external user. |
* |
* The length includes the object structure plus any additional |
* needed space. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, |
acpi_size * obj_length) |
{ |
acpi_size length; |
acpi_size size; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_PTR(ut_get_simple_object_size, internal_object); |
/* Start with the length of the (external) Acpi object */ |
length = sizeof(union acpi_object); |
/* A NULL object is allowed, can be a legal uninitialized package element */ |
if (!internal_object) { |
/* |
* Object is NULL, just return the length of union acpi_object |
* (A NULL union acpi_object is an object of all zeroes.) |
*/ |
*obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD(length); |
return_ACPI_STATUS(AE_OK); |
} |
/* A Namespace Node should never appear here */ |
if (ACPI_GET_DESCRIPTOR_TYPE(internal_object) == ACPI_DESC_TYPE_NAMED) { |
/* A namespace node should never get here */ |
return_ACPI_STATUS(AE_AML_INTERNAL); |
} |
/* |
* The final length depends on the object type |
* Strings and Buffers are packed right up against the parent object and |
* must be accessed bytewise or there may be alignment problems on |
* certain processors |
*/ |
switch (internal_object->common.type) { |
case ACPI_TYPE_STRING: |
length += (acpi_size) internal_object->string.length + 1; |
break; |
case ACPI_TYPE_BUFFER: |
length += (acpi_size) internal_object->buffer.length; |
break; |
case ACPI_TYPE_INTEGER: |
case ACPI_TYPE_PROCESSOR: |
case ACPI_TYPE_POWER: |
/* No extra data for these types */ |
break; |
case ACPI_TYPE_LOCAL_REFERENCE: |
switch (internal_object->reference.class) { |
case ACPI_REFCLASS_NAME: |
/* |
* Get the actual length of the full pathname to this object. |
* The reference will be converted to the pathname to the object |
*/ |
size = |
acpi_ns_get_pathname_length(internal_object-> |
reference.node); |
if (!size) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
length += ACPI_ROUND_UP_TO_NATIVE_WORD(size); |
break; |
default: |
/* |
* No other reference opcodes are supported. |
* Notably, Locals and Args are not supported, but this may be |
* required eventually. |
*/ |
ACPI_ERROR((AE_INFO, |
"Cannot convert to external object - " |
"unsupported Reference Class [%s] 0x%X in object %p", |
acpi_ut_get_reference_name(internal_object), |
internal_object->reference.class, |
internal_object)); |
status = AE_TYPE; |
break; |
} |
break; |
default: |
ACPI_ERROR((AE_INFO, "Cannot convert to external object - " |
"unsupported type [%s] 0x%X in object %p", |
acpi_ut_get_object_type_name(internal_object), |
internal_object->common.type, internal_object)); |
status = AE_TYPE; |
break; |
} |
/* |
* Account for the space required by the object rounded up to the next |
* multiple of the machine word size. This keeps each object aligned |
* on a machine word boundary. (preventing alignment faults on some |
* machines.) |
*/ |
*obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD(length); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_element_length |
* |
* PARAMETERS: acpi_pkg_callback |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get the length of one package element. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_get_element_length(u8 object_type, |
union acpi_operand_object *source_object, |
union acpi_generic_state *state, void *context) |
{ |
acpi_status status = AE_OK; |
struct acpi_pkg_info *info = (struct acpi_pkg_info *)context; |
acpi_size object_space; |
switch (object_type) { |
case ACPI_COPY_TYPE_SIMPLE: |
/* |
* Simple object - just get the size (Null object/entry is handled |
* here also) and sum it into the running package length |
*/ |
status = |
acpi_ut_get_simple_object_size(source_object, |
&object_space); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
info->length += object_space; |
break; |
case ACPI_COPY_TYPE_PACKAGE: |
/* Package object - nothing much to do here, let the walk handle it */ |
info->num_packages++; |
state->pkg.this_target_obj = NULL; |
break; |
default: |
/* No other types allowed */ |
return (AE_BAD_PARAMETER); |
} |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_package_object_size |
* |
* PARAMETERS: internal_object - An ACPI internal object |
* obj_length - Where the length is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to determine the space required to |
* contain a package object for return to an external user. |
* |
* This is moderately complex since a package contains other |
* objects including packages. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_get_package_object_size(union acpi_operand_object *internal_object, |
acpi_size * obj_length) |
{ |
acpi_status status; |
struct acpi_pkg_info info; |
ACPI_FUNCTION_TRACE_PTR(ut_get_package_object_size, internal_object); |
info.length = 0; |
info.object_space = 0; |
info.num_packages = 1; |
status = acpi_ut_walk_package_tree(internal_object, NULL, |
acpi_ut_get_element_length, &info); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* We have handled all of the objects in all levels of the package. |
* just add the length of the package objects themselves. |
* Round up to the next machine word. |
*/ |
info.length += ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)) * |
(acpi_size) info.num_packages; |
/* Return the total package length */ |
*obj_length = info.length; |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_object_size |
* |
* PARAMETERS: internal_object - An ACPI internal object |
* obj_length - Where the length will be returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: This function is called to determine the space required to |
* contain an object for return to an API user. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_get_object_size(union acpi_operand_object *internal_object, |
acpi_size * obj_length) |
{ |
acpi_status status; |
ACPI_FUNCTION_ENTRY(); |
if ((ACPI_GET_DESCRIPTOR_TYPE(internal_object) == |
ACPI_DESC_TYPE_OPERAND) |
&& (internal_object->common.type == ACPI_TYPE_PACKAGE)) { |
status = |
acpi_ut_get_package_object_size(internal_object, |
obj_length); |
} else { |
status = |
acpi_ut_get_simple_object_size(internal_object, obj_length); |
} |
return (status); |
} |
/drivers/acpi/acpica/utosi.c |
---|
0,0 → 1,473 |
/****************************************************************************** |
* |
* Module Name: utosi - Support for the _OSI predefined control method |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utosi") |
/****************************************************************************** |
* |
* ACPICA policy for new _OSI strings: |
* |
* It is the stated policy of ACPICA that new _OSI strings will be integrated |
* into this module as soon as possible after they are defined. It is strongly |
* recommended that all ACPICA hosts mirror this policy and integrate any |
* changes to this module as soon as possible. There are several historical |
* reasons behind this policy: |
* |
* 1) New BIOSs tend to test only the case where the host responds TRUE to |
* the latest version of Windows, which would respond to the latest/newest |
* _OSI string. Not responding TRUE to the latest version of Windows will |
* risk executing untested code paths throughout the DSDT and SSDTs. |
* |
* 2) If a new _OSI string is recognized only after a significant delay, this |
* has the potential to cause problems on existing working machines because |
* of the possibility that a new and different path through the ASL code |
* will be executed. |
* |
* 3) New _OSI strings are tending to come out about once per year. A delay |
* in recognizing a new string for a significant amount of time risks the |
* release of another string which only compounds the initial problem. |
* |
*****************************************************************************/ |
/* |
* Strings supported by the _OSI predefined control method (which is |
* implemented internally within this module.) |
* |
* March 2009: Removed "Linux" as this host no longer wants to respond true |
* for this string. Basically, the only safe OS strings are windows-related |
* and in many or most cases represent the only test path within the |
* BIOS-provided ASL code. |
* |
* The last element of each entry is used to track the newest version of |
* Windows that the BIOS has requested. |
*/ |
static struct acpi_interface_info acpi_default_supported_interfaces[] = { |
/* Operating System Vendor Strings */ |
{"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000}, /* Windows 2000 */ |
{"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP}, /* Windows XP */ |
{"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */ |
{"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003}, /* Windows Server 2003 */ |
{"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */ |
{"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */ |
{"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA}, /* Windows vista - Added 03/2006 */ |
{"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */ |
{"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */ |
{"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */ |
{"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */ |
{"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */ |
{"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ |
{"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ |
/* Feature Group Strings */ |
{"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0}, |
/* |
* All "optional" feature group strings (features that are implemented |
* by the host) should be dynamically modified to VALID by the host via |
* acpi_install_interface or acpi_update_interfaces. Such optional feature |
* group strings are set as INVALID by default here. |
*/ |
{"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
{"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
{"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
{"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
{"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0} |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_initialize_interfaces |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initialize the global _OSI supported interfaces list |
* |
******************************************************************************/ |
acpi_status acpi_ut_initialize_interfaces(void) |
{ |
acpi_status status; |
u32 i; |
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
acpi_gbl_supported_interfaces = acpi_default_supported_interfaces; |
/* Link the static list of supported interfaces */ |
for (i = 0; |
i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1); |
i++) { |
acpi_default_supported_interfaces[i].next = |
&acpi_default_supported_interfaces[(acpi_size) i + 1]; |
} |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_interface_terminate |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Delete all interfaces in the global list. Sets |
* acpi_gbl_supported_interfaces to NULL. |
* |
******************************************************************************/ |
acpi_status acpi_ut_interface_terminate(void) |
{ |
acpi_status status; |
struct acpi_interface_info *next_interface; |
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
next_interface = acpi_gbl_supported_interfaces; |
while (next_interface) { |
acpi_gbl_supported_interfaces = next_interface->next; |
if (next_interface->flags & ACPI_OSI_DYNAMIC) { |
/* Only interfaces added at runtime can be freed */ |
ACPI_FREE(next_interface->name); |
ACPI_FREE(next_interface); |
} else { |
/* Interface is in static list. Reset it to invalid or valid. */ |
if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) { |
next_interface->flags |= ACPI_OSI_INVALID; |
} else { |
next_interface->flags &= ~ACPI_OSI_INVALID; |
} |
} |
next_interface = acpi_gbl_supported_interfaces; |
} |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_install_interface |
* |
* PARAMETERS: interface_name - The interface to install |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install the interface into the global interface list. |
* Caller MUST hold acpi_gbl_osi_mutex |
* |
******************************************************************************/ |
acpi_status acpi_ut_install_interface(acpi_string interface_name) |
{ |
struct acpi_interface_info *interface_info; |
/* Allocate info block and space for the name string */ |
interface_info = |
ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info)); |
if (!interface_info) { |
return (AE_NO_MEMORY); |
} |
interface_info->name = ACPI_ALLOCATE_ZEROED(strlen(interface_name) + 1); |
if (!interface_info->name) { |
ACPI_FREE(interface_info); |
return (AE_NO_MEMORY); |
} |
/* Initialize new info and insert at the head of the global list */ |
strcpy(interface_info->name, interface_name); |
interface_info->flags = ACPI_OSI_DYNAMIC; |
interface_info->next = acpi_gbl_supported_interfaces; |
acpi_gbl_supported_interfaces = interface_info; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_remove_interface |
* |
* PARAMETERS: interface_name - The interface to remove |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove the interface from the global interface list. |
* Caller MUST hold acpi_gbl_osi_mutex |
* |
******************************************************************************/ |
acpi_status acpi_ut_remove_interface(acpi_string interface_name) |
{ |
struct acpi_interface_info *previous_interface; |
struct acpi_interface_info *next_interface; |
previous_interface = next_interface = acpi_gbl_supported_interfaces; |
while (next_interface) { |
if (!strcmp(interface_name, next_interface->name)) { |
/* Found: name is in either the static list or was added at runtime */ |
if (next_interface->flags & ACPI_OSI_DYNAMIC) { |
/* Interface was added dynamically, remove and free it */ |
if (previous_interface == next_interface) { |
acpi_gbl_supported_interfaces = |
next_interface->next; |
} else { |
previous_interface->next = |
next_interface->next; |
} |
ACPI_FREE(next_interface->name); |
ACPI_FREE(next_interface); |
} else { |
/* |
* Interface is in static list. If marked invalid, then it |
* does not actually exist. Else, mark it invalid. |
*/ |
if (next_interface->flags & ACPI_OSI_INVALID) { |
return (AE_NOT_EXIST); |
} |
next_interface->flags |= ACPI_OSI_INVALID; |
} |
return (AE_OK); |
} |
previous_interface = next_interface; |
next_interface = next_interface->next; |
} |
/* Interface was not found */ |
return (AE_NOT_EXIST); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_update_interfaces |
* |
* PARAMETERS: action - Actions to be performed during the |
* update |
* |
* RETURN: Status |
* |
* DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor |
* strings or/and feature group strings. |
* Caller MUST hold acpi_gbl_osi_mutex |
* |
******************************************************************************/ |
acpi_status acpi_ut_update_interfaces(u8 action) |
{ |
struct acpi_interface_info *next_interface; |
next_interface = acpi_gbl_supported_interfaces; |
while (next_interface) { |
if (((next_interface->flags & ACPI_OSI_FEATURE) && |
(action & ACPI_FEATURE_STRINGS)) || |
(!(next_interface->flags & ACPI_OSI_FEATURE) && |
(action & ACPI_VENDOR_STRINGS))) { |
if (action & ACPI_DISABLE_INTERFACES) { |
/* Mark the interfaces as invalid */ |
next_interface->flags |= ACPI_OSI_INVALID; |
} else { |
/* Mark the interfaces as valid */ |
next_interface->flags &= ~ACPI_OSI_INVALID; |
} |
} |
next_interface = next_interface->next; |
} |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_interface |
* |
* PARAMETERS: interface_name - The interface to find |
* |
* RETURN: struct acpi_interface_info if found. NULL if not found. |
* |
* DESCRIPTION: Search for the specified interface name in the global list. |
* Caller MUST hold acpi_gbl_osi_mutex |
* |
******************************************************************************/ |
struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name) |
{ |
struct acpi_interface_info *next_interface; |
next_interface = acpi_gbl_supported_interfaces; |
while (next_interface) { |
if (!strcmp(interface_name, next_interface->name)) { |
return (next_interface); |
} |
next_interface = next_interface->next; |
} |
return (NULL); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_osi_implementation |
* |
* PARAMETERS: walk_state - Current walk state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Implementation of the _OSI predefined control method. When |
* an invocation of _OSI is encountered in the system AML, |
* control is transferred to this function. |
* |
******************************************************************************/ |
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state) |
{ |
union acpi_operand_object *string_desc; |
union acpi_operand_object *return_desc; |
struct acpi_interface_info *interface_info; |
acpi_interface_handler interface_handler; |
acpi_status status; |
u32 return_value; |
ACPI_FUNCTION_TRACE(ut_osi_implementation); |
/* Validate the string input argument (from the AML caller) */ |
string_desc = walk_state->arguments[0].object; |
if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { |
return_ACPI_STATUS(AE_TYPE); |
} |
/* Create a return object */ |
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
if (!return_desc) { |
return_ACPI_STATUS(AE_NO_MEMORY); |
} |
/* Default return value is 0, NOT SUPPORTED */ |
return_value = 0; |
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
acpi_ut_remove_reference(return_desc); |
return_ACPI_STATUS(status); |
} |
/* Lookup the interface in the global _OSI list */ |
interface_info = acpi_ut_get_interface(string_desc->string.pointer); |
if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) { |
/* |
* The interface is supported. |
* Update the osi_data if necessary. We keep track of the latest |
* version of Windows that has been requested by the BIOS. |
*/ |
if (interface_info->value > acpi_gbl_osi_data) { |
acpi_gbl_osi_data = interface_info->value; |
} |
return_value = ACPI_UINT32_MAX; |
} |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
/* |
* Invoke an optional _OSI interface handler. The host OS may wish |
* to do some interface-specific handling. For example, warn about |
* certain interfaces or override the true/false support value. |
*/ |
interface_handler = acpi_gbl_interface_handler; |
if (interface_handler) { |
return_value = |
interface_handler(string_desc->string.pointer, |
return_value); |
} |
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, |
"ACPI: BIOS _OSI(\"%s\") is %ssupported\n", |
string_desc->string.pointer, |
return_value == 0 ? "not " : "")); |
/* Complete the return object */ |
return_desc->integer.value = return_value; |
walk_state->return_desc = return_desc; |
return_ACPI_STATUS(AE_OK); |
} |
/drivers/acpi/acpica/utownerid.c |
---|
0,0 → 1,218 |
/******************************************************************************* |
* |
* Module Name: utownerid - Support for Table/Method Owner IDs |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utownerid") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_allocate_owner_id |
* |
* PARAMETERS: owner_id - Where the new owner ID is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Allocate a table or method owner ID. The owner ID is used to |
* track objects created by the table or method, to be deleted |
* when the method exits or the table is unloaded. |
* |
******************************************************************************/ |
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) |
{ |
u32 i; |
u32 j; |
u32 k; |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_allocate_owner_id); |
/* Guard against multiple allocations of ID to the same location */ |
if (*owner_id) { |
ACPI_ERROR((AE_INFO, "Owner ID [0x%2.2X] already exists", |
*owner_id)); |
return_ACPI_STATUS(AE_ALREADY_EXISTS); |
} |
/* Mutex for the global ID mask */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Find a free owner ID, cycle through all possible IDs on repeated |
* allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index may have |
* to be scanned twice. |
*/ |
for (i = 0, j = acpi_gbl_last_owner_id_index; |
i < (ACPI_NUM_OWNERID_MASKS + 1); i++, j++) { |
if (j >= ACPI_NUM_OWNERID_MASKS) { |
j = 0; /* Wraparound to start of mask array */ |
} |
for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) { |
if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) { |
/* There are no free IDs in this mask */ |
break; |
} |
if (!(acpi_gbl_owner_id_mask[j] & (1 << k))) { |
/* |
* Found a free ID. The actual ID is the bit index plus one, |
* making zero an invalid Owner ID. Save this as the last ID |
* allocated and update the global ID mask. |
*/ |
acpi_gbl_owner_id_mask[j] |= (1 << k); |
acpi_gbl_last_owner_id_index = (u8)j; |
acpi_gbl_next_owner_id_offset = (u8)(k + 1); |
/* |
* Construct encoded ID from the index and bit position |
* |
* Note: Last [j].k (bit 255) is never used and is marked |
* permanently allocated (prevents +1 overflow) |
*/ |
*owner_id = |
(acpi_owner_id) ((k + 1) + ACPI_MUL_32(j)); |
ACPI_DEBUG_PRINT((ACPI_DB_VALUES, |
"Allocated OwnerId: %2.2X\n", |
(unsigned int)*owner_id)); |
goto exit; |
} |
} |
acpi_gbl_next_owner_id_offset = 0; |
} |
/* |
* All owner_ids have been allocated. This typically should |
* not happen since the IDs are reused after deallocation. The IDs are |
* allocated upon table load (one per table) and method execution, and |
* they are released when a table is unloaded or a method completes |
* execution. |
* |
* If this error happens, there may be very deep nesting of invoked control |
* methods, or there may be a bug where the IDs are not released. |
*/ |
status = AE_OWNER_ID_LIMIT; |
ACPI_ERROR((AE_INFO, |
"Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT")); |
exit: |
(void)acpi_ut_release_mutex(ACPI_MTX_CACHES); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_release_owner_id |
* |
* PARAMETERS: owner_id_ptr - Pointer to a previously allocated owner_ID |
* |
* RETURN: None. No error is returned because we are either exiting a |
* control method or unloading a table. Either way, we would |
* ignore any error anyway. |
* |
* DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255 |
* |
******************************************************************************/ |
void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr) |
{ |
acpi_owner_id owner_id = *owner_id_ptr; |
acpi_status status; |
u32 index; |
u32 bit; |
ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id); |
/* Always clear the input owner_id (zero is an invalid ID) */ |
*owner_id_ptr = 0; |
/* Zero is not a valid owner_ID */ |
if (owner_id == 0) { |
ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%2.2X", owner_id)); |
return_VOID; |
} |
/* Mutex for the global ID mask */ |
status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); |
if (ACPI_FAILURE(status)) { |
return_VOID; |
} |
/* Normalize the ID to zero */ |
owner_id--; |
/* Decode ID to index/offset pair */ |
index = ACPI_DIV_32(owner_id); |
bit = 1 << ACPI_MOD_32(owner_id); |
/* Free the owner ID only if it is valid */ |
if (acpi_gbl_owner_id_mask[index] & bit) { |
acpi_gbl_owner_id_mask[index] ^= bit; |
} else { |
ACPI_ERROR((AE_INFO, |
"Release of non-allocated OwnerId: 0x%2.2X", |
owner_id + 1)); |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_CACHES); |
return_VOID; |
} |
/drivers/acpi/acpica/utpredef.c |
---|
0,0 → 1,399 |
/****************************************************************************** |
* |
* Module Name: utpredef - support functions for predefined names |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acpredef.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utpredef") |
/* |
* Names for the types that can be returned by the predefined objects. |
* Used for warning messages. Must be in the same order as the ACPI_RTYPEs |
*/ |
static const char *ut_rtype_names[] = { |
"/Integer", |
"/String", |
"/Buffer", |
"/Package", |
"/Reference", |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_next_predefined_method |
* |
* PARAMETERS: this_name - Entry in the predefined method/name table |
* |
* RETURN: Pointer to next entry in predefined table. |
* |
* DESCRIPTION: Get the next entry in the predefine method table. Handles the |
* cases where a package info entry follows a method name that |
* returns a package. |
* |
******************************************************************************/ |
const union acpi_predefined_info *acpi_ut_get_next_predefined_method(const union |
acpi_predefined_info |
*this_name) |
{ |
/* |
* Skip next entry in the table if this name returns a Package |
* (next entry contains the package info) |
*/ |
if ((this_name->info.expected_btypes & ACPI_RTYPE_PACKAGE) && |
(this_name->info.expected_btypes != ACPI_RTYPE_ALL)) { |
this_name++; |
} |
this_name++; |
return (this_name); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_match_predefined_method |
* |
* PARAMETERS: name - Name to find |
* |
* RETURN: Pointer to entry in predefined table. NULL indicates not found. |
* |
* DESCRIPTION: Check an object name against the predefined object list. |
* |
******************************************************************************/ |
const union acpi_predefined_info *acpi_ut_match_predefined_method(char *name) |
{ |
const union acpi_predefined_info *this_name; |
/* Quick check for a predefined name, first character must be underscore */ |
if (name[0] != '_') { |
return (NULL); |
} |
/* Search info table for a predefined method/object name */ |
this_name = acpi_gbl_predefined_methods; |
while (this_name->info.name[0]) { |
if (ACPI_COMPARE_NAME(name, this_name->info.name)) { |
return (this_name); |
} |
this_name = acpi_ut_get_next_predefined_method(this_name); |
} |
return (NULL); /* Not found */ |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_expected_return_types |
* |
* PARAMETERS: buffer - Where the formatted string is returned |
* expected_Btypes - Bitfield of expected data types |
* |
* RETURN: Formatted string in Buffer. |
* |
* DESCRIPTION: Format the expected object types into a printable string. |
* |
******************************************************************************/ |
void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes) |
{ |
u32 this_rtype; |
u32 i; |
u32 j; |
if (!expected_btypes) { |
strcpy(buffer, "NONE"); |
return; |
} |
j = 1; |
buffer[0] = 0; |
this_rtype = ACPI_RTYPE_INTEGER; |
for (i = 0; i < ACPI_NUM_RTYPES; i++) { |
/* If one of the expected types, concatenate the name of this type */ |
if (expected_btypes & this_rtype) { |
strcat(buffer, &ut_rtype_names[i][j]); |
j = 0; /* Use name separator from now on */ |
} |
this_rtype <<= 1; /* Next Rtype */ |
} |
} |
/******************************************************************************* |
* |
* The remaining functions are used by iASL and acpi_help only |
* |
******************************************************************************/ |
#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP) |
#include <stdio.h> |
#include <string.h> |
/* Local prototypes */ |
static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types); |
/* Types that can be returned externally by a predefined name */ |
static const char *ut_external_type_names[] = /* Indexed by ACPI_TYPE_* */ |
{ |
", UNSUPPORTED-TYPE", |
", Integer", |
", String", |
", Buffer", |
", Package" |
}; |
/* Bit widths for resource descriptor predefined names */ |
static const char *ut_resource_type_names[] = { |
"/1", |
"/2", |
"/3", |
"/8", |
"/16", |
"/32", |
"/64", |
"/variable", |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_match_resource_name |
* |
* PARAMETERS: name - Name to find |
* |
* RETURN: Pointer to entry in the resource table. NULL indicates not |
* found. |
* |
* DESCRIPTION: Check an object name against the predefined resource |
* descriptor object list. |
* |
******************************************************************************/ |
const union acpi_predefined_info *acpi_ut_match_resource_name(char *name) |
{ |
const union acpi_predefined_info *this_name; |
/* Quick check for a predefined name, first character must be underscore */ |
if (name[0] != '_') { |
return (NULL); |
} |
/* Search info table for a predefined method/object name */ |
this_name = acpi_gbl_resource_names; |
while (this_name->info.name[0]) { |
if (ACPI_COMPARE_NAME(name, this_name->info.name)) { |
return (this_name); |
} |
this_name++; |
} |
return (NULL); /* Not found */ |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_display_predefined_method |
* |
* PARAMETERS: buffer - Scratch buffer for this function |
* this_name - Entry in the predefined method/name table |
* multi_line - TRUE if output should be on >1 line |
* |
* RETURN: None |
* |
* DESCRIPTION: Display information about a predefined method. Number and |
* type of the input arguments, and expected type(s) for the |
* return value, if any. |
* |
******************************************************************************/ |
void |
acpi_ut_display_predefined_method(char *buffer, |
const union acpi_predefined_info *this_name, |
u8 multi_line) |
{ |
u32 arg_count; |
/* |
* Get the argument count and the string buffer |
* containing all argument types |
*/ |
arg_count = acpi_ut_get_argument_types(buffer, |
this_name->info.argument_list); |
if (multi_line) { |
printf(" "); |
} |
printf("%4.4s Requires %s%u argument%s", |
this_name->info.name, |
(this_name->info.argument_list & ARG_COUNT_IS_MINIMUM) ? |
"(at least) " : "", arg_count, arg_count != 1 ? "s" : ""); |
/* Display the types for any arguments */ |
if (arg_count > 0) { |
printf(" (%s)", buffer); |
} |
if (multi_line) { |
printf("\n "); |
} |
/* Get the return value type(s) allowed */ |
if (this_name->info.expected_btypes) { |
acpi_ut_get_expected_return_types(buffer, |
this_name->info. |
expected_btypes); |
printf(" Return value types: %s\n", buffer); |
} else { |
printf(" No return value\n"); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_argument_types |
* |
* PARAMETERS: buffer - Where to return the formatted types |
* argument_types - Types field for this method |
* |
* RETURN: count - the number of arguments required for this method |
* |
* DESCRIPTION: Format the required data types for this method (Integer, |
* String, Buffer, or Package) and return the required argument |
* count. |
* |
******************************************************************************/ |
static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types) |
{ |
u16 this_argument_type; |
u16 sub_index; |
u16 arg_count; |
u32 i; |
*buffer = 0; |
sub_index = 2; |
/* First field in the types list is the count of args to follow */ |
arg_count = METHOD_GET_ARG_COUNT(argument_types); |
if (arg_count > METHOD_PREDEF_ARGS_MAX) { |
printf("**** Invalid argument count (%u) " |
"in predefined info structure\n", arg_count); |
return (arg_count); |
} |
/* Get each argument from the list, convert to ascii, store to buffer */ |
for (i = 0; i < arg_count; i++) { |
this_argument_type = METHOD_GET_NEXT_TYPE(argument_types); |
if (!this_argument_type |
|| (this_argument_type > METHOD_MAX_ARG_TYPE)) { |
printf("**** Invalid argument type (%u) " |
"in predefined info structure\n", |
this_argument_type); |
return (arg_count); |
} |
strcat(buffer, |
ut_external_type_names[this_argument_type] + sub_index); |
sub_index = 0; |
} |
return (arg_count); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_resource_bit_width |
* |
* PARAMETERS: buffer - Where the formatted string is returned |
* types - Bitfield of expected data types |
* |
* RETURN: Count of return types. Formatted string in Buffer. |
* |
* DESCRIPTION: Format the resource bit widths into a printable string. |
* |
******************************************************************************/ |
u32 acpi_ut_get_resource_bit_width(char *buffer, u16 types) |
{ |
u32 i; |
u16 sub_index; |
u32 found; |
*buffer = 0; |
sub_index = 1; |
found = 0; |
for (i = 0; i < NUM_RESOURCE_WIDTHS; i++) { |
if (types & 1) { |
strcat(buffer, &(ut_resource_type_names[i][sub_index])); |
sub_index = 0; |
found++; |
} |
types >>= 1; |
} |
return (found); |
} |
#endif |
/drivers/acpi/acpica/utprint.c |
---|
0,0 → 1,667 |
/****************************************************************************** |
* |
* Module Name: utprint - Formatted printing routines |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utprint") |
#define ACPI_FORMAT_SIGN 0x01 |
#define ACPI_FORMAT_SIGN_PLUS 0x02 |
#define ACPI_FORMAT_SIGN_PLUS_SPACE 0x04 |
#define ACPI_FORMAT_ZERO 0x08 |
#define ACPI_FORMAT_LEFT 0x10 |
#define ACPI_FORMAT_UPPER 0x20 |
#define ACPI_FORMAT_PREFIX 0x40 |
/* Local prototypes */ |
static acpi_size |
acpi_ut_bound_string_length(const char *string, acpi_size count); |
static char *acpi_ut_bound_string_output(char *string, const char *end, char c); |
static char *acpi_ut_format_number(char *string, |
char *end, |
u64 number, |
u8 base, s32 width, s32 precision, u8 type); |
static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper); |
/* Module globals */ |
static const char acpi_gbl_lower_hex_digits[] = "0123456789abcdef"; |
static const char acpi_gbl_upper_hex_digits[] = "0123456789ABCDEF"; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_bound_string_length |
* |
* PARAMETERS: string - String with boundary |
* count - Boundary of the string |
* |
* RETURN: Length of the string. Less than or equal to Count. |
* |
* DESCRIPTION: Calculate the length of a string with boundary. |
* |
******************************************************************************/ |
static acpi_size |
acpi_ut_bound_string_length(const char *string, acpi_size count) |
{ |
u32 length = 0; |
while (*string && count) { |
length++; |
string++; |
count--; |
} |
return (length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_bound_string_output |
* |
* PARAMETERS: string - String with boundary |
* end - Boundary of the string |
* c - Character to be output to the string |
* |
* RETURN: Updated position for next valid character |
* |
* DESCRIPTION: Output a character into a string with boundary check. |
* |
******************************************************************************/ |
static char *acpi_ut_bound_string_output(char *string, const char *end, char c) |
{ |
if (string < end) { |
*string = c; |
} |
++string; |
return (string); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_put_number |
* |
* PARAMETERS: string - Buffer to hold reverse-ordered string |
* number - Integer to be converted |
* base - Base of the integer |
* upper - Whether or not using upper cased digits |
* |
* RETURN: Updated position for next valid character |
* |
* DESCRIPTION: Convert an integer into a string, note that, the string holds a |
* reversed ordered number without the trailing zero. |
* |
******************************************************************************/ |
static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper) |
{ |
const char *digits; |
u64 digit_index; |
char *pos; |
pos = string; |
digits = upper ? acpi_gbl_upper_hex_digits : acpi_gbl_lower_hex_digits; |
if (number == 0) { |
*(pos++) = '0'; |
} else { |
while (number) { |
(void)acpi_ut_divide(number, base, &number, |
&digit_index); |
*(pos++) = digits[digit_index]; |
} |
} |
/* *(Pos++) = '0'; */ |
return (pos); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_scan_number |
* |
* PARAMETERS: string - String buffer |
* number_ptr - Where the number is returned |
* |
* RETURN: Updated position for next valid character |
* |
* DESCRIPTION: Scan a string for a decimal integer. |
* |
******************************************************************************/ |
const char *acpi_ut_scan_number(const char *string, u64 *number_ptr) |
{ |
u64 number = 0; |
while (isdigit((int)*string)) { |
number *= 10; |
number += *(string++) - '0'; |
} |
*number_ptr = number; |
return (string); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_print_number |
* |
* PARAMETERS: string - String buffer |
* number - The number to be converted |
* |
* RETURN: Updated position for next valid character |
* |
* DESCRIPTION: Print a decimal integer into a string. |
* |
******************************************************************************/ |
const char *acpi_ut_print_number(char *string, u64 number) |
{ |
char ascii_string[20]; |
const char *pos1; |
char *pos2; |
pos1 = acpi_ut_put_number(ascii_string, number, 10, FALSE); |
pos2 = string; |
while (pos1 != ascii_string) { |
*(pos2++) = *(--pos1); |
} |
*pos2 = 0; |
return (string); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_format_number |
* |
* PARAMETERS: string - String buffer with boundary |
* end - Boundary of the string |
* number - The number to be converted |
* base - Base of the integer |
* width - Field width |
* precision - Precision of the integer |
* type - Special printing flags |
* |
* RETURN: Updated position for next valid character |
* |
* DESCRIPTION: Print an integer into a string with any base and any precision. |
* |
******************************************************************************/ |
static char *acpi_ut_format_number(char *string, |
char *end, |
u64 number, |
u8 base, s32 width, s32 precision, u8 type) |
{ |
char *pos; |
char sign; |
char zero; |
u8 need_prefix; |
u8 upper; |
s32 i; |
char reversed_string[66]; |
/* Parameter validation */ |
if (base < 2 || base > 16) { |
return (NULL); |
} |
if (type & ACPI_FORMAT_LEFT) { |
type &= ~ACPI_FORMAT_ZERO; |
} |
need_prefix = ((type & ACPI_FORMAT_PREFIX) |
&& base != 10) ? TRUE : FALSE; |
upper = (type & ACPI_FORMAT_UPPER) ? TRUE : FALSE; |
zero = (type & ACPI_FORMAT_ZERO) ? '0' : ' '; |
/* Calculate size according to sign and prefix */ |
sign = '\0'; |
if (type & ACPI_FORMAT_SIGN) { |
if ((s64) number < 0) { |
sign = '-'; |
number = -(s64) number; |
width--; |
} else if (type & ACPI_FORMAT_SIGN_PLUS) { |
sign = '+'; |
width--; |
} else if (type & ACPI_FORMAT_SIGN_PLUS_SPACE) { |
sign = ' '; |
width--; |
} |
} |
if (need_prefix) { |
width--; |
if (base == 16) { |
width--; |
} |
} |
/* Generate full string in reverse order */ |
pos = acpi_ut_put_number(reversed_string, number, base, upper); |
i = ACPI_PTR_DIFF(pos, reversed_string); |
/* Printing 100 using %2d gives "100", not "00" */ |
if (i > precision) { |
precision = i; |
} |
width -= precision; |
/* Output the string */ |
if (!(type & (ACPI_FORMAT_ZERO | ACPI_FORMAT_LEFT))) { |
while (--width >= 0) { |
string = acpi_ut_bound_string_output(string, end, ' '); |
} |
} |
if (sign) { |
string = acpi_ut_bound_string_output(string, end, sign); |
} |
if (need_prefix) { |
string = acpi_ut_bound_string_output(string, end, '0'); |
if (base == 16) { |
string = acpi_ut_bound_string_output(string, end, |
upper ? 'X' : 'x'); |
} |
} |
if (!(type & ACPI_FORMAT_LEFT)) { |
while (--width >= 0) { |
string = acpi_ut_bound_string_output(string, end, zero); |
} |
} |
while (i <= --precision) { |
string = acpi_ut_bound_string_output(string, end, '0'); |
} |
while (--i >= 0) { |
string = acpi_ut_bound_string_output(string, end, |
reversed_string[i]); |
} |
while (--width >= 0) { |
string = acpi_ut_bound_string_output(string, end, ' '); |
} |
return (string); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_vsnprintf |
* |
* PARAMETERS: string - String with boundary |
* size - Boundary of the string |
* format - Standard printf format |
* args - Argument list |
* |
* RETURN: Number of bytes actually written. |
* |
* DESCRIPTION: Formatted output to a string using argument list pointer. |
* |
******************************************************************************/ |
int |
acpi_ut_vsnprintf(char *string, |
acpi_size size, const char *format, va_list args) |
{ |
u8 base; |
u8 type; |
s32 width; |
s32 precision; |
char qualifier; |
u64 number; |
char *pos; |
char *end; |
char c; |
const char *s; |
const void *p; |
s32 length; |
int i; |
pos = string; |
end = string + size; |
for (; *format; ++format) { |
if (*format != '%') { |
pos = acpi_ut_bound_string_output(pos, end, *format); |
continue; |
} |
type = 0; |
base = 10; |
/* Process sign */ |
do { |
++format; |
if (*format == '#') { |
type |= ACPI_FORMAT_PREFIX; |
} else if (*format == '0') { |
type |= ACPI_FORMAT_ZERO; |
} else if (*format == '+') { |
type |= ACPI_FORMAT_SIGN_PLUS; |
} else if (*format == ' ') { |
type |= ACPI_FORMAT_SIGN_PLUS_SPACE; |
} else if (*format == '-') { |
type |= ACPI_FORMAT_LEFT; |
} else { |
break; |
} |
} while (1); |
/* Process width */ |
width = -1; |
if (isdigit((int)*format)) { |
format = acpi_ut_scan_number(format, &number); |
width = (s32) number; |
} else if (*format == '*') { |
++format; |
width = va_arg(args, int); |
if (width < 0) { |
width = -width; |
type |= ACPI_FORMAT_LEFT; |
} |
} |
/* Process precision */ |
precision = -1; |
if (*format == '.') { |
++format; |
if (isdigit((int)*format)) { |
format = acpi_ut_scan_number(format, &number); |
precision = (s32) number; |
} else if (*format == '*') { |
++format; |
precision = va_arg(args, int); |
} |
if (precision < 0) { |
precision = 0; |
} |
} |
/* Process qualifier */ |
qualifier = -1; |
if (*format == 'h' || *format == 'l' || *format == 'L') { |
qualifier = *format; |
++format; |
if (qualifier == 'l' && *format == 'l') { |
qualifier = 'L'; |
++format; |
} |
} |
switch (*format) { |
case '%': |
pos = acpi_ut_bound_string_output(pos, end, '%'); |
continue; |
case 'c': |
if (!(type & ACPI_FORMAT_LEFT)) { |
while (--width > 0) { |
pos = |
acpi_ut_bound_string_output(pos, |
end, |
' '); |
} |
} |
c = (char)va_arg(args, int); |
pos = acpi_ut_bound_string_output(pos, end, c); |
while (--width > 0) { |
pos = |
acpi_ut_bound_string_output(pos, end, ' '); |
} |
continue; |
case 's': |
s = va_arg(args, char *); |
if (!s) { |
s = "<NULL>"; |
} |
length = acpi_ut_bound_string_length(s, precision); |
if (!(type & ACPI_FORMAT_LEFT)) { |
while (length < width--) { |
pos = |
acpi_ut_bound_string_output(pos, |
end, |
' '); |
} |
} |
for (i = 0; i < length; ++i) { |
pos = acpi_ut_bound_string_output(pos, end, *s); |
++s; |
} |
while (length < width--) { |
pos = |
acpi_ut_bound_string_output(pos, end, ' '); |
} |
continue; |
case 'o': |
base = 8; |
break; |
case 'X': |
type |= ACPI_FORMAT_UPPER; |
case 'x': |
base = 16; |
break; |
case 'd': |
case 'i': |
type |= ACPI_FORMAT_SIGN; |
case 'u': |
break; |
case 'p': |
if (width == -1) { |
width = 2 * sizeof(void *); |
type |= ACPI_FORMAT_ZERO; |
} |
p = va_arg(args, void *); |
pos = acpi_ut_format_number(pos, end, |
ACPI_TO_INTEGER(p), 16, |
width, precision, type); |
continue; |
default: |
pos = acpi_ut_bound_string_output(pos, end, '%'); |
if (*format) { |
pos = |
acpi_ut_bound_string_output(pos, end, |
*format); |
} else { |
--format; |
} |
continue; |
} |
if (qualifier == 'L') { |
number = va_arg(args, u64); |
if (type & ACPI_FORMAT_SIGN) { |
number = (s64) number; |
} |
} else if (qualifier == 'l') { |
number = va_arg(args, unsigned long); |
if (type & ACPI_FORMAT_SIGN) { |
number = (s32) number; |
} |
} else if (qualifier == 'h') { |
number = (u16)va_arg(args, int); |
if (type & ACPI_FORMAT_SIGN) { |
number = (s16) number; |
} |
} else { |
number = va_arg(args, unsigned int); |
if (type & ACPI_FORMAT_SIGN) { |
number = (signed int)number; |
} |
} |
pos = acpi_ut_format_number(pos, end, number, base, |
width, precision, type); |
} |
if (size > 0) { |
if (pos < end) { |
*pos = '\0'; |
} else { |
end[-1] = '\0'; |
} |
} |
return (ACPI_PTR_DIFF(pos, string)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_snprintf |
* |
* PARAMETERS: string - String with boundary |
* size - Boundary of the string |
* Format, ... - Standard printf format |
* |
* RETURN: Number of bytes actually written. |
* |
* DESCRIPTION: Formatted output to a string. |
* |
******************************************************************************/ |
int acpi_ut_snprintf(char *string, acpi_size size, const char *format, ...) |
{ |
va_list args; |
int length; |
va_start(args, format); |
length = acpi_ut_vsnprintf(string, size, format, args); |
va_end(args); |
return (length); |
} |
#ifdef ACPI_APPLICATION |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_file_vprintf |
* |
* PARAMETERS: file - File descriptor |
* format - Standard printf format |
* args - Argument list |
* |
* RETURN: Number of bytes actually written. |
* |
* DESCRIPTION: Formatted output to a file using argument list pointer. |
* |
******************************************************************************/ |
int acpi_ut_file_vprintf(ACPI_FILE file, const char *format, va_list args) |
{ |
acpi_cpu_flags flags; |
int length; |
flags = acpi_os_acquire_lock(acpi_gbl_print_lock); |
length = acpi_ut_vsnprintf(acpi_gbl_print_buffer, |
sizeof(acpi_gbl_print_buffer), format, args); |
(void)acpi_os_write_file(file, acpi_gbl_print_buffer, length, 1); |
acpi_os_release_lock(acpi_gbl_print_lock, flags); |
return (length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_file_printf |
* |
* PARAMETERS: file - File descriptor |
* Format, ... - Standard printf format |
* |
* RETURN: Number of bytes actually written. |
* |
* DESCRIPTION: Formatted output to a file. |
* |
******************************************************************************/ |
int acpi_ut_file_printf(ACPI_FILE file, const char *format, ...) |
{ |
va_list args; |
int length; |
va_start(args, format); |
length = acpi_ut_file_vprintf(file, format, args); |
va_end(args); |
return (length); |
} |
#endif |
/drivers/acpi/acpica/utresrc.c |
---|
0,0 → 1,830 |
/******************************************************************************* |
* |
* Module Name: utresrc - Resource management utilities |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acresrc.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utresrc") |
#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) |
/* |
* Strings used to decode resource descriptors. |
* Used by both the disassembler and the debugger resource dump routines |
*/ |
const char *acpi_gbl_bm_decode[] = { |
"NotBusMaster", |
"BusMaster" |
}; |
const char *acpi_gbl_config_decode[] = { |
"0 - Good Configuration", |
"1 - Acceptable Configuration", |
"2 - Suboptimal Configuration", |
"3 - ***Invalid Configuration***", |
}; |
const char *acpi_gbl_consume_decode[] = { |
"ResourceProducer", |
"ResourceConsumer" |
}; |
const char *acpi_gbl_dec_decode[] = { |
"PosDecode", |
"SubDecode" |
}; |
const char *acpi_gbl_he_decode[] = { |
"Level", |
"Edge" |
}; |
const char *acpi_gbl_io_decode[] = { |
"Decode10", |
"Decode16" |
}; |
const char *acpi_gbl_ll_decode[] = { |
"ActiveHigh", |
"ActiveLow", |
"ActiveBoth", |
"Reserved" |
}; |
const char *acpi_gbl_max_decode[] = { |
"MaxNotFixed", |
"MaxFixed" |
}; |
const char *acpi_gbl_mem_decode[] = { |
"NonCacheable", |
"Cacheable", |
"WriteCombining", |
"Prefetchable" |
}; |
const char *acpi_gbl_min_decode[] = { |
"MinNotFixed", |
"MinFixed" |
}; |
const char *acpi_gbl_mtp_decode[] = { |
"AddressRangeMemory", |
"AddressRangeReserved", |
"AddressRangeACPI", |
"AddressRangeNVS" |
}; |
const char *acpi_gbl_rng_decode[] = { |
"InvalidRanges", |
"NonISAOnlyRanges", |
"ISAOnlyRanges", |
"EntireRange" |
}; |
const char *acpi_gbl_rw_decode[] = { |
"ReadOnly", |
"ReadWrite" |
}; |
const char *acpi_gbl_shr_decode[] = { |
"Exclusive", |
"Shared", |
"ExclusiveAndWake", /* ACPI 5.0 */ |
"SharedAndWake" /* ACPI 5.0 */ |
}; |
const char *acpi_gbl_siz_decode[] = { |
"Transfer8", |
"Transfer8_16", |
"Transfer16", |
"InvalidSize" |
}; |
const char *acpi_gbl_trs_decode[] = { |
"DenseTranslation", |
"SparseTranslation" |
}; |
const char *acpi_gbl_ttp_decode[] = { |
"TypeStatic", |
"TypeTranslation" |
}; |
const char *acpi_gbl_typ_decode[] = { |
"Compatibility", |
"TypeA", |
"TypeB", |
"TypeF" |
}; |
const char *acpi_gbl_ppc_decode[] = { |
"PullDefault", |
"PullUp", |
"PullDown", |
"PullNone" |
}; |
const char *acpi_gbl_ior_decode[] = { |
"IoRestrictionNone", |
"IoRestrictionInputOnly", |
"IoRestrictionOutputOnly", |
"IoRestrictionNoneAndPreserve" |
}; |
const char *acpi_gbl_dts_decode[] = { |
"Width8bit", |
"Width16bit", |
"Width32bit", |
"Width64bit", |
"Width128bit", |
"Width256bit", |
}; |
/* GPIO connection type */ |
const char *acpi_gbl_ct_decode[] = { |
"Interrupt", |
"I/O" |
}; |
/* Serial bus type */ |
const char *acpi_gbl_sbt_decode[] = { |
"/* UNKNOWN serial bus type */", |
"I2C", |
"SPI", |
"UART" |
}; |
/* I2C serial bus access mode */ |
const char *acpi_gbl_am_decode[] = { |
"AddressingMode7Bit", |
"AddressingMode10Bit" |
}; |
/* I2C serial bus slave mode */ |
const char *acpi_gbl_sm_decode[] = { |
"ControllerInitiated", |
"DeviceInitiated" |
}; |
/* SPI serial bus wire mode */ |
const char *acpi_gbl_wm_decode[] = { |
"FourWireMode", |
"ThreeWireMode" |
}; |
/* SPI serial clock phase */ |
const char *acpi_gbl_cph_decode[] = { |
"ClockPhaseFirst", |
"ClockPhaseSecond" |
}; |
/* SPI serial bus clock polarity */ |
const char *acpi_gbl_cpo_decode[] = { |
"ClockPolarityLow", |
"ClockPolarityHigh" |
}; |
/* SPI serial bus device polarity */ |
const char *acpi_gbl_dp_decode[] = { |
"PolarityLow", |
"PolarityHigh" |
}; |
/* UART serial bus endian */ |
const char *acpi_gbl_ed_decode[] = { |
"LittleEndian", |
"BigEndian" |
}; |
/* UART serial bus bits per byte */ |
const char *acpi_gbl_bpb_decode[] = { |
"DataBitsFive", |
"DataBitsSix", |
"DataBitsSeven", |
"DataBitsEight", |
"DataBitsNine", |
"/* UNKNOWN Bits per byte */", |
"/* UNKNOWN Bits per byte */", |
"/* UNKNOWN Bits per byte */" |
}; |
/* UART serial bus stop bits */ |
const char *acpi_gbl_sb_decode[] = { |
"StopBitsZero", |
"StopBitsOne", |
"StopBitsOnePlusHalf", |
"StopBitsTwo" |
}; |
/* UART serial bus flow control */ |
const char *acpi_gbl_fc_decode[] = { |
"FlowControlNone", |
"FlowControlHardware", |
"FlowControlXON", |
"/* UNKNOWN flow control keyword */" |
}; |
/* UART serial bus parity type */ |
const char *acpi_gbl_pt_decode[] = { |
"ParityTypeNone", |
"ParityTypeEven", |
"ParityTypeOdd", |
"ParityTypeMark", |
"ParityTypeSpace", |
"/* UNKNOWN parity keyword */", |
"/* UNKNOWN parity keyword */", |
"/* UNKNOWN parity keyword */" |
}; |
#endif |
/* |
* Base sizes of the raw AML resource descriptors, indexed by resource type. |
* Zero indicates a reserved (and therefore invalid) resource type. |
*/ |
const u8 acpi_gbl_resource_aml_sizes[] = { |
/* Small descriptors */ |
0, |
0, |
0, |
0, |
ACPI_AML_SIZE_SMALL(struct aml_resource_irq), |
ACPI_AML_SIZE_SMALL(struct aml_resource_dma), |
ACPI_AML_SIZE_SMALL(struct aml_resource_start_dependent), |
ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent), |
ACPI_AML_SIZE_SMALL(struct aml_resource_io), |
ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io), |
ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma), |
0, |
0, |
0, |
ACPI_AML_SIZE_SMALL(struct aml_resource_vendor_small), |
ACPI_AML_SIZE_SMALL(struct aml_resource_end_tag), |
/* Large descriptors */ |
0, |
ACPI_AML_SIZE_LARGE(struct aml_resource_memory24), |
ACPI_AML_SIZE_LARGE(struct aml_resource_generic_register), |
0, |
ACPI_AML_SIZE_LARGE(struct aml_resource_vendor_large), |
ACPI_AML_SIZE_LARGE(struct aml_resource_memory32), |
ACPI_AML_SIZE_LARGE(struct aml_resource_fixed_memory32), |
ACPI_AML_SIZE_LARGE(struct aml_resource_address32), |
ACPI_AML_SIZE_LARGE(struct aml_resource_address16), |
ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq), |
ACPI_AML_SIZE_LARGE(struct aml_resource_address64), |
ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64), |
ACPI_AML_SIZE_LARGE(struct aml_resource_gpio), |
0, |
ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus), |
}; |
const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = { |
0, |
ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus), |
ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus), |
ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus), |
}; |
/* |
* Resource types, used to validate the resource length field. |
* The length of fixed-length types must match exactly, variable |
* lengths must meet the minimum required length, etc. |
* Zero indicates a reserved (and therefore invalid) resource type. |
*/ |
static const u8 acpi_gbl_resource_types[] = { |
/* Small descriptors */ |
0, |
0, |
0, |
0, |
ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */ |
ACPI_FIXED_LENGTH, /* 05 DMA */ |
ACPI_SMALL_VARIABLE_LENGTH, /* 06 start_dependent_functions */ |
ACPI_FIXED_LENGTH, /* 07 end_dependent_functions */ |
ACPI_FIXED_LENGTH, /* 08 IO */ |
ACPI_FIXED_LENGTH, /* 09 fixed_IO */ |
ACPI_FIXED_LENGTH, /* 0A fixed_DMA */ |
0, |
0, |
0, |
ACPI_VARIABLE_LENGTH, /* 0E vendor_short */ |
ACPI_FIXED_LENGTH, /* 0F end_tag */ |
/* Large descriptors */ |
0, |
ACPI_FIXED_LENGTH, /* 01 Memory24 */ |
ACPI_FIXED_LENGTH, /* 02 generic_register */ |
0, |
ACPI_VARIABLE_LENGTH, /* 04 vendor_long */ |
ACPI_FIXED_LENGTH, /* 05 Memory32 */ |
ACPI_FIXED_LENGTH, /* 06 memory32_fixed */ |
ACPI_VARIABLE_LENGTH, /* 07 Dword* address */ |
ACPI_VARIABLE_LENGTH, /* 08 Word* address */ |
ACPI_VARIABLE_LENGTH, /* 09 extended_IRQ */ |
ACPI_VARIABLE_LENGTH, /* 0A Qword* address */ |
ACPI_FIXED_LENGTH, /* 0B Extended* address */ |
ACPI_VARIABLE_LENGTH, /* 0C Gpio* */ |
0, |
ACPI_VARIABLE_LENGTH /* 0E *serial_bus */ |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_walk_aml_resources |
* |
* PARAMETERS: walk_state - Current walk info |
* PARAMETERS: aml - Pointer to the raw AML resource template |
* aml_length - Length of the entire template |
* user_function - Called once for each descriptor found. If |
* NULL, a pointer to the end_tag is returned |
* context - Passed to user_function |
* |
* RETURN: Status |
* |
* DESCRIPTION: Walk a raw AML resource list(buffer). User function called |
* once for each resource found. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, |
u8 *aml, |
acpi_size aml_length, |
acpi_walk_aml_callback user_function, void **context) |
{ |
acpi_status status; |
u8 *end_aml; |
u8 resource_index; |
u32 length; |
u32 offset = 0; |
u8 end_tag[2] = { 0x79, 0x00 }; |
ACPI_FUNCTION_TRACE(ut_walk_aml_resources); |
/* The absolute minimum resource template is one end_tag descriptor */ |
if (aml_length < sizeof(struct aml_resource_end_tag)) { |
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); |
} |
/* Point to the end of the resource template buffer */ |
end_aml = aml + aml_length; |
/* Walk the byte list, abort on any invalid descriptor type or length */ |
while (aml < end_aml) { |
/* Validate the Resource Type and Resource Length */ |
status = |
acpi_ut_validate_resource(walk_state, aml, &resource_index); |
if (ACPI_FAILURE(status)) { |
/* |
* Exit on failure. Cannot continue because the descriptor length |
* may be bogus also. |
*/ |
return_ACPI_STATUS(status); |
} |
/* Get the length of this descriptor */ |
length = acpi_ut_get_descriptor_length(aml); |
/* Invoke the user function */ |
if (user_function) { |
status = |
user_function(aml, length, offset, resource_index, |
context); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* An end_tag descriptor terminates this resource template */ |
if (acpi_ut_get_resource_type(aml) == |
ACPI_RESOURCE_NAME_END_TAG) { |
/* |
* There must be at least one more byte in the buffer for |
* the 2nd byte of the end_tag |
*/ |
if ((aml + 1) >= end_aml) { |
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); |
} |
/* Return the pointer to the end_tag if requested */ |
if (!user_function) { |
*context = aml; |
} |
/* Normal exit */ |
return_ACPI_STATUS(AE_OK); |
} |
aml += length; |
offset += length; |
} |
/* Did not find an end_tag descriptor */ |
if (user_function) { |
/* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */ |
(void)acpi_ut_validate_resource(walk_state, end_tag, |
&resource_index); |
status = |
user_function(end_tag, 2, offset, resource_index, context); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_validate_resource |
* |
* PARAMETERS: walk_state - Current walk info |
* aml - Pointer to the raw AML resource descriptor |
* return_index - Where the resource index is returned. NULL |
* if the index is not required. |
* |
* RETURN: Status, and optionally the Index into the global resource tables |
* |
* DESCRIPTION: Validate an AML resource descriptor by checking the Resource |
* Type and Resource Length. Returns an index into the global |
* resource information/dispatch tables for later use. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_validate_resource(struct acpi_walk_state *walk_state, |
void *aml, u8 *return_index) |
{ |
union aml_resource *aml_resource; |
u8 resource_type; |
u8 resource_index; |
acpi_rs_length resource_length; |
acpi_rs_length minimum_resource_length; |
ACPI_FUNCTION_ENTRY(); |
/* |
* 1) Validate the resource_type field (Byte 0) |
*/ |
resource_type = ACPI_GET8(aml); |
/* |
* Byte 0 contains the descriptor name (Resource Type) |
* Examine the large/small bit in the resource header |
*/ |
if (resource_type & ACPI_RESOURCE_NAME_LARGE) { |
/* Verify the large resource type (name) against the max */ |
if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) { |
goto invalid_resource; |
} |
/* |
* Large Resource Type -- bits 6:0 contain the name |
* Translate range 0x80-0x8B to index range 0x10-0x1B |
*/ |
resource_index = (u8) (resource_type - 0x70); |
} else { |
/* |
* Small Resource Type -- bits 6:3 contain the name |
* Shift range to index range 0x00-0x0F |
*/ |
resource_index = (u8) |
((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3); |
} |
/* |
* Check validity of the resource type, via acpi_gbl_resource_types. Zero |
* indicates an invalid resource. |
*/ |
if (!acpi_gbl_resource_types[resource_index]) { |
goto invalid_resource; |
} |
/* |
* Validate the resource_length field. This ensures that the length |
* is at least reasonable, and guarantees that it is non-zero. |
*/ |
resource_length = acpi_ut_get_resource_length(aml); |
minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index]; |
/* Validate based upon the type of resource - fixed length or variable */ |
switch (acpi_gbl_resource_types[resource_index]) { |
case ACPI_FIXED_LENGTH: |
/* Fixed length resource, length must match exactly */ |
if (resource_length != minimum_resource_length) { |
goto bad_resource_length; |
} |
break; |
case ACPI_VARIABLE_LENGTH: |
/* Variable length resource, length must be at least the minimum */ |
if (resource_length < minimum_resource_length) { |
goto bad_resource_length; |
} |
break; |
case ACPI_SMALL_VARIABLE_LENGTH: |
/* Small variable length resource, length can be (Min) or (Min-1) */ |
if ((resource_length > minimum_resource_length) || |
(resource_length < (minimum_resource_length - 1))) { |
goto bad_resource_length; |
} |
break; |
default: |
/* Shouldn't happen (because of validation earlier), but be sure */ |
goto invalid_resource; |
} |
aml_resource = ACPI_CAST_PTR(union aml_resource, aml); |
if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) { |
/* Validate the bus_type field */ |
if ((aml_resource->common_serial_bus.type == 0) || |
(aml_resource->common_serial_bus.type > |
AML_RESOURCE_MAX_SERIALBUSTYPE)) { |
if (walk_state) { |
ACPI_ERROR((AE_INFO, |
"Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", |
aml_resource->common_serial_bus. |
type)); |
} |
return (AE_AML_INVALID_RESOURCE_TYPE); |
} |
} |
/* Optionally return the resource table index */ |
if (return_index) { |
*return_index = resource_index; |
} |
return (AE_OK); |
invalid_resource: |
if (walk_state) { |
ACPI_ERROR((AE_INFO, |
"Invalid/unsupported resource descriptor: Type 0x%2.2X", |
resource_type)); |
} |
return (AE_AML_INVALID_RESOURCE_TYPE); |
bad_resource_length: |
if (walk_state) { |
ACPI_ERROR((AE_INFO, |
"Invalid resource descriptor length: Type " |
"0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X", |
resource_type, resource_length, |
minimum_resource_length)); |
} |
return (AE_AML_BAD_RESOURCE_LENGTH); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_resource_type |
* |
* PARAMETERS: aml - Pointer to the raw AML resource descriptor |
* |
* RETURN: The Resource Type with no extraneous bits (except the |
* Large/Small descriptor bit -- this is left alone) |
* |
* DESCRIPTION: Extract the Resource Type/Name from the first byte of |
* a resource descriptor. |
* |
******************************************************************************/ |
u8 acpi_ut_get_resource_type(void *aml) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* |
* Byte 0 contains the descriptor name (Resource Type) |
* Examine the large/small bit in the resource header |
*/ |
if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { |
/* Large Resource Type -- bits 6:0 contain the name */ |
return (ACPI_GET8(aml)); |
} else { |
/* Small Resource Type -- bits 6:3 contain the name */ |
return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_resource_length |
* |
* PARAMETERS: aml - Pointer to the raw AML resource descriptor |
* |
* RETURN: Byte Length |
* |
* DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By |
* definition, this does not include the size of the descriptor |
* header or the length field itself. |
* |
******************************************************************************/ |
u16 acpi_ut_get_resource_length(void *aml) |
{ |
acpi_rs_length resource_length; |
ACPI_FUNCTION_ENTRY(); |
/* |
* Byte 0 contains the descriptor name (Resource Type) |
* Examine the large/small bit in the resource header |
*/ |
if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { |
/* Large Resource type -- bytes 1-2 contain the 16-bit length */ |
ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1)); |
} else { |
/* Small Resource type -- bits 2:0 of byte 0 contain the length */ |
resource_length = (u16) (ACPI_GET8(aml) & |
ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK); |
} |
return (resource_length); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_resource_header_length |
* |
* PARAMETERS: aml - Pointer to the raw AML resource descriptor |
* |
* RETURN: Length of the AML header (depends on large/small descriptor) |
* |
* DESCRIPTION: Get the length of the header for this resource. |
* |
******************************************************************************/ |
u8 acpi_ut_get_resource_header_length(void *aml) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Examine the large/small bit in the resource header */ |
if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { |
return (sizeof(struct aml_resource_large_header)); |
} else { |
return (sizeof(struct aml_resource_small_header)); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_descriptor_length |
* |
* PARAMETERS: aml - Pointer to the raw AML resource descriptor |
* |
* RETURN: Byte length |
* |
* DESCRIPTION: Get the total byte length of a raw AML descriptor, including the |
* length of the descriptor header and the length field itself. |
* Used to walk descriptor lists. |
* |
******************************************************************************/ |
u32 acpi_ut_get_descriptor_length(void *aml) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* |
* Get the Resource Length (does not include header length) and add |
* the header length (depends on if this is a small or large resource) |
*/ |
return (acpi_ut_get_resource_length(aml) + |
acpi_ut_get_resource_header_length(aml)); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_resource_end_tag |
* |
* PARAMETERS: obj_desc - The resource template buffer object |
* end_tag - Where the pointer to the end_tag is returned |
* |
* RETURN: Status, pointer to the end tag |
* |
* DESCRIPTION: Find the end_tag resource descriptor in an AML resource template |
* Note: allows a buffer length of zero. |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(ut_get_resource_end_tag); |
/* Allow a buffer length of zero */ |
if (!obj_desc->buffer.length) { |
*end_tag = obj_desc->buffer.pointer; |
return_ACPI_STATUS(AE_OK); |
} |
/* Validate the template and get a pointer to the end_tag */ |
status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer, |
obj_desc->buffer.length, NULL, |
(void **)end_tag); |
return_ACPI_STATUS(status); |
} |
/drivers/acpi/acpica/utstate.c |
---|
0,0 → 1,308 |
/******************************************************************************* |
* |
* Module Name: utstate - state object support procedures |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utstate") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_push_generic_state |
* |
* PARAMETERS: list_head - Head of the state stack |
* state - State object to push |
* |
* RETURN: None |
* |
* DESCRIPTION: Push a state object onto a state stack |
* |
******************************************************************************/ |
void |
acpi_ut_push_generic_state(union acpi_generic_state **list_head, |
union acpi_generic_state *state) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Push the state object onto the front of the list (stack) */ |
state->common.next = *list_head; |
*list_head = state; |
return; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_pop_generic_state |
* |
* PARAMETERS: list_head - Head of the state stack |
* |
* RETURN: The popped state object |
* |
* DESCRIPTION: Pop a state object from a state stack |
* |
******************************************************************************/ |
union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state |
**list_head) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_ENTRY(); |
/* Remove the state object at the head of the list (stack) */ |
state = *list_head; |
if (state) { |
/* Update the list head */ |
*list_head = state->common.next; |
} |
return (state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_generic_state |
* |
* PARAMETERS: None |
* |
* RETURN: The new state object. NULL on failure. |
* |
* DESCRIPTION: Create a generic state object. Attempt to obtain one from |
* the global state cache; If none available, create a new one. |
* |
******************************************************************************/ |
union acpi_generic_state *acpi_ut_create_generic_state(void) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_ENTRY(); |
state = acpi_os_acquire_object(acpi_gbl_state_cache); |
if (state) { |
/* Initialize */ |
state->common.descriptor_type = ACPI_DESC_TYPE_STATE; |
} |
return (state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_thread_state |
* |
* PARAMETERS: None |
* |
* RETURN: New Thread State. NULL on failure |
* |
* DESCRIPTION: Create a "Thread State" - a flavor of the generic state used |
* to track per-thread info during method execution |
* |
******************************************************************************/ |
struct acpi_thread_state *acpi_ut_create_thread_state(void) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_ENTRY(); |
/* Create the generic state object */ |
state = acpi_ut_create_generic_state(); |
if (!state) { |
return (NULL); |
} |
/* Init fields specific to the update struct */ |
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_THREAD; |
state->thread.thread_id = acpi_os_get_thread_id(); |
/* Check for invalid thread ID - zero is very bad, it will break things */ |
if (!state->thread.thread_id) { |
ACPI_ERROR((AE_INFO, "Invalid zero ID from AcpiOsGetThreadId")); |
state->thread.thread_id = (acpi_thread_id) 1; |
} |
return ((struct acpi_thread_state *)state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_update_state |
* |
* PARAMETERS: object - Initial Object to be installed in the state |
* action - Update action to be performed |
* |
* RETURN: New state object, null on failure |
* |
* DESCRIPTION: Create an "Update State" - a flavor of the generic state used |
* to update reference counts and delete complex objects such |
* as packages. |
* |
******************************************************************************/ |
union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object |
*object, u16 action) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_ENTRY(); |
/* Create the generic state object */ |
state = acpi_ut_create_generic_state(); |
if (!state) { |
return (NULL); |
} |
/* Init fields specific to the update struct */ |
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_UPDATE; |
state->update.object = object; |
state->update.value = action; |
return (state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_pkg_state |
* |
* PARAMETERS: object - Initial Object to be installed in the state |
* action - Update action to be performed |
* |
* RETURN: New state object, null on failure |
* |
* DESCRIPTION: Create a "Package State" |
* |
******************************************************************************/ |
union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, |
void *external_object, |
u16 index) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_ENTRY(); |
/* Create the generic state object */ |
state = acpi_ut_create_generic_state(); |
if (!state) { |
return (NULL); |
} |
/* Init fields specific to the update struct */ |
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_PACKAGE; |
state->pkg.source_object = (union acpi_operand_object *)internal_object; |
state->pkg.dest_object = external_object; |
state->pkg.index = index; |
state->pkg.num_packages = 1; |
return (state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_control_state |
* |
* PARAMETERS: None |
* |
* RETURN: New state object, null on failure |
* |
* DESCRIPTION: Create a "Control State" - a flavor of the generic state used |
* to support nested IF/WHILE constructs in the AML. |
* |
******************************************************************************/ |
union acpi_generic_state *acpi_ut_create_control_state(void) |
{ |
union acpi_generic_state *state; |
ACPI_FUNCTION_ENTRY(); |
/* Create the generic state object */ |
state = acpi_ut_create_generic_state(); |
if (!state) { |
return (NULL); |
} |
/* Init fields specific to the control struct */ |
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_CONTROL; |
state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING; |
return (state); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_delete_generic_state |
* |
* PARAMETERS: state - The state object to be deleted |
* |
* RETURN: None |
* |
* DESCRIPTION: Release a state object to the state cache. NULL state objects |
* are ignored. |
* |
******************************************************************************/ |
void acpi_ut_delete_generic_state(union acpi_generic_state *state) |
{ |
ACPI_FUNCTION_ENTRY(); |
/* Ignore null state */ |
if (state) { |
(void)acpi_os_release_object(acpi_gbl_state_cache, state); |
} |
return; |
} |
/drivers/acpi/acpica/utstring.c |
---|
0,0 → 1,305 |
/******************************************************************************* |
* |
* Module Name: utstring - Common functions for strings and characters |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utstring") |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_print_string |
* |
* PARAMETERS: string - Null terminated ASCII string |
* max_length - Maximum output length. Used to constrain the |
* length of strings during debug output only. |
* |
* RETURN: None |
* |
* DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape |
* sequences. |
* |
******************************************************************************/ |
void acpi_ut_print_string(char *string, u16 max_length) |
{ |
u32 i; |
if (!string) { |
acpi_os_printf("<\"NULL STRING PTR\">"); |
return; |
} |
acpi_os_printf("\""); |
for (i = 0; (i < max_length) && string[i]; i++) { |
/* Escape sequences */ |
switch (string[i]) { |
case 0x07: |
acpi_os_printf("\\a"); /* BELL */ |
break; |
case 0x08: |
acpi_os_printf("\\b"); /* BACKSPACE */ |
break; |
case 0x0C: |
acpi_os_printf("\\f"); /* FORMFEED */ |
break; |
case 0x0A: |
acpi_os_printf("\\n"); /* LINEFEED */ |
break; |
case 0x0D: |
acpi_os_printf("\\r"); /* CARRIAGE RETURN */ |
break; |
case 0x09: |
acpi_os_printf("\\t"); /* HORIZONTAL TAB */ |
break; |
case 0x0B: |
acpi_os_printf("\\v"); /* VERTICAL TAB */ |
break; |
case '\'': /* Single Quote */ |
case '\"': /* Double Quote */ |
case '\\': /* Backslash */ |
acpi_os_printf("\\%c", (int)string[i]); |
break; |
default: |
/* Check for printable character or hex escape */ |
if (isprint((int)string[i])) { |
/* This is a normal character */ |
acpi_os_printf("%c", (int)string[i]); |
} else { |
/* All others will be Hex escapes */ |
acpi_os_printf("\\x%2.2X", (s32) string[i]); |
} |
break; |
} |
} |
acpi_os_printf("\""); |
if (i == max_length && string[i]) { |
acpi_os_printf("..."); |
} |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_valid_acpi_char |
* |
* PARAMETERS: char - The character to be examined |
* position - Byte position (0-3) |
* |
* RETURN: TRUE if the character is valid, FALSE otherwise |
* |
* DESCRIPTION: Check for a valid ACPI character. Must be one of: |
* 1) Upper case alpha |
* 2) numeric |
* 3) underscore |
* |
* We allow a '!' as the last character because of the ASF! table |
* |
******************************************************************************/ |
u8 acpi_ut_valid_acpi_char(char character, u32 position) |
{ |
if (!((character >= 'A' && character <= 'Z') || |
(character >= '0' && character <= '9') || (character == '_'))) { |
/* Allow a '!' in the last position */ |
if (character == '!' && position == 3) { |
return (TRUE); |
} |
return (FALSE); |
} |
return (TRUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_valid_acpi_name |
* |
* PARAMETERS: name - The name to be examined. Does not have to |
* be NULL terminated string. |
* |
* RETURN: TRUE if the name is valid, FALSE otherwise |
* |
* DESCRIPTION: Check for a valid ACPI name. Each character must be one of: |
* 1) Upper case alpha |
* 2) numeric |
* 3) underscore |
* |
******************************************************************************/ |
u8 acpi_ut_valid_acpi_name(char *name) |
{ |
u32 i; |
ACPI_FUNCTION_ENTRY(); |
for (i = 0; i < ACPI_NAME_SIZE; i++) { |
if (!acpi_ut_valid_acpi_char(name[i], i)) { |
return (FALSE); |
} |
} |
return (TRUE); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_repair_name |
* |
* PARAMETERS: name - The ACPI name to be repaired |
* |
* RETURN: Repaired version of the name |
* |
* DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and |
* return the new name. NOTE: the Name parameter must reside in |
* read/write memory, cannot be a const. |
* |
* An ACPI Name must consist of valid ACPI characters. We will repair the name |
* if necessary because we don't want to abort because of this, but we want |
* all namespace names to be printable. A warning message is appropriate. |
* |
* This issue came up because there are in fact machines that exhibit |
* this problem, and we want to be able to enable ACPI support for them, |
* even though there are a few bad names. |
* |
******************************************************************************/ |
void acpi_ut_repair_name(char *name) |
{ |
u32 i; |
u8 found_bad_char = FALSE; |
u32 original_name; |
ACPI_FUNCTION_NAME(ut_repair_name); |
ACPI_MOVE_NAME(&original_name, name); |
/* Check each character in the name */ |
for (i = 0; i < ACPI_NAME_SIZE; i++) { |
if (acpi_ut_valid_acpi_char(name[i], i)) { |
continue; |
} |
/* |
* Replace a bad character with something printable, yet technically |
* still invalid. This prevents any collisions with existing "good" |
* names in the namespace. |
*/ |
name[i] = '*'; |
found_bad_char = TRUE; |
} |
if (found_bad_char) { |
/* Report warning only if in strict mode or debug mode */ |
if (!acpi_gbl_enable_interpreter_slack) { |
ACPI_WARNING((AE_INFO, |
"Invalid character(s) in name (0x%.8X), repaired: [%4.4s]", |
original_name, name)); |
} else { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
"Invalid character(s) in name (0x%.8X), repaired: [%4.4s]", |
original_name, name)); |
} |
} |
} |
#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP |
/******************************************************************************* |
* |
* FUNCTION: ut_convert_backslashes |
* |
* PARAMETERS: pathname - File pathname string to be converted |
* |
* RETURN: Modifies the input Pathname |
* |
* DESCRIPTION: Convert all backslashes (0x5C) to forward slashes (0x2F) within |
* the entire input file pathname string. |
* |
******************************************************************************/ |
void ut_convert_backslashes(char *pathname) |
{ |
if (!pathname) { |
return; |
} |
while (*pathname) { |
if (*pathname == '\\') { |
*pathname = '/'; |
} |
pathname++; |
} |
} |
#endif |
/drivers/acpi/acpica/uttrack.c |
---|
0,0 → 1,722 |
/****************************************************************************** |
* |
* Module Name: uttrack - Memory allocation tracking routines (debug only) |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
/* |
* These procedures are used for tracking memory leaks in the subsystem, and |
* they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. |
* |
* Each memory allocation is tracked via a doubly linked list. Each |
* element contains the caller's component, module name, function name, and |
* line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call |
* acpi_ut_track_allocation to add an element to the list; deletion |
* occurs in the body of acpi_ut_free. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#ifdef ACPI_DBG_TRACK_ALLOCATIONS |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("uttrack") |
/* Local prototypes */ |
static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct |
acpi_debug_mem_block |
*allocation); |
static acpi_status |
acpi_ut_track_allocation(struct acpi_debug_mem_block *address, |
acpi_size size, |
u8 alloc_type, |
u32 component, const char *module, u32 line); |
static acpi_status |
acpi_ut_remove_allocation(struct acpi_debug_mem_block *address, |
u32 component, const char *module, u32 line); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_create_list |
* |
* PARAMETERS: cache_name - Ascii name for the cache |
* object_size - Size of each cached object |
* return_cache - Where the new cache object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Create a local memory list for tracking purposed |
* |
******************************************************************************/ |
acpi_status |
acpi_ut_create_list(char *list_name, |
u16 object_size, struct acpi_memory_list **return_cache) |
{ |
struct acpi_memory_list *cache; |
cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); |
if (!cache) { |
return (AE_NO_MEMORY); |
} |
memset(cache, 0, sizeof(struct acpi_memory_list)); |
cache->list_name = list_name; |
cache->object_size = object_size; |
*return_cache = cache; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_allocate_and_track |
* |
* PARAMETERS: size - Size of the allocation |
* component - Component type of caller |
* module - Source file name of caller |
* line - Line number of caller |
* |
* RETURN: Address of the allocated memory on success, NULL on failure. |
* |
* DESCRIPTION: The subsystem's equivalent of malloc. |
* |
******************************************************************************/ |
void *acpi_ut_allocate_and_track(acpi_size size, |
u32 component, const char *module, u32 line) |
{ |
struct acpi_debug_mem_block *allocation; |
acpi_status status; |
/* Check for an inadvertent size of zero bytes */ |
if (!size) { |
ACPI_WARNING((module, line, |
"Attempt to allocate zero bytes, allocating 1 byte")); |
size = 1; |
} |
allocation = |
acpi_os_allocate(size + sizeof(struct acpi_debug_mem_header)); |
if (!allocation) { |
/* Report allocation error */ |
ACPI_WARNING((module, line, |
"Could not allocate size %u", (u32)size)); |
return (NULL); |
} |
status = acpi_ut_track_allocation(allocation, size, |
ACPI_MEM_MALLOC, component, module, |
line); |
if (ACPI_FAILURE(status)) { |
acpi_os_free(allocation); |
return (NULL); |
} |
acpi_gbl_global_list->total_allocated++; |
acpi_gbl_global_list->total_size += (u32)size; |
acpi_gbl_global_list->current_total_size += (u32)size; |
if (acpi_gbl_global_list->current_total_size > |
acpi_gbl_global_list->max_occupied) { |
acpi_gbl_global_list->max_occupied = |
acpi_gbl_global_list->current_total_size; |
} |
return ((void *)&allocation->user_space); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_allocate_zeroed_and_track |
* |
* PARAMETERS: size - Size of the allocation |
* component - Component type of caller |
* module - Source file name of caller |
* line - Line number of caller |
* |
* RETURN: Address of the allocated memory on success, NULL on failure. |
* |
* DESCRIPTION: Subsystem equivalent of calloc. |
* |
******************************************************************************/ |
void *acpi_ut_allocate_zeroed_and_track(acpi_size size, |
u32 component, |
const char *module, u32 line) |
{ |
struct acpi_debug_mem_block *allocation; |
acpi_status status; |
/* Check for an inadvertent size of zero bytes */ |
if (!size) { |
ACPI_WARNING((module, line, |
"Attempt to allocate zero bytes, allocating 1 byte")); |
size = 1; |
} |
allocation = |
acpi_os_allocate_zeroed(size + |
sizeof(struct acpi_debug_mem_header)); |
if (!allocation) { |
/* Report allocation error */ |
ACPI_ERROR((module, line, |
"Could not allocate size %u", (u32)size)); |
return (NULL); |
} |
status = acpi_ut_track_allocation(allocation, size, |
ACPI_MEM_CALLOC, component, module, |
line); |
if (ACPI_FAILURE(status)) { |
acpi_os_free(allocation); |
return (NULL); |
} |
acpi_gbl_global_list->total_allocated++; |
acpi_gbl_global_list->total_size += (u32)size; |
acpi_gbl_global_list->current_total_size += (u32)size; |
if (acpi_gbl_global_list->current_total_size > |
acpi_gbl_global_list->max_occupied) { |
acpi_gbl_global_list->max_occupied = |
acpi_gbl_global_list->current_total_size; |
} |
return ((void *)&allocation->user_space); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_free_and_track |
* |
* PARAMETERS: allocation - Address of the memory to deallocate |
* component - Component type of caller |
* module - Source file name of caller |
* line - Line number of caller |
* |
* RETURN: None |
* |
* DESCRIPTION: Frees the memory at Allocation |
* |
******************************************************************************/ |
void |
acpi_ut_free_and_track(void *allocation, |
u32 component, const char *module, u32 line) |
{ |
struct acpi_debug_mem_block *debug_block; |
acpi_status status; |
ACPI_FUNCTION_TRACE_PTR(ut_free, allocation); |
if (NULL == allocation) { |
ACPI_ERROR((module, line, "Attempt to delete a NULL address")); |
return_VOID; |
} |
debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block, |
(((char *)allocation) - |
sizeof(struct acpi_debug_mem_header))); |
acpi_gbl_global_list->total_freed++; |
acpi_gbl_global_list->current_total_size -= debug_block->size; |
status = acpi_ut_remove_allocation(debug_block, |
component, module, line); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, "Could not free memory")); |
} |
acpi_os_free(debug_block); |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n", |
allocation, debug_block)); |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_find_allocation |
* |
* PARAMETERS: allocation - Address of allocated memory |
* |
* RETURN: Three cases: |
* 1) List is empty, NULL is returned. |
* 2) Element was found. Returns Allocation parameter. |
* 3) Element was not found. Returns position where it should be |
* inserted into the list. |
* |
* DESCRIPTION: Searches for an element in the global allocation tracking list. |
* If the element is not found, returns the location within the |
* list where the element should be inserted. |
* |
* Note: The list is ordered by larger-to-smaller addresses. |
* |
* This global list is used to detect memory leaks in ACPICA as |
* well as other issues such as an attempt to release the same |
* internal object more than once. Although expensive as far |
* as cpu time, this list is much more helpful for finding these |
* types of issues than using memory leak detectors outside of |
* the ACPICA code. |
* |
******************************************************************************/ |
static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct |
acpi_debug_mem_block |
*allocation) |
{ |
struct acpi_debug_mem_block *element; |
element = acpi_gbl_global_list->list_head; |
if (!element) { |
return (NULL); |
} |
/* |
* Search for the address. |
* |
* Note: List is ordered by larger-to-smaller addresses, on the |
* assumption that a new allocation usually has a larger address |
* than previous allocations. |
*/ |
while (element > allocation) { |
/* Check for end-of-list */ |
if (!element->next) { |
return (element); |
} |
element = element->next; |
} |
if (element == allocation) { |
return (element); |
} |
return (element->previous); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_track_allocation |
* |
* PARAMETERS: allocation - Address of allocated memory |
* size - Size of the allocation |
* alloc_type - MEM_MALLOC or MEM_CALLOC |
* component - Component type of caller |
* module - Source file name of caller |
* line - Line number of caller |
* |
* RETURN: Status |
* |
* DESCRIPTION: Inserts an element into the global allocation tracking list. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, |
acpi_size size, |
u8 alloc_type, |
u32 component, const char *module, u32 line) |
{ |
struct acpi_memory_list *mem_list; |
struct acpi_debug_mem_block *element; |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation); |
if (acpi_gbl_disable_mem_tracking) { |
return_ACPI_STATUS(AE_OK); |
} |
mem_list = acpi_gbl_global_list; |
status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Search the global list for this address to make sure it is not |
* already present. This will catch several kinds of problems. |
*/ |
element = acpi_ut_find_allocation(allocation); |
if (element == allocation) { |
ACPI_ERROR((AE_INFO, |
"UtTrackAllocation: Allocation (%p) already present in global list!", |
allocation)); |
goto unlock_and_exit; |
} |
/* Fill in the instance data */ |
allocation->size = (u32)size; |
allocation->alloc_type = alloc_type; |
allocation->component = component; |
allocation->line = line; |
strncpy(allocation->module, module, ACPI_MAX_MODULE_NAME); |
allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; |
if (!element) { |
/* Insert at list head */ |
if (mem_list->list_head) { |
((struct acpi_debug_mem_block *)(mem_list->list_head))-> |
previous = allocation; |
} |
allocation->next = mem_list->list_head; |
allocation->previous = NULL; |
mem_list->list_head = allocation; |
} else { |
/* Insert after element */ |
allocation->next = element->next; |
allocation->previous = element; |
if (element->next) { |
(element->next)->previous = allocation; |
} |
element->next = allocation; |
} |
unlock_and_exit: |
status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); |
return_ACPI_STATUS(status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_remove_allocation |
* |
* PARAMETERS: allocation - Address of allocated memory |
* component - Component type of caller |
* module - Source file name of caller |
* line - Line number of caller |
* |
* RETURN: Status |
* |
* DESCRIPTION: Deletes an element from the global allocation tracking list. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, |
u32 component, const char *module, u32 line) |
{ |
struct acpi_memory_list *mem_list; |
acpi_status status; |
ACPI_FUNCTION_NAME(ut_remove_allocation); |
if (acpi_gbl_disable_mem_tracking) { |
return (AE_OK); |
} |
mem_list = acpi_gbl_global_list; |
if (NULL == mem_list->list_head) { |
/* No allocations! */ |
ACPI_ERROR((module, line, |
"Empty allocation list, nothing to free!")); |
return (AE_OK); |
} |
status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Unlink */ |
if (allocation->previous) { |
(allocation->previous)->next = allocation->next; |
} else { |
mem_list->list_head = allocation->next; |
} |
if (allocation->next) { |
(allocation->next)->previous = allocation->previous; |
} |
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n", |
&allocation->user_space, allocation->size)); |
/* Mark the segment as deleted */ |
memset(&allocation->user_space, 0xEA, allocation->size); |
status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_dump_allocation_info |
* |
* PARAMETERS: None |
* |
* RETURN: None |
* |
* DESCRIPTION: Print some info about the outstanding allocations. |
* |
******************************************************************************/ |
void acpi_ut_dump_allocation_info(void) |
{ |
/* |
struct acpi_memory_list *mem_list; |
*/ |
ACPI_FUNCTION_TRACE(ut_dump_allocation_info); |
/* |
ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, |
("%30s: %4d (%3d Kb)\n", "Current allocations", |
mem_list->current_count, |
ROUND_UP_TO_1K (mem_list->current_size))); |
ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, |
("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", |
mem_list->max_concurrent_count, |
ROUND_UP_TO_1K (mem_list->max_concurrent_size))); |
ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, |
("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", |
running_object_count, |
ROUND_UP_TO_1K (running_object_size))); |
ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, |
("%30s: %4d (%3d Kb)\n", "Total (all) allocations", |
running_alloc_count, |
ROUND_UP_TO_1K (running_alloc_size))); |
ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, |
("%30s: %4d (%3d Kb)\n", "Current Nodes", |
acpi_gbl_current_node_count, |
ROUND_UP_TO_1K (acpi_gbl_current_node_size))); |
ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, |
("%30s: %4d (%3d Kb)\n", "Max Nodes", |
acpi_gbl_max_concurrent_node_count, |
ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * |
sizeof (struct acpi_namespace_node))))); |
*/ |
return_VOID; |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_dump_allocations |
* |
* PARAMETERS: component - Component(s) to dump info for. |
* module - Module to dump info for. NULL means all. |
* |
* RETURN: None |
* |
* DESCRIPTION: Print a list of all outstanding allocations. |
* |
******************************************************************************/ |
void acpi_ut_dump_allocations(u32 component, const char *module) |
{ |
struct acpi_debug_mem_block *element; |
union acpi_descriptor *descriptor; |
u32 num_outstanding = 0; |
u8 descriptor_type; |
ACPI_FUNCTION_TRACE(ut_dump_allocations); |
if (acpi_gbl_disable_mem_tracking) { |
return_VOID; |
} |
/* |
* Walk the allocation list. |
*/ |
if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) { |
return_VOID; |
} |
element = acpi_gbl_global_list->list_head; |
while (element) { |
if ((element->component & component) && |
((module == NULL) |
|| (0 == strcmp(module, element->module)))) { |
descriptor = |
ACPI_CAST_PTR(union acpi_descriptor, |
&element->user_space); |
if (element->size < |
sizeof(struct acpi_common_descriptor)) { |
acpi_os_printf("%p Length 0x%04X %9.9s-%u " |
"[Not a Descriptor - too small]\n", |
descriptor, element->size, |
element->module, element->line); |
} else { |
/* Ignore allocated objects that are in a cache */ |
if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) != |
ACPI_DESC_TYPE_CACHED) { |
acpi_os_printf |
("%p Length 0x%04X %9.9s-%u [%s] ", |
descriptor, element->size, |
element->module, element->line, |
acpi_ut_get_descriptor_name |
(descriptor)); |
/* Validate the descriptor type using Type field and length */ |
descriptor_type = 0; /* Not a valid descriptor type */ |
switch (ACPI_GET_DESCRIPTOR_TYPE |
(descriptor)) { |
case ACPI_DESC_TYPE_OPERAND: |
if (element->size == |
sizeof(union |
acpi_operand_object)) |
{ |
descriptor_type = |
ACPI_DESC_TYPE_OPERAND; |
} |
break; |
case ACPI_DESC_TYPE_PARSER: |
if (element->size == |
sizeof(union |
acpi_parse_object)) { |
descriptor_type = |
ACPI_DESC_TYPE_PARSER; |
} |
break; |
case ACPI_DESC_TYPE_NAMED: |
if (element->size == |
sizeof(struct |
acpi_namespace_node)) |
{ |
descriptor_type = |
ACPI_DESC_TYPE_NAMED; |
} |
break; |
default: |
break; |
} |
/* Display additional info for the major descriptor types */ |
switch (descriptor_type) { |
case ACPI_DESC_TYPE_OPERAND: |
acpi_os_printf |
("%12.12s RefCount 0x%04X\n", |
acpi_ut_get_type_name |
(descriptor->object.common. |
type), |
descriptor->object.common. |
reference_count); |
break; |
case ACPI_DESC_TYPE_PARSER: |
acpi_os_printf |
("AmlOpcode 0x%04hX\n", |
descriptor->op.asl. |
aml_opcode); |
break; |
case ACPI_DESC_TYPE_NAMED: |
acpi_os_printf("%4.4s\n", |
acpi_ut_get_node_name |
(&descriptor-> |
node)); |
break; |
default: |
acpi_os_printf("\n"); |
break; |
} |
} |
} |
num_outstanding++; |
} |
element = element->next; |
} |
(void)acpi_ut_release_mutex(ACPI_MTX_MEMORY); |
/* Print summary */ |
if (!num_outstanding) { |
ACPI_INFO((AE_INFO, "No outstanding allocations")); |
} else { |
ACPI_ERROR((AE_INFO, "%u(0x%X) Outstanding allocations", |
num_outstanding, num_outstanding)); |
} |
return_VOID; |
} |
#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ |
/drivers/acpi/acpica/utuuid.c |
---|
0,0 → 1,98 |
/****************************************************************************** |
* |
* Module Name: utuuid -- UUID support functions |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_COMPILER |
ACPI_MODULE_NAME("utuuid") |
#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP) |
/* |
* UUID support functions. |
* |
* This table is used to convert an input UUID ascii string to a 16 byte |
* buffer and the reverse. The table maps a UUID buffer index 0-15 to |
* the index within the 36-byte UUID string where the associated 2-byte |
* hex value can be found. |
* |
* 36-byte UUID strings are of the form: |
* aabbccdd-eeff-gghh-iijj-kkllmmnnoopp |
* Where aa-pp are one byte hex numbers, made up of two hex digits |
* |
* Note: This table is basically the inverse of the string-to-offset table |
* found in the ACPI spec in the description of the to_UUID macro. |
*/ |
const u8 acpi_gbl_map_to_uuid_offset[UUID_BUFFER_LENGTH] = { |
6, 4, 2, 0, 11, 9, 16, 14, 19, 21, 24, 26, 28, 30, 32, 34 |
}; |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_convert_string_to_uuid |
* |
* PARAMETERS: in_string - 36-byte formatted UUID string |
* uuid_buffer - Where the 16-byte UUID buffer is returned |
* |
* RETURN: None. Output data is returned in the uuid_buffer |
* |
* DESCRIPTION: Convert a 36-byte formatted UUID string to 16-byte UUID buffer |
* |
******************************************************************************/ |
void acpi_ut_convert_string_to_uuid(char *in_string, u8 *uuid_buffer) |
{ |
u32 i; |
for (i = 0; i < UUID_BUFFER_LENGTH; i++) { |
uuid_buffer[i] = |
(acpi_ut_ascii_char_to_hex |
(in_string[acpi_gbl_map_to_uuid_offset[i]]) << 4); |
uuid_buffer[i] |= |
acpi_ut_ascii_char_to_hex(in_string |
[acpi_gbl_map_to_uuid_offset[i] + |
1]); |
} |
} |
#endif |
/drivers/acpi/acpica/utxface.c |
---|
0,0 → 1,560 |
/****************************************************************************** |
* |
* Module Name: utxface - External interfaces, miscellaneous utility functions |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acdebug.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utxface") |
/******************************************************************************* |
* |
* FUNCTION: acpi_terminate |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Shutdown the ACPICA subsystem and release all resources. |
* |
******************************************************************************/ |
acpi_status __init acpi_terminate(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_terminate); |
/* Shutdown and free all resources */ |
acpi_ut_subsystem_shutdown(); |
/* Free the mutex objects */ |
acpi_ut_mutex_terminate(); |
/* Now we can shutdown the OS-dependent layer */ |
status = acpi_os_terminate(); |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_terminate) |
#ifndef ACPI_ASL_COMPILER |
#ifdef ACPI_FUTURE_USAGE |
/******************************************************************************* |
* |
* FUNCTION: acpi_subsystem_status |
* |
* PARAMETERS: None |
* |
* RETURN: Status of the ACPI subsystem |
* |
* DESCRIPTION: Other drivers that use the ACPI subsystem should call this |
* before making any other calls, to ensure the subsystem |
* initialized successfully. |
* |
******************************************************************************/ |
acpi_status acpi_subsystem_status(void) |
{ |
if (acpi_gbl_startup_flags & ACPI_INITIALIZED_OK) { |
return (AE_OK); |
} else { |
return (AE_ERROR); |
} |
} |
ACPI_EXPORT_SYMBOL(acpi_subsystem_status) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_system_info |
* |
* PARAMETERS: out_buffer - A buffer to receive the resources for the |
* device |
* |
* RETURN: status - the status of the call |
* |
* DESCRIPTION: This function is called to get information about the current |
* state of the ACPI subsystem. It will return system information |
* in the out_buffer. |
* |
* If the function fails an appropriate status will be returned |
* and the value of out_buffer is undefined. |
* |
******************************************************************************/ |
acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) |
{ |
struct acpi_system_info *info_ptr; |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_get_system_info); |
/* Parameter validation */ |
status = acpi_ut_validate_buffer(out_buffer); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* Validate/Allocate/Clear caller buffer */ |
status = |
acpi_ut_initialize_buffer(out_buffer, |
sizeof(struct acpi_system_info)); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
/* |
* Populate the return buffer |
*/ |
info_ptr = (struct acpi_system_info *)out_buffer->pointer; |
info_ptr->acpi_ca_version = ACPI_CA_VERSION; |
/* System flags (ACPI capabilities) */ |
info_ptr->flags = ACPI_SYS_MODE_ACPI; |
/* Timer resolution - 24 or 32 bits */ |
if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) { |
info_ptr->timer_resolution = 24; |
} else { |
info_ptr->timer_resolution = 32; |
} |
/* Clear the reserved fields */ |
info_ptr->reserved1 = 0; |
info_ptr->reserved2 = 0; |
/* Current debug levels */ |
info_ptr->debug_layer = acpi_dbg_layer; |
info_ptr->debug_level = acpi_dbg_level; |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_system_info) |
/******************************************************************************* |
* |
* FUNCTION: acpi_get_statistics |
* |
* PARAMETERS: stats - Where the statistics are returned |
* |
* RETURN: status - the status of the call |
* |
* DESCRIPTION: Get the contents of the various system counters |
* |
******************************************************************************/ |
acpi_status acpi_get_statistics(struct acpi_statistics *stats) |
{ |
ACPI_FUNCTION_TRACE(acpi_get_statistics); |
/* Parameter validation */ |
if (!stats) { |
return_ACPI_STATUS(AE_BAD_PARAMETER); |
} |
/* Various interrupt-based event counters */ |
stats->sci_count = acpi_sci_count; |
stats->gpe_count = acpi_gpe_count; |
memcpy(stats->fixed_event_count, acpi_fixed_event_count, |
sizeof(acpi_fixed_event_count)); |
/* Other counters */ |
stats->method_count = acpi_method_count; |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_get_statistics) |
/***************************************************************************** |
* |
* FUNCTION: acpi_install_initialization_handler |
* |
* PARAMETERS: handler - Callback procedure |
* function - Not (currently) used, see below |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install an initialization handler |
* |
* TBD: When a second function is added, must save the Function also. |
* |
****************************************************************************/ |
acpi_status |
acpi_install_initialization_handler(acpi_init_handler handler, u32 function) |
{ |
if (!handler) { |
return (AE_BAD_PARAMETER); |
} |
if (acpi_gbl_init_handler) { |
return (AE_ALREADY_EXISTS); |
} |
acpi_gbl_init_handler = handler; |
return (AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler) |
#endif |
/***************************************************************************** |
* |
* FUNCTION: acpi_purge_cached_objects |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Empty all caches (delete the cached objects) |
* |
****************************************************************************/ |
acpi_status acpi_purge_cached_objects(void) |
{ |
ACPI_FUNCTION_TRACE(acpi_purge_cached_objects); |
(void)acpi_os_purge_cache(acpi_gbl_state_cache); |
(void)acpi_os_purge_cache(acpi_gbl_operand_cache); |
(void)acpi_os_purge_cache(acpi_gbl_ps_node_cache); |
(void)acpi_os_purge_cache(acpi_gbl_ps_node_ext_cache); |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects) |
/***************************************************************************** |
* |
* FUNCTION: acpi_install_interface |
* |
* PARAMETERS: interface_name - The interface to install |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install an _OSI interface to the global list |
* |
****************************************************************************/ |
acpi_status acpi_install_interface(acpi_string interface_name) |
{ |
acpi_status status; |
struct acpi_interface_info *interface_info; |
/* Parameter validation */ |
if (!interface_name || (strlen(interface_name) == 0)) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Check if the interface name is already in the global list */ |
interface_info = acpi_ut_get_interface(interface_name); |
if (interface_info) { |
/* |
* The interface already exists in the list. This is OK if the |
* interface has been marked invalid -- just clear the bit. |
*/ |
if (interface_info->flags & ACPI_OSI_INVALID) { |
interface_info->flags &= ~ACPI_OSI_INVALID; |
status = AE_OK; |
} else { |
status = AE_ALREADY_EXISTS; |
} |
} else { |
/* New interface name, install into the global list */ |
status = acpi_ut_install_interface(interface_name); |
} |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_interface) |
/***************************************************************************** |
* |
* FUNCTION: acpi_remove_interface |
* |
* PARAMETERS: interface_name - The interface to remove |
* |
* RETURN: Status |
* |
* DESCRIPTION: Remove an _OSI interface from the global list |
* |
****************************************************************************/ |
acpi_status acpi_remove_interface(acpi_string interface_name) |
{ |
acpi_status status; |
/* Parameter validation */ |
if (!interface_name || (strlen(interface_name) == 0)) { |
return (AE_BAD_PARAMETER); |
} |
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = acpi_ut_remove_interface(interface_name); |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_remove_interface) |
/***************************************************************************** |
* |
* FUNCTION: acpi_install_interface_handler |
* |
* PARAMETERS: handler - The _OSI interface handler to install |
* NULL means "remove existing handler" |
* |
* RETURN: Status |
* |
* DESCRIPTION: Install a handler for the predefined _OSI ACPI method. |
* invoked during execution of the internal implementation of |
* _OSI. A NULL handler simply removes any existing handler. |
* |
****************************************************************************/ |
acpi_status acpi_install_interface_handler(acpi_interface_handler handler) |
{ |
acpi_status status; |
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
if (handler && acpi_gbl_interface_handler) { |
status = AE_ALREADY_EXISTS; |
} else { |
acpi_gbl_interface_handler = handler; |
} |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
return (status); |
} |
ACPI_EXPORT_SYMBOL(acpi_install_interface_handler) |
/***************************************************************************** |
* |
* FUNCTION: acpi_update_interfaces |
* |
* PARAMETERS: action - Actions to be performed during the |
* update |
* |
* RETURN: Status |
* |
* DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor |
* string or/and feature group strings. |
* |
****************************************************************************/ |
acpi_status acpi_update_interfaces(u8 action) |
{ |
acpi_status status; |
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
status = acpi_ut_update_interfaces(action); |
acpi_os_release_mutex(acpi_gbl_osi_mutex); |
return (status); |
} |
/***************************************************************************** |
* |
* FUNCTION: acpi_check_address_range |
* |
* PARAMETERS: space_id - Address space ID |
* address - Start address |
* length - Length |
* warn - TRUE if warning on overlap desired |
* |
* RETURN: Count of the number of conflicts detected. |
* |
* DESCRIPTION: Check if the input address range overlaps any of the |
* ASL operation region address ranges. |
* |
****************************************************************************/ |
u32 |
acpi_check_address_range(acpi_adr_space_type space_id, |
acpi_physical_address address, |
acpi_size length, u8 warn) |
{ |
u32 overlaps; |
acpi_status status; |
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
if (ACPI_FAILURE(status)) { |
return (0); |
} |
overlaps = acpi_ut_check_address_range(space_id, address, |
(u32)length, warn); |
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
return (overlaps); |
} |
ACPI_EXPORT_SYMBOL(acpi_check_address_range) |
#endif /* !ACPI_ASL_COMPILER */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_decode_pld_buffer |
* |
* PARAMETERS: in_buffer - Buffer returned by _PLD method |
* length - Length of the in_buffer |
* return_buffer - Where the decode buffer is returned |
* |
* RETURN: Status and the decoded _PLD buffer. User must deallocate |
* the buffer via ACPI_FREE. |
* |
* DESCRIPTION: Decode the bit-packed buffer returned by the _PLD method into |
* a local struct that is much more useful to an ACPI driver. |
* |
******************************************************************************/ |
acpi_status |
acpi_decode_pld_buffer(u8 *in_buffer, |
acpi_size length, struct acpi_pld_info ** return_buffer) |
{ |
struct acpi_pld_info *pld_info; |
u32 *buffer = ACPI_CAST_PTR(u32, in_buffer); |
u32 dword; |
/* Parameter validation */ |
if (!in_buffer || !return_buffer |
|| (length < ACPI_PLD_REV1_BUFFER_SIZE)) { |
return (AE_BAD_PARAMETER); |
} |
pld_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pld_info)); |
if (!pld_info) { |
return (AE_NO_MEMORY); |
} |
/* First 32-bit DWord */ |
ACPI_MOVE_32_TO_32(&dword, &buffer[0]); |
pld_info->revision = ACPI_PLD_GET_REVISION(&dword); |
pld_info->ignore_color = ACPI_PLD_GET_IGNORE_COLOR(&dword); |
pld_info->red = ACPI_PLD_GET_RED(&dword); |
pld_info->green = ACPI_PLD_GET_GREEN(&dword); |
pld_info->blue = ACPI_PLD_GET_BLUE(&dword); |
/* Second 32-bit DWord */ |
ACPI_MOVE_32_TO_32(&dword, &buffer[1]); |
pld_info->width = ACPI_PLD_GET_WIDTH(&dword); |
pld_info->height = ACPI_PLD_GET_HEIGHT(&dword); |
/* Third 32-bit DWord */ |
ACPI_MOVE_32_TO_32(&dword, &buffer[2]); |
pld_info->user_visible = ACPI_PLD_GET_USER_VISIBLE(&dword); |
pld_info->dock = ACPI_PLD_GET_DOCK(&dword); |
pld_info->lid = ACPI_PLD_GET_LID(&dword); |
pld_info->panel = ACPI_PLD_GET_PANEL(&dword); |
pld_info->vertical_position = ACPI_PLD_GET_VERTICAL(&dword); |
pld_info->horizontal_position = ACPI_PLD_GET_HORIZONTAL(&dword); |
pld_info->shape = ACPI_PLD_GET_SHAPE(&dword); |
pld_info->group_orientation = ACPI_PLD_GET_ORIENTATION(&dword); |
pld_info->group_token = ACPI_PLD_GET_TOKEN(&dword); |
pld_info->group_position = ACPI_PLD_GET_POSITION(&dword); |
pld_info->bay = ACPI_PLD_GET_BAY(&dword); |
/* Fourth 32-bit DWord */ |
ACPI_MOVE_32_TO_32(&dword, &buffer[3]); |
pld_info->ejectable = ACPI_PLD_GET_EJECTABLE(&dword); |
pld_info->ospm_eject_required = ACPI_PLD_GET_OSPM_EJECT(&dword); |
pld_info->cabinet_number = ACPI_PLD_GET_CABINET(&dword); |
pld_info->card_cage_number = ACPI_PLD_GET_CARD_CAGE(&dword); |
pld_info->reference = ACPI_PLD_GET_REFERENCE(&dword); |
pld_info->rotation = ACPI_PLD_GET_ROTATION(&dword); |
pld_info->order = ACPI_PLD_GET_ORDER(&dword); |
if (length >= ACPI_PLD_REV2_BUFFER_SIZE) { |
/* Fifth 32-bit DWord (Revision 2 of _PLD) */ |
ACPI_MOVE_32_TO_32(&dword, &buffer[4]); |
pld_info->vertical_offset = ACPI_PLD_GET_VERT_OFFSET(&dword); |
pld_info->horizontal_offset = ACPI_PLD_GET_HORIZ_OFFSET(&dword); |
} |
*return_buffer = pld_info; |
return (AE_OK); |
} |
ACPI_EXPORT_SYMBOL(acpi_decode_pld_buffer) |
/drivers/acpi/acpica/utxferror.c |
---|
0,0 → 1,260 |
/******************************************************************************* |
* |
* Module Name: utxferror - Various error/warning output functions |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utxferror") |
/* |
* This module is used for the in-kernel ACPICA as well as the ACPICA |
* tools/applications. |
*/ |
#ifndef ACPI_NO_ERROR_MESSAGES /* Entire module */ |
/******************************************************************************* |
* |
* FUNCTION: acpi_error |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Print "ACPI Error" message with module/line/version info |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_error(const char *module_name, u32 line_number, const char *format, ...) |
{ |
va_list arg_list; |
ACPI_MSG_REDIRECT_BEGIN; |
acpi_os_printf(ACPI_MSG_ERROR); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
ACPI_MSG_REDIRECT_END; |
} |
ACPI_EXPORT_SYMBOL(acpi_error) |
/******************************************************************************* |
* |
* FUNCTION: acpi_exception |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* status - Status to be formatted |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Print "ACPI Exception" message with module/line/version info |
* and decoded acpi_status. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_exception(const char *module_name, |
u32 line_number, acpi_status status, const char *format, ...) |
{ |
va_list arg_list; |
ACPI_MSG_REDIRECT_BEGIN; |
/* For AE_OK, just print the message */ |
if (ACPI_SUCCESS(status)) { |
acpi_os_printf(ACPI_MSG_EXCEPTION); |
} else { |
acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ", |
acpi_format_exception(status)); |
} |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
ACPI_MSG_REDIRECT_END; |
} |
ACPI_EXPORT_SYMBOL(acpi_exception) |
/******************************************************************************* |
* |
* FUNCTION: acpi_warning |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Print "ACPI Warning" message with module/line/version info |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_warning(const char *module_name, u32 line_number, const char *format, ...) |
{ |
va_list arg_list; |
ACPI_MSG_REDIRECT_BEGIN; |
acpi_os_printf(ACPI_MSG_WARNING); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
ACPI_MSG_REDIRECT_END; |
} |
ACPI_EXPORT_SYMBOL(acpi_warning) |
/******************************************************************************* |
* |
* FUNCTION: acpi_info |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Print generic "ACPI:" information message. There is no |
* module/line/version info in order to keep the message simple. |
* |
* TBD: module_name and line_number args are not needed, should be removed. |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_info(const char *module_name, u32 line_number, const char *format, ...) |
{ |
va_list arg_list; |
ACPI_MSG_REDIRECT_BEGIN; |
acpi_os_printf(ACPI_MSG_INFO); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
acpi_os_printf("\n"); |
va_end(arg_list); |
ACPI_MSG_REDIRECT_END; |
} |
ACPI_EXPORT_SYMBOL(acpi_info) |
/******************************************************************************* |
* |
* FUNCTION: acpi_bios_error |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Print "ACPI Firmware Error" message with module/line/version |
* info |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_bios_error(const char *module_name, |
u32 line_number, const char *format, ...) |
{ |
va_list arg_list; |
ACPI_MSG_REDIRECT_BEGIN; |
acpi_os_printf(ACPI_MSG_BIOS_ERROR); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
ACPI_MSG_REDIRECT_END; |
} |
ACPI_EXPORT_SYMBOL(acpi_bios_error) |
/******************************************************************************* |
* |
* FUNCTION: acpi_bios_warning |
* |
* PARAMETERS: module_name - Caller's module name (for error output) |
* line_number - Caller's line number (for error output) |
* format - Printf format string + additional args |
* |
* RETURN: None |
* |
* DESCRIPTION: Print "ACPI Firmware Warning" message with module/line/version |
* info |
* |
******************************************************************************/ |
void ACPI_INTERNAL_VAR_XFACE |
acpi_bios_warning(const char *module_name, |
u32 line_number, const char *format, ...) |
{ |
va_list arg_list; |
ACPI_MSG_REDIRECT_BEGIN; |
acpi_os_printf(ACPI_MSG_BIOS_WARNING); |
va_start(arg_list, format); |
acpi_os_vprintf(format, arg_list); |
ACPI_MSG_SUFFIX; |
va_end(arg_list); |
ACPI_MSG_REDIRECT_END; |
} |
ACPI_EXPORT_SYMBOL(acpi_bios_warning) |
#endif /* ACPI_NO_ERROR_MESSAGES */ |
/drivers/acpi/acpica/utxfinit.c |
---|
0,0 → 1,331 |
/****************************************************************************** |
* |
* Module Name: utxfinit - External interfaces for ACPICA initialization |
* |
*****************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#define EXPORT_ACPI_INTERFACES |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acevents.h" |
#include "acnamesp.h" |
#include "acdebug.h" |
#include "actables.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utxfinit") |
/* For acpi_exec only */ |
void ae_do_object_overrides(void); |
/******************************************************************************* |
* |
* FUNCTION: acpi_initialize_subsystem |
* |
* PARAMETERS: None |
* |
* RETURN: Status |
* |
* DESCRIPTION: Initializes all global variables. This is the first function |
* called, so any early initialization belongs here. |
* |
******************************************************************************/ |
acpi_status __init acpi_initialize_subsystem(void) |
{ |
acpi_status status; |
ACPI_FUNCTION_TRACE(acpi_initialize_subsystem); |
acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE; |
ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace()); |
/* Initialize the OS-Dependent layer */ |
status = acpi_os_initialize(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, "During OSL initialization")); |
return_ACPI_STATUS(status); |
} |
/* Initialize all globals used by the subsystem */ |
status = acpi_ut_init_globals(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"During initialization of globals")); |
return_ACPI_STATUS(status); |
} |
/* Create the default mutex objects */ |
status = acpi_ut_mutex_initialize(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"During Global Mutex creation")); |
return_ACPI_STATUS(status); |
} |
/* |
* Initialize the namespace manager and |
* the root of the namespace tree |
*/ |
status = acpi_ns_root_initialize(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"During Namespace initialization")); |
return_ACPI_STATUS(status); |
} |
/* Initialize the global OSI interfaces list with the static names */ |
status = acpi_ut_initialize_interfaces(); |
if (ACPI_FAILURE(status)) { |
ACPI_EXCEPTION((AE_INFO, status, |
"During OSI interfaces initialization")); |
return_ACPI_STATUS(status); |
} |
return_ACPI_STATUS(AE_OK); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_subsystem) |
/******************************************************************************* |
* |
* FUNCTION: acpi_enable_subsystem |
* |
* PARAMETERS: flags - Init/enable Options |
* |
* RETURN: Status |
* |
* DESCRIPTION: Completes the subsystem initialization including hardware. |
* Puts system into ACPI mode if it isn't already. |
* |
******************************************************************************/ |
acpi_status __init acpi_enable_subsystem(u32 flags) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(acpi_enable_subsystem); |
#if (!ACPI_REDUCED_HARDWARE) |
/* Enable ACPI mode */ |
if (!(flags & ACPI_NO_ACPI_ENABLE)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Init] Going into ACPI mode\n")); |
acpi_gbl_original_mode = acpi_hw_get_mode(); |
status = acpi_enable(); |
if (ACPI_FAILURE(status)) { |
ACPI_WARNING((AE_INFO, "AcpiEnable failed")); |
return_ACPI_STATUS(status); |
} |
} |
/* |
* Obtain a permanent mapping for the FACS. This is required for the |
* Global Lock and the Firmware Waking Vector |
*/ |
if (!(flags & ACPI_NO_FACS_INIT)) { |
status = acpi_tb_initialize_facs(); |
if (ACPI_FAILURE(status)) { |
ACPI_WARNING((AE_INFO, "Could not map the FACS table")); |
return_ACPI_STATUS(status); |
} |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
/* |
* Install the default op_region handlers. These are installed unless |
* other handlers have already been installed via the |
* install_address_space_handler interface. |
*/ |
if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Init] Installing default address space handlers\n")); |
status = acpi_ev_install_region_handlers(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
#if (!ACPI_REDUCED_HARDWARE) |
/* |
* Initialize ACPI Event handling (Fixed and General Purpose) |
* |
* Note1: We must have the hardware and events initialized before we can |
* execute any control methods safely. Any control method can require |
* ACPI hardware support, so the hardware must be fully initialized before |
* any method execution! |
* |
* Note2: Fixed events are initialized and enabled here. GPEs are |
* initialized, but cannot be enabled until after the hardware is |
* completely initialized (SCI and global_lock activated) and the various |
* initialization control methods are run (_REG, _STA, _INI) on the |
* entire namespace. |
*/ |
if (!(flags & ACPI_NO_EVENT_INIT)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Init] Initializing ACPI events\n")); |
status = acpi_ev_initialize_events(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* |
* Install the SCI handler and Global Lock handler. This completes the |
* hardware initialization. |
*/ |
if (!(flags & ACPI_NO_HANDLER_INIT)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Init] Installing SCI/GL handlers\n")); |
status = acpi_ev_install_xrupt_handlers(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
#endif /* !ACPI_REDUCED_HARDWARE */ |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_enable_subsystem) |
/******************************************************************************* |
* |
* FUNCTION: acpi_initialize_objects |
* |
* PARAMETERS: flags - Init/enable Options |
* |
* RETURN: Status |
* |
* DESCRIPTION: Completes namespace initialization by initializing device |
* objects and executing AML code for Regions, buffers, etc. |
* |
******************************************************************************/ |
acpi_status __init acpi_initialize_objects(u32 flags) |
{ |
acpi_status status = AE_OK; |
ACPI_FUNCTION_TRACE(acpi_initialize_objects); |
/* |
* Run all _REG methods |
* |
* Note: Any objects accessed by the _REG methods will be automatically |
* initialized, even if they contain executable AML (see the call to |
* acpi_ns_initialize_objects below). |
*/ |
if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Init] Executing _REG OpRegion methods\n")); |
status = acpi_ev_initialize_op_regions(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
#ifdef ACPI_EXEC_APP |
/* |
* This call implements the "initialization file" option for acpi_exec. |
* This is the precise point that we want to perform the overrides. |
*/ |
ae_do_object_overrides(); |
#endif |
/* |
* Execute any module-level code that was detected during the table load |
* phase. Although illegal since ACPI 2.0, there are many machines that |
* contain this type of code. Each block of detected executable AML code |
* outside of any control method is wrapped with a temporary control |
* method object and placed on a global list. The methods on this list |
* are executed below. |
*/ |
acpi_ns_exec_module_code_list(); |
/* |
* Initialize the objects that remain uninitialized. This runs the |
* executable AML that may be part of the declaration of these objects: |
* operation_regions, buffer_fields, Buffers, and Packages. |
*/ |
if (!(flags & ACPI_NO_OBJECT_INIT)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Init] Completing Initialization of ACPI Objects\n")); |
status = acpi_ns_initialize_objects(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* |
* Initialize all device objects in the namespace. This runs the device |
* _STA and _INI methods. |
*/ |
if (!(flags & ACPI_NO_DEVICE_INIT)) { |
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
"[Init] Initializing ACPI Devices\n")); |
status = acpi_ns_initialize_devices(); |
if (ACPI_FAILURE(status)) { |
return_ACPI_STATUS(status); |
} |
} |
/* |
* Empty the caches (delete the cached objects) on the assumption that |
* the table load filled them up more than they will be at runtime -- |
* thus wasting non-paged memory. |
*/ |
status = acpi_purge_cached_objects(); |
acpi_gbl_startup_flags |= ACPI_INITIALIZED_OK; |
return_ACPI_STATUS(status); |
} |
ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_objects) |
/drivers/acpi/acpica/utxfmutex.c |
---|
0,0 → 1,187 |
/******************************************************************************* |
* |
* Module Name: utxfmutex - external AML mutex access functions |
* |
******************************************************************************/ |
/* |
* Copyright (C) 2000 - 2015, Intel Corp. |
* 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, |
* without modification. |
* 2. Redistributions in binary form must reproduce at minimum a disclaimer |
* substantially similar to the "NO WARRANTY" disclaimer below |
* ("Disclaimer") and any redistribution must be conditioned upon |
* including a substantially similar Disclaimer requirement for further |
* binary redistribution. |
* 3. Neither the names of the above-listed copyright holders nor the names |
* of any contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* |
* Alternatively, this software may be distributed under the terms of the |
* GNU General Public License ("GPL") version 2 as published by the Free |
* Software Foundation. |
* |
* NO WARRANTY |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. |
*/ |
#include <acpi/acpi.h> |
#include "accommon.h" |
#include "acnamesp.h" |
#define _COMPONENT ACPI_UTILITIES |
ACPI_MODULE_NAME("utxfmutex") |
/* Local prototypes */ |
static acpi_status |
acpi_ut_get_mutex_object(acpi_handle handle, |
acpi_string pathname, |
union acpi_operand_object **ret_obj); |
/******************************************************************************* |
* |
* FUNCTION: acpi_ut_get_mutex_object |
* |
* PARAMETERS: handle - Mutex or prefix handle (optional) |
* pathname - Mutex pathname (optional) |
* ret_obj - Where the mutex object is returned |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get an AML mutex object. The mutex node is pointed to by |
* Handle:Pathname. Either Handle or Pathname can be NULL, but |
* not both. |
* |
******************************************************************************/ |
static acpi_status |
acpi_ut_get_mutex_object(acpi_handle handle, |
acpi_string pathname, |
union acpi_operand_object **ret_obj) |
{ |
struct acpi_namespace_node *mutex_node; |
union acpi_operand_object *mutex_obj; |
acpi_status status; |
/* Parameter validation */ |
if (!ret_obj || (!handle && !pathname)) { |
return (AE_BAD_PARAMETER); |
} |
/* Get a the namespace node for the mutex */ |
mutex_node = handle; |
if (pathname != NULL) { |
status = acpi_get_handle(handle, pathname, |
ACPI_CAST_PTR(acpi_handle, |
&mutex_node)); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
} |
/* Ensure that we actually have a Mutex object */ |
if (!mutex_node || (mutex_node->type != ACPI_TYPE_MUTEX)) { |
return (AE_TYPE); |
} |
/* Get the low-level mutex object */ |
mutex_obj = acpi_ns_get_attached_object(mutex_node); |
if (!mutex_obj) { |
return (AE_NULL_OBJECT); |
} |
*ret_obj = mutex_obj; |
return (AE_OK); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_acquire_mutex |
* |
* PARAMETERS: handle - Mutex or prefix handle (optional) |
* pathname - Mutex pathname (optional) |
* timeout - Max time to wait for the lock (millisec) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Acquire an AML mutex. This is a device driver interface to |
* AML mutex objects, and allows for transaction locking between |
* drivers and AML code. The mutex node is pointed to by |
* Handle:Pathname. Either Handle or Pathname can be NULL, but |
* not both. |
* |
******************************************************************************/ |
acpi_status |
acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout) |
{ |
acpi_status status; |
union acpi_operand_object *mutex_obj; |
/* Get the low-level mutex associated with Handle:Pathname */ |
status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Acquire the OS mutex */ |
status = acpi_os_acquire_mutex(mutex_obj->mutex.os_mutex, timeout); |
return (status); |
} |
/******************************************************************************* |
* |
* FUNCTION: acpi_release_mutex |
* |
* PARAMETERS: handle - Mutex or prefix handle (optional) |
* pathname - Mutex pathname (optional) |
* |
* RETURN: Status |
* |
* DESCRIPTION: Release an AML mutex. This is a device driver interface to |
* AML mutex objects, and allows for transaction locking between |
* drivers and AML code. The mutex node is pointed to by |
* Handle:Pathname. Either Handle or Pathname can be NULL, but |
* not both. |
* |
******************************************************************************/ |
acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) |
{ |
acpi_status status; |
union acpi_operand_object *mutex_obj; |
/* Get the low-level mutex associated with Handle:Pathname */ |
status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj); |
if (ACPI_FAILURE(status)) { |
return (status); |
} |
/* Release the OS mutex */ |
acpi_os_release_mutex(mutex_obj->mutex.os_mutex); |
return (AE_OK); |
} |
/drivers/acpi/blacklist.c |
---|
0,0 → 1,353 |
/* |
* blacklist.c |
* |
* Check to see if the given machine has a known bad ACPI BIOS |
* or if the BIOS is too old. |
* Check given machine against acpi_osi_dmi_table[]. |
* |
* Copyright (C) 2004 Len Brown <len.brown@intel.com> |
* Copyright (C) 2002 Andy Grover <andrew.grover@intel.com> |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or (at |
* your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, but |
* WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* General Public License for more details. |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
*/ |
#include <linux/kernel.h> |
#include <linux/init.h> |
#include <linux/acpi.h> |
#include <linux/dmi.h> |
#include "internal.h" |
enum acpi_blacklist_predicates { |
all_versions, |
less_than_or_equal, |
equal, |
greater_than_or_equal, |
}; |
struct acpi_blacklist_item { |
char oem_id[7]; |
char oem_table_id[9]; |
u32 oem_revision; |
char *table; |
enum acpi_blacklist_predicates oem_revision_predicate; |
char *reason; |
u32 is_critical_error; |
}; |
static struct dmi_system_id acpi_osi_dmi_table[] __initdata; |
/* |
* POLICY: If *anything* doesn't work, put it on the blacklist. |
* If they are critical errors, mark it critical, and abort driver load. |
*/ |
static struct acpi_blacklist_item acpi_blacklist[] __initdata = { |
/* Compaq Presario 1700 */ |
{"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal, |
"Multiple problems", 1}, |
/* Sony FX120, FX140, FX150? */ |
{"SONY ", "U0 ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal, |
"ACPI driver problem", 1}, |
/* Compaq Presario 800, Insyde BIOS */ |
{"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal, |
"Does not use _REG to protect EC OpRegions", 1}, |
/* IBM 600E - _ADR should return 7, but it returns 1 */ |
{"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, |
"Incorrect _ADR", 1}, |
{""} |
}; |
int __init acpi_blacklisted(void) |
{ |
int i = 0; |
int blacklisted = 0; |
struct acpi_table_header table_header; |
while (acpi_blacklist[i].oem_id[0] != '\0') { |
if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) { |
i++; |
continue; |
} |
if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) { |
i++; |
continue; |
} |
if (strncmp |
(acpi_blacklist[i].oem_table_id, table_header.oem_table_id, |
8)) { |
i++; |
continue; |
} |
if ((acpi_blacklist[i].oem_revision_predicate == all_versions) |
|| (acpi_blacklist[i].oem_revision_predicate == |
less_than_or_equal |
&& table_header.oem_revision <= |
acpi_blacklist[i].oem_revision) |
|| (acpi_blacklist[i].oem_revision_predicate == |
greater_than_or_equal |
&& table_header.oem_revision >= |
acpi_blacklist[i].oem_revision) |
|| (acpi_blacklist[i].oem_revision_predicate == equal |
&& table_header.oem_revision == |
acpi_blacklist[i].oem_revision)) { |
printk(KERN_ERR PREFIX |
"Vendor \"%6.6s\" System \"%8.8s\" " |
"Revision 0x%x has a known ACPI BIOS problem.\n", |
acpi_blacklist[i].oem_id, |
acpi_blacklist[i].oem_table_id, |
acpi_blacklist[i].oem_revision); |
printk(KERN_ERR PREFIX |
"Reason: %s. This is a %s error\n", |
acpi_blacklist[i].reason, |
(acpi_blacklist[i]. |
is_critical_error ? "non-recoverable" : |
"recoverable")); |
blacklisted = acpi_blacklist[i].is_critical_error; |
break; |
} else { |
i++; |
} |
} |
dmi_check_system(acpi_osi_dmi_table); |
return blacklisted; |
} |
#ifdef CONFIG_DMI |
static int __init dmi_enable_osi_linux(const struct dmi_system_id *d) |
{ |
acpi_dmi_osi_linux(1, d); /* enable */ |
return 0; |
} |
static int __init dmi_disable_osi_vista(const struct dmi_system_id *d) |
{ |
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); |
acpi_osi_setup("!Windows 2006"); |
acpi_osi_setup("!Windows 2006 SP1"); |
acpi_osi_setup("!Windows 2006 SP2"); |
return 0; |
} |
static int __init dmi_disable_osi_win7(const struct dmi_system_id *d) |
{ |
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); |
acpi_osi_setup("!Windows 2009"); |
return 0; |
} |
static int __init dmi_disable_osi_win8(const struct dmi_system_id *d) |
{ |
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); |
acpi_osi_setup("!Windows 2012"); |
return 0; |
} |
#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE |
static int __init dmi_enable_rev_override(const struct dmi_system_id *d) |
{ |
printk(KERN_NOTICE PREFIX "DMI detected: %s (force ACPI _REV to 5)\n", |
d->ident); |
acpi_rev_override_setup(NULL); |
return 0; |
} |
#endif |
static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "Fujitsu Siemens", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), |
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), |
}, |
}, |
{ |
/* |
* There have a NVIF method in MSI GX723 DSDT need call by Nvidia |
* driver (e.g. nouveau) when user press brightness hotkey. |
* Currently, nouveau driver didn't do the job and it causes there |
* have a infinite while loop in DSDT when user press hotkey. |
* We add MSI GX723's dmi information to this table for workaround |
* this issue. |
* Will remove MSI GX723 from the table after nouveau grows support. |
*/ |
.callback = dmi_disable_osi_vista, |
.ident = "MSI GX723", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), |
DMI_MATCH(DMI_PRODUCT_NAME, "GX723"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "Sony VGN-NS10J_S", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "Sony VGN-SR290J", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "VGN-NS50B_L", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS50B_L"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "VGN-SR19XN", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR19XN"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "Toshiba Satellite L355", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), |
DMI_MATCH(DMI_PRODUCT_VERSION, "Satellite L355"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_win7, |
.ident = "ASUS K50IJ", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "Toshiba P305D", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), |
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_vista, |
.ident = "Toshiba NB100", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), |
DMI_MATCH(DMI_PRODUCT_NAME, "NB100"), |
}, |
}, |
/* |
* The wireless hotkey does not work on those machines when |
* returning true for _OSI("Windows 2012") |
*/ |
{ |
.callback = dmi_disable_osi_win8, |
.ident = "Dell Inspiron 7737", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7737"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_win8, |
.ident = "Dell Inspiron 7537", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_win8, |
.ident = "Dell Inspiron 5437", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5437"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_win8, |
.ident = "Dell Inspiron 3437", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3437"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_win8, |
.ident = "Dell Vostro 3446", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3446"), |
}, |
}, |
{ |
.callback = dmi_disable_osi_win8, |
.ident = "Dell Vostro 3546", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3546"), |
}, |
}, |
/* |
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug. |
* Linux ignores it, except for the machines enumerated below. |
*/ |
/* |
* Without this this EEEpc exports a non working WMI interface, with |
* this it exports a working "good old" eeepc_laptop interface, fixing |
* both brightness control, and rfkill not working. |
*/ |
{ |
.callback = dmi_enable_osi_linux, |
.ident = "Asus EEE PC 1015PX", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."), |
DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"), |
}, |
}, |
#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE |
/* |
* DELL XPS 13 (2015) switches sound between HDA and I2S |
* depending on the ACPI _REV callback. If userspace supports |
* I2S sufficiently (or if you do not care about sound), you |
* can safely disable this quirk. |
*/ |
{ |
.callback = dmi_enable_rev_override, |
.ident = "DELL XPS 13 (2015)", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"), |
}, |
}, |
#endif |
{} |
}; |
#endif /* CONFIG_DMI */ |
/drivers/acpi/boot.c |
---|
0,0 → 1,616 |
/* |
* boot.c - Architecture-Specific Low-Level ACPI Boot Support |
* |
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
* Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com> |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
*/ |
#include <linux/init.h> |
#include <linux/acpi.h> |
#include <linux/module.h> |
#include <linux/dmi.h> |
#include <linux/pci.h> |
static inline void outb(u8 v, u16 port) |
{ |
asm volatile("outb %0,%1" : : "a" (v), "dN" (port)); |
} |
static inline u8 inb(u16 port) |
{ |
u8 v; |
asm volatile("inb %1,%0" : "=a" (v) : "dN" (port)); |
return v; |
} |
static int __initdata acpi_force = 0; |
int acpi_disabled; |
EXPORT_SYMBOL(acpi_disabled); |
#ifdef CONFIG_X86_64 |
# include <asm/proto.h> |
#endif /* X86 */ |
#define PREFIX "ACPI: " |
int acpi_noirq; /* skip ACPI IRQ initialization */ |
int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ |
EXPORT_SYMBOL(acpi_pci_disabled); |
int acpi_ioapic; |
int acpi_strict; |
u8 acpi_sci_flags __initdata; |
/* |
* acpi_pic_sci_set_trigger() |
* |
* use ELCR to set PIC-mode trigger type for SCI |
* |
* If a PIC-mode SCI is not recognized or gives spurious IRQ7's |
* it may require Edge Trigger -- use "acpi_sci=edge" |
* |
* Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers |
* for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. |
* ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0) |
* ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0) |
*/ |
void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) |
{ |
unsigned int mask = 1 << irq; |
unsigned int old, new; |
/* Real old ELCR mask */ |
// old = inb(0x4d0) | (inb(0x4d1) << 8); |
/* |
* If we use ACPI to set PCI IRQs, then we should clear ELCR |
* since we will set it correctly as we enable the PCI irq |
* routing. |
*/ |
new = acpi_noirq ? old : 0; |
/* |
* Update SCI information in the ELCR, it isn't in the PCI |
* routing tables.. |
*/ |
switch (trigger) { |
case 1: /* Edge - clear */ |
new &= ~mask; |
break; |
case 3: /* Level - set */ |
new |= mask; |
break; |
} |
if (old == new) |
return; |
printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old); |
// outb(new, 0x4d0); |
// outb(new >> 8, 0x4d1); |
} |
static int __init acpi_parse_sbf(struct acpi_table_header *table) |
{ |
struct acpi_table_boot *sb = (struct acpi_table_boot *)table; |
sbf_port = sb->cmos_index; /* Save CMOS port */ |
return 0; |
} |
#ifdef CONFIG_HPET_TIMER |
#include <asm/hpet.h> |
static struct resource *hpet_res __initdata; |
static int __init acpi_parse_hpet(struct acpi_table_header *table) |
{ |
struct acpi_table_hpet *hpet_tbl = (struct acpi_table_hpet *)table; |
if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) { |
printk(KERN_WARNING PREFIX "HPET timers must be located in " |
"memory.\n"); |
return -1; |
} |
hpet_address = hpet_tbl->address.address; |
hpet_blockid = hpet_tbl->sequence; |
/* |
* Some broken BIOSes advertise HPET at 0x0. We really do not |
* want to allocate a resource there. |
*/ |
if (!hpet_address) { |
printk(KERN_WARNING PREFIX |
"HPET id: %#x base: %#lx is invalid\n", |
hpet_tbl->id, hpet_address); |
return 0; |
} |
#ifdef CONFIG_X86_64 |
/* |
* Some even more broken BIOSes advertise HPET at |
* 0xfed0000000000000 instead of 0xfed00000. Fix it up and add |
* some noise: |
*/ |
if (hpet_address == 0xfed0000000000000UL) { |
if (!hpet_force_user) { |
printk(KERN_WARNING PREFIX "HPET id: %#x " |
"base: 0xfed0000000000000 is bogus\n " |
"try hpet=force on the kernel command line to " |
"fix it up to 0xfed00000.\n", hpet_tbl->id); |
hpet_address = 0; |
return 0; |
} |
printk(KERN_WARNING PREFIX |
"HPET id: %#x base: 0xfed0000000000000 fixed up " |
"to 0xfed00000.\n", hpet_tbl->id); |
hpet_address >>= 32; |
} |
#endif |
printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", |
hpet_tbl->id, hpet_address); |
/* |
* Allocate and initialize the HPET firmware resource for adding into |
* the resource tree during the lateinit timeframe. |
*/ |
#define HPET_RESOURCE_NAME_SIZE 9 |
hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE); |
hpet_res->name = (void *)&hpet_res[1]; |
hpet_res->flags = IORESOURCE_MEM; |
snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u", |
hpet_tbl->sequence); |
hpet_res->start = hpet_address; |
hpet_res->end = hpet_address + (1 * 1024) - 1; |
return 0; |
} |
/* |
* hpet_insert_resource inserts the HPET resources used into the resource |
* tree. |
*/ |
static __init int hpet_insert_resource(void) |
{ |
if (!hpet_res) |
return 1; |
return insert_resource(&iomem_resource, hpet_res); |
} |
late_initcall(hpet_insert_resource); |
#else |
#define acpi_parse_hpet NULL |
#endif |
static int __init acpi_parse_fadt(struct acpi_table_header *table) |
{ |
#ifdef CONFIG_X86_PM_TIMER |
/* detect the location of the ACPI PM Timer */ |
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) { |
/* FADT rev. 2 */ |
if (acpi_gbl_FADT.xpm_timer_block.space_id != |
ACPI_ADR_SPACE_SYSTEM_IO) |
return 0; |
pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address; |
/* |
* "X" fields are optional extensions to the original V1.0 |
* fields, so we must selectively expand V1.0 fields if the |
* corresponding X field is zero. |
*/ |
if (!pmtmr_ioport) |
pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; |
} else { |
/* FADT rev. 1 */ |
pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; |
} |
if (pmtmr_ioport) |
printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", |
pmtmr_ioport); |
#endif |
return 0; |
} |
#ifdef CONFIG_X86_IO_APIC |
#else |
static inline int acpi_parse_madt_ioapic_entries(void) |
{ |
return -1; |
} |
#endif /* !CONFIG_X86_IO_APIC */ |
static void __init early_acpi_process_madt(void) |
{ |
#ifdef CONFIG_X86_LOCAL_APIC |
int error; |
if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) { |
/* |
* Parse MADT LAPIC entries |
*/ |
error = early_acpi_parse_madt_lapic_addr_ovr(); |
if (!error) { |
acpi_lapic = 1; |
smp_found_config = 1; |
} |
if (error == -EINVAL) { |
/* |
* Dell Precision Workstation 410, 610 come here. |
*/ |
printk(KERN_ERR PREFIX |
"Invalid BIOS MADT, disabling ACPI\n"); |
disable_acpi(); |
} |
} |
#endif |
} |
static void __init acpi_process_madt(void) |
{ |
#ifdef CONFIG_X86_LOCAL_APIC |
int error; |
if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) { |
/* |
* Parse MADT LAPIC entries |
*/ |
error = acpi_parse_madt_lapic_entries(); |
if (!error) { |
acpi_lapic = 1; |
/* |
* Parse MADT IO-APIC entries |
*/ |
mutex_lock(&acpi_ioapic_lock); |
error = acpi_parse_madt_ioapic_entries(); |
mutex_unlock(&acpi_ioapic_lock); |
if (!error) { |
acpi_set_irq_model_ioapic(); |
smp_found_config = 1; |
} |
} |
if (error == -EINVAL) { |
/* |
* Dell Precision Workstation 410, 610 come here. |
*/ |
printk(KERN_ERR PREFIX |
"Invalid BIOS MADT, disabling ACPI\n"); |
disable_acpi(); |
} |
} else { |
/* |
* ACPI found no MADT, and so ACPI wants UP PIC mode. |
* In the event an MPS table was found, forget it. |
* Boot with "acpi=off" to use MPS on such a system. |
*/ |
if (smp_found_config) { |
printk(KERN_WARNING PREFIX |
"No APIC-table, disabling MPS\n"); |
smp_found_config = 0; |
} |
} |
/* |
* ACPI supports both logical (e.g. Hyper-Threading) and physical |
* processors, where MPS only supports physical. |
*/ |
if (acpi_lapic && acpi_ioapic) |
printk(KERN_INFO "Using ACPI (MADT) for SMP configuration " |
"information\n"); |
else if (acpi_lapic) |
printk(KERN_INFO "Using ACPI for processor (LAPIC) " |
"configuration information\n"); |
#endif |
return; |
} |
static int __init disable_acpi_irq(const struct dmi_system_id *d) |
{ |
if (!acpi_force) { |
printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n", |
d->ident); |
acpi_noirq_set(); |
} |
return 0; |
} |
static int __init disable_acpi_pci(const struct dmi_system_id *d) |
{ |
if (!acpi_force) { |
printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n", |
d->ident); |
acpi_disable_pci(); |
} |
return 0; |
} |
static int __init dmi_disable_acpi(const struct dmi_system_id *d) |
{ |
if (!acpi_force) { |
printk(KERN_NOTICE "%s detected: acpi off\n", d->ident); |
disable_acpi(); |
} else { |
printk(KERN_NOTICE |
"Warning: DMI blacklist says broken, but acpi forced\n"); |
} |
return 0; |
} |
/* |
* Force ignoring BIOS IRQ0 override |
*/ |
static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d) |
{ |
if (!acpi_skip_timer_override) { |
pr_notice("%s detected: Ignoring BIOS IRQ0 override\n", |
d->ident); |
acpi_skip_timer_override = 1; |
} |
return 0; |
} |
/* |
* If your system is blacklisted here, but you find that acpi=force |
* works for you, please contact linux-acpi@vger.kernel.org |
*/ |
static struct dmi_system_id __initdata acpi_dmi_table[] = { |
/* |
* Boxes that need ACPI disabled |
*/ |
{ |
.callback = dmi_disable_acpi, |
.ident = "IBM Thinkpad", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), |
DMI_MATCH(DMI_BOARD_NAME, "2629H1G"), |
}, |
}, |
/* |
* Boxes that need ACPI PCI IRQ routing disabled |
*/ |
{ |
.callback = disable_acpi_irq, |
.ident = "ASUS A7V", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"), |
DMI_MATCH(DMI_BOARD_NAME, "<A7V>"), |
/* newer BIOS, Revision 1011, does work */ |
DMI_MATCH(DMI_BIOS_VERSION, |
"ASUS A7V ACPI BIOS Revision 1007"), |
}, |
}, |
{ |
/* |
* Latest BIOS for IBM 600E (1.16) has bad pcinum |
* for LPC bridge, which is needed for the PCI |
* interrupt links to work. DSDT fix is in bug 5966. |
* 2645, 2646 model numbers are shared with 600/600E/600X |
*/ |
.callback = disable_acpi_irq, |
.ident = "IBM Thinkpad 600 Series 2645", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), |
DMI_MATCH(DMI_BOARD_NAME, "2645"), |
}, |
}, |
{ |
.callback = disable_acpi_irq, |
.ident = "IBM Thinkpad 600 Series 2646", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), |
DMI_MATCH(DMI_BOARD_NAME, "2646"), |
}, |
}, |
/* |
* Boxes that need ACPI PCI IRQ routing and PCI scan disabled |
*/ |
{ /* _BBN 0 bug */ |
.callback = disable_acpi_pci, |
.ident = "ASUS PR-DLS", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), |
DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"), |
DMI_MATCH(DMI_BIOS_VERSION, |
"ASUS PR-DLS ACPI BIOS Revision 1010"), |
DMI_MATCH(DMI_BIOS_DATE, "03/21/2003") |
}, |
}, |
{ |
.callback = disable_acpi_pci, |
.ident = "Acer TravelMate 36x Laptop", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), |
}, |
}, |
{} |
}; |
/* second table for DMI checks that should run after early-quirks */ |
static struct dmi_system_id __initdata acpi_dmi_table_late[] = { |
/* |
* HP laptops which use a DSDT reporting as HP/SB400/10000, |
* which includes some code which overrides all temperature |
* trip points to 16C if the INTIN2 input of the I/O APIC |
* is enabled. This input is incorrectly designated the |
* ISA IRQ 0 via an interrupt source override even though |
* it is wired to the output of the master 8259A and INTIN0 |
* is not connected at all. Force ignoring BIOS IRQ0 |
* override in that cases. |
*/ |
{ |
.callback = dmi_ignore_irq0_timer_override, |
.ident = "HP nx6115 laptop", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6115"), |
}, |
}, |
{ |
.callback = dmi_ignore_irq0_timer_override, |
.ident = "HP NX6125 laptop", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"), |
}, |
}, |
{ |
.callback = dmi_ignore_irq0_timer_override, |
.ident = "HP NX6325 laptop", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"), |
}, |
}, |
{ |
.callback = dmi_ignore_irq0_timer_override, |
.ident = "HP 6715b laptop", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"), |
}, |
}, |
{ |
.callback = dmi_ignore_irq0_timer_override, |
.ident = "FUJITSU SIEMENS", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), |
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), |
}, |
}, |
{} |
}; |
/* |
* acpi_boot_table_init() and acpi_boot_init() |
* called from setup_arch(), always. |
* 1. checksums all tables |
* 2. enumerates lapics |
* 3. enumerates io-apics |
* |
* acpi_table_init() is separate to allow reading SRAT without |
* other side effects. |
* |
* side effects of acpi_boot_init: |
* acpi_lapic = 1 if LAPIC found |
* acpi_ioapic = 1 if IOAPIC found |
* if (acpi_lapic && acpi_ioapic) smp_found_config = 1; |
* if acpi_blacklisted() acpi_disabled = 1; |
* acpi_irq_model=... |
* ... |
*/ |
void __init acpi_boot_table_init(void) |
{ |
dmi_check_system(acpi_dmi_table); |
/* |
* If acpi_disabled, bail out |
*/ |
if (acpi_disabled) |
return; |
/* |
* Initialize the ACPI boot-time table parser. |
*/ |
if (acpi_table_init()) { |
disable_acpi(); |
return; |
} |
acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); |
/* |
* blacklist may disable ACPI entirely |
*/ |
if (acpi_blacklisted()) { |
if (acpi_force) { |
printk(KERN_WARNING PREFIX "acpi=force override\n"); |
} else { |
printk(KERN_WARNING PREFIX "Disabling ACPI support\n"); |
disable_acpi(); |
return; |
} |
} |
} |
int __init early_acpi_boot_init(void) |
{ |
/* |
* If acpi_disabled, bail out |
*/ |
if (acpi_disabled) |
return 1; |
/* |
* Process the Multiple APIC Description Table (MADT), if present |
*/ |
early_acpi_process_madt(); |
/* |
* Hardware-reduced ACPI mode initialization: |
*/ |
// acpi_reduced_hw_init(); |
return 0; |
} |
int __init acpi_boot_init(void) |
{ |
/* those are executed after early-quirks are executed */ |
dmi_check_system(acpi_dmi_table_late); |
/* |
* If acpi_disabled, bail out |
*/ |
if (acpi_disabled) |
return 1; |
// acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); |
/* |
* set sci_int and PM timer address |
*/ |
acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt); |
/* |
* Process the Multiple APIC Description Table (MADT), if present |
*/ |
acpi_process_madt(); |
acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); |
// if (!acpi_noirq) |
// x86_init.pci.init = pci_acpi_init; |
return 0; |
} |
/drivers/acpi/bus.c |
---|
0,0 → 1,145 |
/* |
* acpi_bus.c - ACPI Bus Driver ($Revision: 80 $) |
* |
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or (at |
* your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, but |
* WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* General Public License for more details. |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
*/ |
#include <linux/module.h> |
#include <linux/init.h> |
#include <linux/ioport.h> |
#include <linux/kernel.h> |
#include <linux/list.h> |
#include <linux/acpi.h> |
#include <linux/pci.h> |
#include <linux/dmi.h> |
#include "internal.h" |
struct acpi_device *acpi_root; |
#ifdef CONFIG_X86 |
#ifdef CONFIG_ACPI_CUSTOM_DSDT |
static inline int set_copy_dsdt(const struct dmi_system_id *id) |
{ |
return 0; |
} |
#else |
static int set_copy_dsdt(const struct dmi_system_id *id) |
{ |
printk(KERN_NOTICE "%s detected - " |
"force copy of DSDT to local memory\n", id->ident); |
acpi_gbl_copy_dsdt_locally = 1; |
return 0; |
} |
#endif |
static struct dmi_system_id dsdt_dmi_table[] __initdata = { |
/* |
* Invoke DSDT corruption work-around on all Toshiba Satellite. |
* https://bugzilla.kernel.org/show_bug.cgi?id=14679 |
*/ |
{ |
.callback = set_copy_dsdt, |
.ident = "TOSHIBA Satellite", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), |
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), |
}, |
}, |
{} |
}; |
#else |
static struct dmi_system_id dsdt_dmi_table[] __initdata = { |
{} |
}; |
#endif |
/** |
* acpi_early_init - Initialize ACPICA and populate the ACPI namespace. |
* |
* The ACPI tables are accessible after this, but the handling of events has not |
* been initialized and the global lock is not available yet, so AML should not |
* be executed at this point. |
* |
* Doing this before switching the EFI runtime services to virtual mode allows |
* the EfiBootServices memory to be freed slightly earlier on boot. |
*/ |
void __init acpi_early_init(void) |
{ |
acpi_status status; |
if (acpi_disabled) |
return; |
printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION); |
/* It's safe to verify table checksums during late stage */ |
acpi_gbl_verify_table_checksum = TRUE; |
/* enable workarounds, unless strict ACPI spec. compliance */ |
if (!acpi_strict) |
acpi_gbl_enable_interpreter_slack = TRUE; |
acpi_gbl_permanent_mmap = 1; |
/* |
* If the machine falls into the DMI check table, |
* DSDT will be copied to memory |
*/ |
dmi_check_system(dsdt_dmi_table); |
status = acpi_reallocate_root_table(); |
if (ACPI_FAILURE(status)) { |
printk(KERN_ERR PREFIX |
"Unable to reallocate ACPI tables\n"); |
goto error0; |
} |
status = acpi_initialize_subsystem(); |
if (ACPI_FAILURE(status)) { |
printk(KERN_ERR PREFIX |
"Unable to initialize the ACPI Interpreter\n"); |
goto error0; |
} |
status = acpi_load_tables(); |
if (ACPI_FAILURE(status)) { |
printk(KERN_ERR PREFIX |
"Unable to load the System Description Tables\n"); |
goto error0; |
} |
#ifdef CONFIG_X86 |
if (!acpi_ioapic) { |
/* compatible (0) means level (3) */ |
if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) { |
acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK; |
acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL; |
} |
/* Set PIC-mode SCI trigger type */ |
acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt, |
(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2); |
} else { |
/* |
* now that acpi_gbl_FADT is initialized, |
* update it with result from INT_SRC_OVR parsing |
*/ |
acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi; |
} |
#endif |
return; |
error0: |
disable_acpi(); |
} |
/drivers/acpi/internal.h |
---|
0,0 → 1,209 |
/* |
* acpi/internal.h |
* For use by Linux/ACPI infrastructure, not drivers |
* |
* Copyright (c) 2009, Intel Corporation. |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms and conditions of the GNU General Public License, |
* version 2, as published by the Free Software Foundation. |
* |
* This program is distributed in the hope it will be useful, but WITHOUT |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
* more details. |
* |
*/ |
#ifndef _ACPI_INTERNAL_H_ |
#define _ACPI_INTERNAL_H_ |
#define PREFIX "ACPI: " |
acpi_status acpi_os_initialize1(void); |
void init_acpi_device_notify(void); |
int acpi_scan_init(void); |
void acpi_pci_root_init(void); |
void acpi_pci_link_init(void); |
void acpi_processor_init(void); |
void acpi_platform_init(void); |
void acpi_pnp_init(void); |
void acpi_int340x_thermal_init(void); |
int acpi_sysfs_init(void); |
void acpi_container_init(void); |
void acpi_memory_hotplug_init(void); |
#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC |
int acpi_ioapic_add(struct acpi_pci_root *root); |
int acpi_ioapic_remove(struct acpi_pci_root *root); |
#else |
static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } |
static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } |
#endif |
#ifdef CONFIG_ACPI_DOCK |
void register_dock_dependent_device(struct acpi_device *adev, |
acpi_handle dshandle); |
int dock_notify(struct acpi_device *adev, u32 event); |
void acpi_dock_add(struct acpi_device *adev); |
#else |
static inline void register_dock_dependent_device(struct acpi_device *adev, |
acpi_handle dshandle) {} |
static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; } |
static inline void acpi_dock_add(struct acpi_device *adev) {} |
#endif |
#ifdef CONFIG_X86 |
void acpi_cmos_rtc_init(void); |
#else |
static inline void acpi_cmos_rtc_init(void) {} |
#endif |
int acpi_rev_override_setup(char *str); |
extern bool acpi_force_hot_remove; |
void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, |
const char *name); |
int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, |
const char *hotplug_profile_name); |
void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val); |
#ifdef CONFIG_DEBUG_FS |
extern struct dentry *acpi_debugfs_dir; |
void acpi_debugfs_init(void); |
#else |
static inline void acpi_debugfs_init(void) { return; } |
#endif |
void acpi_lpss_init(void); |
void acpi_apd_init(void); |
acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src); |
bool acpi_queue_hotplug_work(struct work_struct *work); |
void acpi_device_hotplug(struct acpi_device *adev, u32 src); |
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); |
/* -------------------------------------------------------------------------- |
Device Node Initialization / Removal |
-------------------------------------------------------------------------- */ |
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
int acpi_device_add(struct acpi_device *device, |
void (*release)(struct device *)); |
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, |
int type, unsigned long long sta); |
int acpi_device_setup_files(struct acpi_device *dev); |
void acpi_device_remove_files(struct acpi_device *dev); |
void acpi_device_add_finalize(struct acpi_device *device); |
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); |
bool acpi_device_is_present(struct acpi_device *adev); |
bool acpi_device_is_battery(struct acpi_device *adev); |
bool acpi_device_is_first_physical_node(struct acpi_device *adev, |
const struct device *dev); |
/* -------------------------------------------------------------------------- |
Device Matching and Notification |
-------------------------------------------------------------------------- */ |
struct acpi_device *acpi_companion_match(const struct device *dev); |
int __acpi_device_uevent_modalias(struct acpi_device *adev, |
struct kobj_uevent_env *env); |
/* -------------------------------------------------------------------------- |
Power Resource |
-------------------------------------------------------------------------- */ |
int acpi_power_init(void); |
void acpi_power_resources_list_free(struct list_head *list); |
int acpi_extract_power_resources(union acpi_object *package, unsigned int start, |
struct list_head *list); |
int acpi_add_power_resource(acpi_handle handle); |
void acpi_power_add_remove_device(struct acpi_device *adev, bool add); |
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level); |
int acpi_device_sleep_wake(struct acpi_device *dev, |
int enable, int sleep_state, int dev_state); |
int acpi_power_get_inferred_state(struct acpi_device *device, int *state); |
int acpi_power_on_resources(struct acpi_device *device, int state); |
int acpi_power_transition(struct acpi_device *device, int state); |
int acpi_wakeup_device_init(void); |
#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC |
void acpi_early_processor_set_pdc(void); |
#else |
static inline void acpi_early_processor_set_pdc(void) {} |
#endif |
#ifdef CONFIG_X86 |
void acpi_early_processor_osc(void); |
#else |
static inline void acpi_early_processor_osc(void) {} |
#endif |
/* -------------------------------------------------------------------------- |
Embedded Controller |
-------------------------------------------------------------------------- */ |
struct acpi_ec { |
acpi_handle handle; |
unsigned long gpe; |
unsigned long command_addr; |
unsigned long data_addr; |
bool global_lock; |
unsigned long flags; |
unsigned long reference_count; |
struct mutex mutex; |
wait_queue_head_t wait; |
struct list_head list; |
struct transaction *curr; |
spinlock_t lock; |
struct work_struct work; |
unsigned long timestamp; |
unsigned long nr_pending_queries; |
}; |
extern struct acpi_ec *first_ec; |
/* If we find an EC via the ECDT, we need to keep a ptr to its context */ |
/* External interfaces use first EC only, so remember */ |
typedef int (*acpi_ec_query_func) (void *data); |
int acpi_ec_init(void); |
int acpi_ec_ecdt_probe(void); |
int acpi_boot_ec_enable(void); |
void acpi_ec_block_transactions(void); |
void acpi_ec_unblock_transactions(void); |
void acpi_ec_unblock_transactions_early(void); |
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, |
acpi_handle handle, acpi_ec_query_func func, |
void *data); |
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); |
/*-------------------------------------------------------------------------- |
Suspend/Resume |
-------------------------------------------------------------------------- */ |
#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT |
extern int acpi_sleep_init(void); |
#else |
static inline int acpi_sleep_init(void) { return -ENXIO; } |
#endif |
#ifdef CONFIG_ACPI_SLEEP |
void acpi_sleep_proc_init(void); |
int suspend_nvs_alloc(void); |
void suspend_nvs_free(void); |
int suspend_nvs_save(void); |
void suspend_nvs_restore(void); |
#else |
static inline void acpi_sleep_proc_init(void) {} |
static inline int suspend_nvs_alloc(void) { return 0; } |
static inline void suspend_nvs_free(void) {} |
static inline int suspend_nvs_save(void) { return 0; } |
static inline void suspend_nvs_restore(void) {} |
#endif |
/*-------------------------------------------------------------------------- |
Device properties |
-------------------------------------------------------------------------- */ |
#define ACPI_DT_NAMESPACE_HID "PRP0001" |
void acpi_init_properties(struct acpi_device *adev); |
void acpi_free_properties(struct acpi_device *adev); |
#endif /* _ACPI_INTERNAL_H_ */ |
/drivers/acpi/tables.c |
---|
0,0 → 1,103 |
/* |
* acpi_tables.c - ACPI Boot-Time Table Parsing |
* |
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
* |
*/ |
/* Uncomment next line to get verbose printout */ |
/* #define DEBUG */ |
#define pr_fmt(fmt) "ACPI: " fmt |
#include <linux/init.h> |
#include <linux/kernel.h> |
#include <linux/string.h> |
#include <linux/types.h> |
#include <linux/errno.h> |
#include <linux/acpi.h> |
#define ACPI_MAX_TABLES 128 |
static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; |
static int acpi_apic_instance __initdata; |
/* |
* Disable table checksum verification for the early stage due to the size |
* limitation of the current x86 early mapping implementation. |
*/ |
static bool acpi_verify_table_checksum __initdata = false; |
/** |
* acpi_table_parse - find table with @id, run @handler on it |
* @id: table id to find |
* @handler: handler to run |
* |
* Scan the ACPI System Descriptor Table (STD) for a table matching @id, |
* run @handler on it. |
* |
* Return 0 if table found, -errno if not. |
*/ |
int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) |
{ |
struct acpi_table_header *table = NULL; |
acpi_size tbl_size; |
if (acpi_disabled) |
return -ENODEV; |
if (!id || !handler) |
return -EINVAL; |
if (strncmp(id, ACPI_SIG_MADT, 4) == 0) |
acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); |
else |
acpi_get_table_with_size(id, 0, &table, &tbl_size); |
if (table) { |
handler(table); |
early_acpi_os_unmap_memory(table, tbl_size); |
return 0; |
} else |
return -ENODEV; |
} |
/* |
* acpi_table_init() |
* |
* find RSDP, find and checksum SDT/XSDT. |
* checksum all tables, print SDT/XSDT |
* |
* result: sdt_entry[] is initialized |
*/ |
int __init acpi_table_init(void) |
{ |
acpi_status status; |
if (acpi_verify_table_checksum) { |
pr_info("Early table checksum verification enabled\n"); |
acpi_gbl_verify_table_checksum = TRUE; |
} else { |
pr_info("Early table checksum verification disabled\n"); |
acpi_gbl_verify_table_checksum = FALSE; |
} |
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); |
if (ACPI_FAILURE(status)) |
return -EINVAL; |
return 0; |
} |